From 5f4e4b6c22bef229b7f17557d4cbc7efad49d75f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Ram=C3=B3n=20L=C3=B3pez?= Date: Sat, 26 Mar 2016 01:56:11 +0100 Subject: [PATCH] [PropertyAccess] Custom methods on property accesses --- components/property_access.rst | 274 ++++++++++++++++++++++++++++++++- 1 file changed, 273 insertions(+), 1 deletion(-) diff --git a/components/property_access.rst b/components/property_access.rst index ca94e819d69..c982f38cedc 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -116,6 +116,9 @@ property name (``first_name`` becomes ``FirstName``) and prefixes it with var_dump($accessor->getValue($person, 'first_name')); // 'Wouter' +You can override the called getter method using metadata (i.e. annotations or +configuration files). See `Custom method calls and virtual properties in a class`_. + Using Hassers/Issers ~~~~~~~~~~~~~~~~~~~~ @@ -314,6 +317,9 @@ see `Enable other Features`_. var_dump($person->getWouter()); // array(...) +You can override the called setter method using metadata (i.e. annotations or +configuration files). See `Custom method calls and virtual properties in a class`_. + Writing to Array Properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -418,8 +424,231 @@ You can also mix objects and arrays:: var_dump('Hello '.$accessor->getValue($person, 'children[0].firstName')); // 'Wouter' // equal to $person->getChildren()[0]->firstName +Custom method calls and virtual properties in a class +----------------------------------------------------- + +.. versionadded:: 3.4 + Support for custom accessors was introduced in Symfony 3.4. + +Sometimes you may not want the component to guess which method has to be called +when reading or writing properties. This is especially interesting when property +names are not in English or its singularization is not properly detected. + +For those cases you can add metadata to the class being accessed so that the +component will use a particular method as a getter, setter or even adder and +remover (for collections). + +Another interesting use of custom methods is declaring virtual properties +which are not stored directly in the object. + +There are three supported ways to state this metadata supported out-of-the-box by +the component: using annotations, using YAML configuration files or using XML +configuration files. + +.. caution:: + + When using as a standalone component the metadata feature is disabled by + default. You can enable it by calling + :method:`PropertyAccessorBuilder::setMetadataFactory + ` + see `Enable other Features`_. + +There are four method calls that can be overriden: ``getter``, ``setter``, ``adder`` and +``remover``. + +When using annotations you can precede a property with ``@PropertyAccessor`` to state which +method should be called when a get, set, add or remove operation is needed on the +property. + +.. configuration-block:: + + .. code-block:: php-annotations + + // ... + use Symfony\Component\PropertyAccess\Annotation\PropertyAccessor; + + class Person + { + /** + * @PropertyAccessor(getter="getFullName", setter="setFullName") + */ + private $name; + + /** + * @PropertyAccessor(adder="addNewChild", remover="discardChild") + */ + private $children; + + public function getFullName() + { + return $this->name; + } + + public function setFullName($fullName) + { + $this->name = $fullName; + } + } + + .. code-block:: yaml + + # src/AppBundle/Resources/config/property_access.yml + Person: + name: + getter: getFullName + setter: setFullName + children: + adder: addNewChild + remover: discardChild + + .. code-block:: xml + + + + + + + + + + + + + +Then, using the overriden methods is automatic: + +.. code-block:: php + + $person = new Person(); + + $accessor->setValue($person, 'name', 'John Doe'); + // will call setFullName + + var_dump('Hello '.$accesor->getValue($person, 'name')); + // will return 'Hello John Doe' + +You can also associate a particular method with an operation on a property +using the ``@GetterAccessor``, ``@SetterAccessor``, ``@AdderAccessor`` and +``@RemoverAccessor`` annotations. All of them take only one parameter: ``property``. + +This allows creating virtual properties that are not directly stored in the +object: + +.. configuration-block:: + + .. code-block:: php-annotations + + // ... + use Symfony\Component\PropertyAccess\Annotation\GetterAccessor; + use Symfony\Component\PropertyAccess\Annotation\SetterAccessor; + + class Invoice + { + private $quantity; + + private $pricePerUnit; + + // Notice that there is no real "total" property + + /** + * @GetterAccessor(property="total") + */ + public function getTotal() + { + return $this->quantity * $this->pricePerUnit; + } + + // Notice that 'property' can be omitted in the parameter + /** + * @SetterAccessor("total") + * + * @param mixed $total + */ + public function setTotal($total) + { + $this->quantity = $total / $this->pricePerUnit; + } + } + + .. code-block:: yaml + + Invoice: + total: + getter: getTotal + setter: setTotal + + .. code-block:: xml + + + + + + + + + + + +.. code-block:: php + + $invoice = new Invoice(); + + $accessor->setValue($invoice, 'quantity', 20); + $accessor->setValue($invoice, 'pricePerUnit', 10); + var_dump('Total: '.$accesor->getValue($invoice, 'total')); + // will return 'Total: 200' + +Using property metadata with Symfony +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, Symfony will look for property metadata in the following places +inside each bundle path: + +- `/Resources/config/property_accessor.xml` +- `/Resources/config/property_accessor.yml` +- `/Resources/config/property_accessor/*.xml` +- `/Resources/config/property_accessor/*.yml` + +If you need getting metadata from annotations you must explicitly enable them: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + property_access: { enable_annotations: true } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('framework', array( + 'property_access' => array( + 'enable_annotations' => true, + ), + )); + Enable other Features -~~~~~~~~~~~~~~~~~~~~~ +--------------------- The :class:`Symfony\\Component\\PropertyAccess\\PropertyAccessor` can be configured to enable extra features. To do that you could use the @@ -450,6 +679,49 @@ Or you can pass parameters directly to the constructor (not the recommended way) // ... $accessor = new PropertyAccessor(true); // this enables handling of magic __call +If you need to enable metadata processing (see +`Custom method calls and virtual properties in a class`_) you must instantiate +a :class:`Symfony\\Component\\PropertyAccess\\Mapping\\Factory\\MetadataFactoryInterface` +and use the method `setMetadataFactory` on the +:class:`Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder`. Bundled with +the component you can find +a `MetadataFactory` class that supports different kind of loaders (annotations, +YAML and YML files) called :class:`Symfony\\Component\\PropertyAccess\\Mapping\\Factory\\LazyLoadingMetadataFactory`. + +.. code-block:: php + + use Doctrine\Common\Annotations\AnnotationReader; + use Symfony\Component\PropertyAccess\Mapping\Factory\LazyLoadingMetadataFactory; + use Symfony\Component\PropertyAccess\Mapping\Loader\AnnotationLoader; + use Symfony\Component\PropertyAccess\Mapping\Loader\LoaderChain; + use Symfony\Component\PropertyAccess\Mapping\Loader\XMLFileLoader; + use Symfony\Component\PropertyAccess\Mapping\Loader\YamlFileLoader; + + // ... + + $accessorBuilder = PropertyAccess::createPropertyAccessorBuilder(); + + // Create annotation loader using Doctrine annotation reader + $loader = new AnnotationLoader(new AnnotationReader()); + + // or read metadata from a XML file + $loader = new XmlFileLoader('metadata.xml'); + + // or read metadata from a YAML file + $loader = new YamlFileLoader('metadata.yml'); + + // or combine several loaders in one + $loader = new LoaderChain( + new AnnotationLoader(new AnnotationReader()), + new XmlFileLoader('metadata.xml'), + new YamlFileLoader('metadata.yml'), + new YamlFileLoader('metadata2.yml') + ); + + // Enable metadata loading + $metadataFactory = new LazyLoadingMetadataFactory($loader); + + $accessorBuilder->setMetadataFactory($metadataFactory); .. _Packagist: https://packagist.org/packages/symfony/property-access .. _The Inflector component: https://github.com/symfony/inflector pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy