You are browsing a version that has not yet been released. |
Upgrading to v4
This page lists the changes that may require adjustments when upgrading from version 3 to version 4, and how to adapt to them.
Requirements
- PHP 8.3 or higher is required, support for PHP 8.2 has been dropped.
doctrine/collections2.6 or higher is required, version 3.1 is supported as well. Note that version 3 requires PHP 8.4.laminas/laminas-hydrator5 is supported in addition to 4.13 or higher. When upgrading laminas-hydrator to version 5, your own strategies, filters and naming strategies need to follow its interfaces, which use native types, see the migration guide of laminas-hydrator.
DoctrineObject is Final
DoctrineObject is final and cannot be extended anymore. All its
protected properties and methods are private now, e.g.
getClassMetadata(), extractByValue(), hydrateByValue(),
toOne(), toMany(), find() and handleTypeConversions(). The
public method getFieldNames() is private as well.
Use cases that required extending the hydrator are covered as follows:
| Use case | Replacement |
|---|---|
| Converting values, e.g. of custom DBAL types | A type converter, see Converting Custom DBAL Types |
| Creating new associated entities differently | The instantiator, see Using a Custom Inflector or Instantiator |
| Configuring the handling of associated entities | Association hydrators, see Configuring Associated Entities |
| Converting single fields | Strategies, see Basic Usage |
| Adjusting the data before or after hydrating | A decorator, see below |
To adjust the data before hydrating or after extracting, wrap the
hydrator in a decorator implementing Laminas\Hydrator\HydratorInterface:
use Doctrine\Laminas\Hydrator\DoctrineObject;use Laminas\Hydrator\HydratorInterface;final class MyHydrator implements HydratorInterface{ public function __construct(private DoctrineObject $hydrator) { } public function extract(object $object): array { $data = $this->hydrator->extract($object); // … adjust $data … return $data; } public function hydrate(array $data, object $object): object { // … adjust $data … return $this->hydrator->hydrate($data, $object); }}
Laminas forms only require a HydratorInterface, so the decorator can
be passed to setHydrator() of a form or fieldset.
Type Conversion
The conversion of values has moved from DoctrineObject::handleTypeConversions()
to Doctrine\Laminas\Hydrator\DoctrineTypeConverter, which can be
replaced or extended by converters for custom types:
use Doctrine\Laminas\Hydrator\DoctrineObject;use Doctrine\Laminas\Hydrator\DoctrineTypeConverter;$hydrator = new DoctrineObject( $entityManager, typeConverter: new DoctrineTypeConverter(typeConverters: ['uuid' => new UuidTypeConverter()]),);
See Converting Custom DBAL Types for details.
Additionally, more values are converted than before:
- Fields mapped with
enumTypeare converted to enums from their backing values. Previously, this required a strategy, otherwise the backing value was passed to the entity, causing aTypeErrorfor typed setters and properties. Existing strategies for enums keep working, as enums returned by a strategy are kept as they are. - Values of the types
smallfloat,ascii_string,guid,enum,number,dateinterval,datetime_utcanddatetime_utc_immutableare converted to their PHP types, e.g. aDateIntervalfordateinterval. Previously, they were passed as they are. If your entities expect other values for fields of these types, add a strategy for the fields or register a converter for the type.
Collection Strategies
The methods of the collection strategies use native types now. If you
implemented CollectionStrategyInterface or extended
AbstractCollectionStrategy, adapt the signatures of your methods:
// Beforepublic function hydrate($value, ?array $data)public function extract($value, ?object $object = null)// Afterpublic function hydrate(mixed $value, ?array $data = null): mixedpublic function extract(mixed $value, ?object $object = null): mixed
Associated Entities
Associated entities given as nested arrays were hydrated by the same
hydrator as the entity passed to hydrate(). Therefore, its strategies
and filters also applied to fields of associated entities that happened to
have the same name. Associated entities are now hydrated by separate
hydrators, so strategies and filters added to your hydrator only apply to
the entity passed to hydrate(). To configure strategies and filters
for associated entities, add them to their hydrators:
$hydrator->getAssociationHydrator(User::class)->addStrategy('name', new NameStrategy());
The naming strategy of your hydrator still applies to associated entities. See Configuring Associated Entities for details. Laminas forms using fieldsets bound to objects, as described in Example Usage with Laminas Form, are not affected, as nested fieldsets hydrate their objects with their own hydrators.
Null Values for Associations
When hydrating by reference, null given for a OneToOne or ManyToOne
association is ignored now if the property does not accept null, like
it is when hydrating by value and the setter does not accept null.
Previously, null was written to the property, causing a TypeError.
Embeddables
An embeddable is extracted once now. Previously, it was extracted once per field of the embeddable, so strategies and filters for the embeddable were called several times. The extracted data is the same.
New Features
The following features have been added and do not require adjustments:
- Extracting associations as identifiers or arrays, see Extracting Associations.
- Extracting and hydrating embeddables as arrays, see Embeddables as Arrays.
- Configuring the hydrators of associated entities, see Configuring Associated Entities.
- Extracting enums and dates as scalar values, and converters for custom types, see Converting Custom DBAL Types.
- Creating new associated entities with a custom instantiator, see Creating New Associated Entities.
