From 9728a4c14386f428bea84d40addbabca07dbc042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 19:22:29 +0100 Subject: [PATCH 01/16] Wrap lines at 72 chars This should make any following commit on the docs easier to review. --- docs/en/annotations.rst | 178 +++++++++++++++++++++++++--------------- docs/en/custom.rst | 49 ++++++----- docs/en/index.rst | 29 +++---- 3 files changed, 155 insertions(+), 101 deletions(-) diff --git a/docs/en/annotations.rst b/docs/en/annotations.rst index 99da3e261..cd6e42839 100644 --- a/docs/en/annotations.rst +++ b/docs/en/annotations.rst @@ -1,9 +1,10 @@ Handling Annotations ==================== -There are several different approaches to handling annotations in PHP. Doctrine Annotations -maps docblock annotations to PHP classes. Because not all docblock annotations are used -for metadata purposes a filter is applied to ignore or skip classes that are not Doctrine annotations. +There are several different approaches to handling annotations in PHP. +Doctrine Annotations maps docblock annotations to PHP classes. Because +not all docblock annotations are used for metadata purposes a filter is +applied to ignore or skip classes that are not Doctrine annotations. Take a look at the following code snippet: @@ -39,21 +40,41 @@ Take a look at the following code snippet: In this snippet you can see a variety of different docblock annotations: -- Documentation annotations such as ``@var`` and ``@author``. These annotations are on a blacklist and never considered for throwing an exception due to wrongly used annotations. -- Annotations imported through use statements. The statement ``use Doctrine\ORM\Mapping AS ORM`` makes all classes under that namespace available as ``@ORM\ClassName``. Same goes for the import of ``@Assert``. -- The ``@dummy`` annotation. It is not a documentation annotation and not blacklisted. For Doctrine Annotations it is not entirely clear how to handle this annotation. Depending on the configuration an exception (unknown annotation) will be thrown when parsing this annotation. -- The fully qualified annotation ``@MyProject\Annotations\Foobarable``. This is transformed directly into the given class name. - -How are these annotations loaded? From looking at the code you could guess that the ORM Mapping, Assert Validation and the fully qualified annotation can just be loaded using -the defined PHP autoloaders. This is not the case however: For error handling reasons every check for class existence inside the AnnotationReader sets the second parameter $autoload -of ``class_exists($name, $autoload)`` to false. To work flawlessly the AnnotationReader requires silent autoloaders which many autoloaders are not. Silent autoloading is NOT -part of the `PSR-0 specification `_ for autoloading. - -This is why Doctrine Annotations uses its own autoloading mechanism through a global registry. If you are wondering about the annotation registry being global, -there is no other way to solve the architectural problems of autoloading annotation classes in a straightforward fashion. Additionally if you think about PHP -autoloading then you recognize it is a global as well. - -To anticipate the configuration section, making the above PHP class work with Doctrine Annotations requires this setup: +- Documentation annotations such as ``@var`` and ``@author``. These + annotations are on a blacklist and never considered for throwing an + exception due to wrongly used annotations. +- Annotations imported through use statements. The statement ``use + Doctrine\ORM\Mapping AS ORM`` makes all classes under that namespace + available as ``@ORM\ClassName``. Same goes for the import of + ``@Assert``. +- The ``@dummy`` annotation. It is not a documentation annotation and + not blacklisted. For Doctrine Annotations it is not entirely clear how + to handle this annotation. Depending on the configuration an exception + (unknown annotation) will be thrown when parsing this annotation. +- The fully qualified annotation ``@MyProject\Annotations\Foobarable``. + This is transformed directly into the given class name. + +How are these annotations loaded? From looking at the code you could +guess that the ORM Mapping, Assert Validation and the fully qualified +annotation can just be loaded using +the defined PHP autoloaders. This is not the case however: For error +handling reasons every check for class existence inside the +AnnotationReader sets the second parameter $autoload +of ``class_exists($name, $autoload)`` to false. To work flawlessly the +AnnotationReader requires silent autoloaders which many autoloaders are +not. Silent autoloading is NOT part of the `PSR-0 specification +`_ +for autoloading. + +This is why Doctrine Annotations uses its own autoloading mechanism +through a global registry. If you are wondering about the annotation +registry being global, there is no other way to solve the architectural +problems of autoloading annotation classes in a straightforward fashion. +Additionally if you think about PHP autoloading then you recognize it is +a global as well. + +To anticipate the configuration section, making the above PHP class work +with Doctrine Annotations requires this setup: .. code-block:: php @@ -67,26 +88,32 @@ To anticipate the configuration section, making the above PHP class work with Do $reader = new AnnotationReader(); AnnotationReader::addGlobalIgnoredName('dummy'); -The second block with the annotation registry calls registers all the three different annotation namespaces that are used. -Doctrine saves all its annotations in a single file, that is why ``AnnotationRegistry#registerFile`` is used in contrast to -``AnnotationRegistry#registerAutoloadNamespace`` which creates a PSR-0 compatible loading mechanism for class to file names. +The second block with the annotation registry calls registers all the +three different annotation namespaces that are used. +Doctrine saves all its annotations in a single file, that is why +``AnnotationRegistry#registerFile`` is used in contrast to +``AnnotationRegistry#registerAutoloadNamespace`` which creates a PSR-0 +compatible loading mechanism for class to file names. -In the third block, we create the actual AnnotationReader instance. Note that we also add "dummy" to the global list of annotations -for which we do not throw exceptions. Setting this is necessary in our example case, otherwise ``@dummy`` would trigger an exception to -be thrown during the parsing of the docblock of ``MyProject\Entities\User#id``. +In the third block, we create the actual AnnotationReader instance. Note +that we also add "dummy" to the global list of annotations for which we +do not throw exceptions. Setting this is necessary in our example case, +otherwise ``@dummy`` would trigger an exception to be thrown during the +parsing of the docblock of ``MyProject\Entities\User#id``. Setup and Configuration ----------------------- -To use the annotations library is simple, you just need to create a new ``AnnotationReader`` instance: +To use the annotations library is simple, you just need to create a new +``AnnotationReader`` instance: .. code-block:: php $reader = new \Doctrine\Common\Annotations\AnnotationReader(); -This creates a simple annotation reader with no caching other than in memory (in php arrays). -Since parsing docblocks can be expensive you should cache this process by using -a caching reader. +This creates a simple annotation reader with no caching other than in +memory (in php arrays). Since parsing docblocks can be expensive you +should cache this process by using a caching reader. You can use a file caching reader: @@ -101,12 +128,15 @@ You can use a file caching reader: $debug = true ); -If you set the debug flag to true the cache reader will check for changes in the original files, which -is very important during development. If you don't set it to true you have to delete the directory to clear the cache. -This gives faster performance, however should only be used in production, because of its inconvenience -during development. +If you set the debug flag to true the cache reader will check for +changes in the original files, which is very important during +development. If you don't set it to true you have to delete the +directory to clear the cache. This gives faster performance, however +should only be used in production, because of its inconvenience during +development. -You can also use one of the ``Doctrine\Common\Cache\Cache`` cache implementations to cache the annotations: +You can also use one of the ``Doctrine\Common\Cache\Cache`` cache +implementations to cache the annotations: .. code-block:: php @@ -120,21 +150,23 @@ You can also use one of the ``Doctrine\Common\Cache\Cache`` cache implementation $debug = true ); -The debug flag is used here as well to invalidate the cache files when the PHP class with annotations changed -and should be used during development. +The debug flag is used here as well to invalidate the cache files when +the PHP class with annotations changed and should be used during +development. .. warning :: The AnnotationReader works and caches under the assumption that all annotations of a doc-block are processed at once. That means that annotation classes that do not exist and - aren't loaded and cannot be autoloaded (using the AnnotationRegistry) would never be visible and not - accessible if a cache is used unless the cache is cleared and the - annotations requested again, this time with all annotations - defined. + aren't loaded and cannot be autoloaded (using the + AnnotationRegistry) would never be visible and not accessible if a + cache is used unless the cache is cleared and the annotations + requested again, this time with all annotations defined. -By default the annotation reader returns a list of annotations with numeric indexes. If you want your annotations -to be indexed by their class name you can wrap the reader in an IndexedReader: +By default the annotation reader returns a list of annotations with +numeric indexes. If you want your annotations to be indexed by their +class name you can wrap the reader in an IndexedReader: .. code-block:: php @@ -145,31 +177,41 @@ to be indexed by their class name you can wrap the reader in an IndexedReader: .. warning:: - You should never wrap the indexed reader inside a cached reader only the other way around. This way you can re-use - the cache with indexed or numeric keys, otherwise your code may experience failures due to caching in an numerical - or indexed format. + You should never wrap the indexed reader inside a cached reader only + the other way around. This way you can re-use the cache with indexed + or numeric keys, otherwise your code may experience failures due to + caching in an numerical or indexed format. Registering Annotations ~~~~~~~~~~~~~~~~~~~~~~~ -As explained in the Introduction Doctrine Annotations uses its own autoloading mechanism to determine if a -given annotation has a corresponding PHP class that can be autoloaded. For Annotation Autoloading you have -to configure the ``Doctrine\Common\Annotations\AnnotationRegistry``. There are three different mechanisms -to configure annotation autoloading: - -- Calling ``AnnotationRegistry#registerFile($file)`` to register a file that contains one or more Annotation classes. -- Calling ``AnnotationRegistry#registerNamespace($namespace, $dirs = null)`` to register that the given namespace - contains annotations and that their base directory is located at the given $dirs or in the include path if NULL is passed. - The given directories should *NOT* be the directory where classes of the namespace are in, but the base directory - of the root namespace. The AnnotationRegistry uses a namespace to directory separator approach to resolve the correct path. -- Calling ``AnnotationRegistry#registerLoader($callable)`` to register an autoloader callback. The callback accepts the - class as first and only parameter and has to return true if the corresponding file was found and included. +As explained in the Introduction Doctrine Annotations uses its own +autoloading mechanism to determine if a given annotation has a +corresponding PHP class that can be autoloaded. For Annotation +Autoloading you have to configure the +``Doctrine\Common\Annotations\AnnotationRegistry``. There are three +different mechanisms to configure annotation autoloading: + +- Calling ``AnnotationRegistry#registerFile($file)`` to register a file + that contains one or more Annotation classes. +- Calling ``AnnotationRegistry#registerNamespace($namespace, $dirs = + null)`` to register that the given namespace contains annotations and + that their base directory is located at the given $dirs or in the + include path if NULL is passed. The given directories should *NOT* be + the directory where classes of the namespace are in, but the base + directory of the root namespace. The AnnotationRegistry uses a + namespace to directory separator approach to resolve the correct path. +- Calling ``AnnotationRegistry#registerLoader($callable)`` to register + an autoloader callback. The callback accepts the class as first and + only parameter and has to return true if the corresponding file was + found and included. .. note:: - Loaders have to fail silently, if a class is not found even if it matches for example the namespace prefix of that loader. - Never is a loader to throw a warning or exception if the loading failed otherwise parsing doc block annotations will become - a huge pain. + Loaders have to fail silently, if a class is not found even if it + matches for example the namespace prefix of that loader. Never is a + loader to throw a warning or exception if the loading failed + otherwise parsing doc block annotations will become a huge pain. A sample loader callback could look like: @@ -194,13 +236,15 @@ A sample loader callback could look like: Ignoring missing exceptions ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -By default an exception is thrown from the AnnotationReader if an annotation was found that: +By default an exception is thrown from the AnnotationReader if an +annotation was found that: - Is not part of the blacklist of ignored "documentation annotations". - Was not imported through a use statement - Is not a fully qualified class that exists -You can disable this behavior for specific names if your docblocks do not follow strict requirements: +You can disable this behavior for specific names if your docblocks do +not follow strict requirements: .. code-block:: php @@ -210,12 +254,14 @@ You can disable this behavior for specific names if your docblocks do not follow PHP Imports ~~~~~~~~~~~ -By default the annotation reader parses the use-statement of a php file to gain access to the import rules -and register them for the annotation processing. Only if you are using PHP Imports you can validate the correct -usage of annotations and throw exceptions if you misspelled an annotation. This mechanism is enabled by default. +By default the annotation reader parses the use-statement of a php file +to gain access to the import rules and register them for the annotation +processing. Only if you are using PHP Imports you can validate the +correct usage of annotations and throw exceptions if you misspelled an +annotation. This mechanism is enabled by default. -To ease the upgrade path, we still allow you to disable this mechanism. Note however that we will remove this -in future versions: +To ease the upgrade path, we still allow you to disable this mechanism. +Note however that we will remove this in future versions: .. code-block:: php diff --git a/docs/en/custom.rst b/docs/en/custom.rst index 860c6e67b..ee0258c3a 100644 --- a/docs/en/custom.rst +++ b/docs/en/custom.rst @@ -1,8 +1,10 @@ Custom Annotation Classes ========================= -If you want to define your own annotations you just have to group them in a namespace and register this namespace -in the AnnotationRegistry. Annotation classes have to contain a class-level docblock with the text ``@Annotation``: +If you want to define your own annotations you just have to group them +in a namespace and register this namespace in the AnnotationRegistry. +Annotation classes have to contain a class-level docblock with the text +``@Annotation``: .. code-block:: php @@ -18,7 +20,8 @@ Inject annotation values ------------------------ The annotation parser check if the annotation constructor has arguments, -if so then we will pass the value array, otherwise will try to inject values into public properties directly: +if so then we will pass the value array, otherwise will try to inject +values into public properties directly: .. code-block:: php @@ -53,8 +56,8 @@ if so then we will pass the value array, otherwise will try to inject values int Annotation Target ----------------- -``@Target`` indicates the kinds of class element to which an annotation type is applicable. -Then you could define one or more targets: +``@Target`` indicates the kinds of class element to which an annotation +type is applicable. Then you could define one or more targets: - ``CLASS`` Allowed in the class docblock - ``PROPERTY`` Allowed in the property docblock @@ -62,7 +65,8 @@ Then you could define one or more targets: - ``ALL`` Allowed in the class, property and method docblock - ``ANNOTATION`` Allowed inside other annotations -If the annotations is not allowed in the current context you got an ``AnnotationException`` +If the annotations is not allowed in the current context you got an +``AnnotationException`` .. code-block:: php @@ -89,9 +93,10 @@ If the annotations is not allowed in the current context you got an ``Annotation Attribute types --------------- -Annotation parser check the given parameters using the phpdoc annotation ``@var``, -The data type could be validated using the ``@var`` annotation on the annotation properties -or using the annotations ``@Attributes`` and ``@Attribute``. +Annotation parser check the given parameters using the phpdoc annotation +``@var``, The data type could be validated using the ``@var`` annotation +on the annotation properties or using the annotations ``@Attributes`` +and ``@Attribute``. If the data type not match you got an ``AnnotationException`` @@ -158,8 +163,9 @@ If the data type not match you got an ``AnnotationException`` Annotation Required ------------------- -``@Required`` indicates that the field must be specified when the annotation is used. -If it is not used you get an ``AnnotationException`` stating that this value can not be null. +``@Required`` indicates that the field must be specified when the +annotation is used. If it is not used you get an ``AnnotationException`` +stating that this value can not be null. Declaring a required field: @@ -189,9 +195,12 @@ Usage: Enumerated values ----------------- -- An annotation property marked with ``@Enum`` is a field that accept a fixed set of scalar values. -- You should use ``@Enum`` fields any time you need to represent fixed values. -- The annotation parser check the given value and throws an ``AnnotationException`` if the value not match. +- An annotation property marked with ``@Enum`` is a field that accept a + fixed set of scalar values. +- You should use ``@Enum`` fields any time you need to represent fixed + values. +- The annotation parser check the given value and throws an + ``AnnotationException`` if the value not match. Declaring an enumerated property: @@ -224,7 +233,8 @@ Annotation usage: Constants --------- -The use of constants and class constants are available on the annotations parser. +The use of constants and class constants are available on the +annotations parser. The following usage are allowed: @@ -251,8 +261,9 @@ Be careful with constants and the cache ! .. note:: - The cached reader will not re-evaluate each time an annotation is loaded from cache. - When a constant is changed the cache must be cleaned. + The cached reader will not re-evaluate each time an annotation is + loaded from cache. When a constant is changed the cache must be + cleaned. Usage @@ -291,8 +302,8 @@ Now we can write a script to get the annotations above: } } -You have a complete API for retrieving annotation class instances -from a class, property or method docblock: +You have a complete API for retrieving annotation class instances from a +class, property or method docblock: Reader API diff --git a/docs/en/index.rst b/docs/en/index.rst index 3ac670336..5e39bfca9 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -14,14 +14,13 @@ functionality for PHP classes. private $bar; } -Annotations aren't implemented in PHP itself which is why -this component offers a way to use the PHP doc-blocks as a -place for the well known annotation syntax using the -``@`` char. +Annotations aren't implemented in PHP itself which is why this component +offers a way to use the PHP doc-blocks as a place for the well known +annotation syntax using the ``@`` char. -Annotations in Doctrine are used for the ORM -configuration to build the class mapping, but it can -be used in other projects for other purposes too. +Annotations in Doctrine are used for the ORM configuration to build the +class mapping, but it can be used in other projects for other purposes +too. Installation ============ @@ -35,9 +34,9 @@ You can install the Annotation component with composer: Create an annotation class ========================== -An annotation class is a representation of the later -used annotation configuration in classes. The annotation -class of the previous example looks like this: +An annotation class is a representation of the later used annotation +configuration in classes. The annotation class of the previous example +looks like this: .. code-block:: php @@ -49,8 +48,7 @@ class of the previous example looks like this: public $myProperty; } -The annotation class is declared as an annotation by -``@Annotation``. +The annotation class is declared as an annotation by ``@Annotation``. :ref:`Read more about custom annotations. ` @@ -59,8 +57,8 @@ Reading annotations The access to the annotations happens by reflection of the class containing them. There are multiple reader-classes implementing the -``Doctrine\Common\Annotations\Reader`` interface, that can -access the annotations of a class. A common one is +``Doctrine\Common\Annotations\Reader`` interface, that can access the +annotations of a class. A common one is ``Doctrine\Common\Annotations\AnnotationReader``: .. code-block:: php @@ -73,8 +71,7 @@ access the annotations of a class. A common one is echo $myAnnotation->myProperty; // result: "value" -A reader has multiple methods to access the annotations -of a class. +A reader has multiple methods to access the annotations of a class. :ref:`Read more about handling annotations. ` From a9ab65177c7964fde5ef6b2c5a7829c002bee1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 19:36:40 +0100 Subject: [PATCH 02/16] Improve formatting --- docs/en/annotations.rst | 47 +++++++++++++++++++++-------------------- docs/en/custom.rst | 2 +- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/docs/en/annotations.rst b/docs/en/annotations.rst index cd6e42839..b604cbfa5 100644 --- a/docs/en/annotations.rst +++ b/docs/en/annotations.rst @@ -59,9 +59,9 @@ guess that the ORM Mapping, Assert Validation and the fully qualified annotation can just be loaded using the defined PHP autoloaders. This is not the case however: For error handling reasons every check for class existence inside the -AnnotationReader sets the second parameter $autoload +``AnnotationReader`` sets the second parameter $autoload of ``class_exists($name, $autoload)`` to false. To work flawlessly the -AnnotationReader requires silent autoloaders which many autoloaders are +``AnnotationReader`` requires silent autoloaders which many autoloaders are not. Silent autoloading is NOT part of the `PSR-0 specification `_ for autoloading. @@ -95,11 +95,12 @@ Doctrine saves all its annotations in a single file, that is why ``AnnotationRegistry#registerAutoloadNamespace`` which creates a PSR-0 compatible loading mechanism for class to file names. -In the third block, we create the actual AnnotationReader instance. Note -that we also add "dummy" to the global list of annotations for which we -do not throw exceptions. Setting this is necessary in our example case, -otherwise ``@dummy`` would trigger an exception to be thrown during the -parsing of the docblock of ``MyProject\Entities\User#id``. +In the third block, we create the actual ``AnnotationReader`` instance. +Note that we also add ``dummy`` to the global list of annotations for +which we do not throw exceptions. Setting this is necessary in our +example case, otherwise ``@dummy`` would trigger an exception to be +thrown during the parsing of the docblock of +``MyProject\Entities\User#id``. Setup and Configuration ----------------------- @@ -128,10 +129,10 @@ You can use a file caching reader: $debug = true ); -If you set the debug flag to true the cache reader will check for -changes in the original files, which is very important during -development. If you don't set it to true you have to delete the -directory to clear the cache. This gives faster performance, however +If you set the ``debug`` flag to ``true`` the cache reader will check +for changes in the original files, which is very important during +development. If you don't set it to ``true`` you have to delete the +directory to clear the cache. This gives faster performance, however should only be used in production, because of its inconvenience during development. @@ -150,13 +151,13 @@ implementations to cache the annotations: $debug = true ); -The debug flag is used here as well to invalidate the cache files when -the PHP class with annotations changed and should be used during +The ``debug`` flag is used here as well to invalidate the cache files +when the PHP class with annotations changed and should be used during development. .. warning :: - The AnnotationReader works and caches under the + The ``AnnotationReader`` works and caches under the assumption that all annotations of a doc-block are processed at once. That means that annotation classes that do not exist and aren't loaded and cannot be autoloaded (using the @@ -166,7 +167,7 @@ development. By default the annotation reader returns a list of annotations with numeric indexes. If you want your annotations to be indexed by their -class name you can wrap the reader in an IndexedReader: +class name you can wrap the reader in an ``IndexedReader``: .. code-block:: php @@ -197,14 +198,14 @@ different mechanisms to configure annotation autoloading: - Calling ``AnnotationRegistry#registerNamespace($namespace, $dirs = null)`` to register that the given namespace contains annotations and that their base directory is located at the given $dirs or in the - include path if NULL is passed. The given directories should *NOT* be - the directory where classes of the namespace are in, but the base + include path if ``NULL`` is passed. The given directories should *NOT* + be the directory where classes of the namespace are in, but the base directory of the root namespace. The AnnotationRegistry uses a namespace to directory separator approach to resolve the correct path. - Calling ``AnnotationRegistry#registerLoader($callable)`` to register an autoloader callback. The callback accepts the class as first and - only parameter and has to return true if the corresponding file was - found and included. + only parameter and has to return ``true`` if the corresponding file + was found and included. .. note:: @@ -236,12 +237,12 @@ A sample loader callback could look like: Ignoring missing exceptions ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -By default an exception is thrown from the AnnotationReader if an +By default an exception is thrown from the ``AnnotationReader`` if an annotation was found that: -- Is not part of the blacklist of ignored "documentation annotations". -- Was not imported through a use statement -- Is not a fully qualified class that exists +- is not part of the blacklist of ignored "documentation annotations"; +- was not imported through a use statement; +- is not a fully qualified class that exists. You can disable this behavior for specific names if your docblocks do not follow strict requirements: diff --git a/docs/en/custom.rst b/docs/en/custom.rst index ee0258c3a..430546824 100644 --- a/docs/en/custom.rst +++ b/docs/en/custom.rst @@ -2,7 +2,7 @@ Custom Annotation Classes ========================= If you want to define your own annotations you just have to group them -in a namespace and register this namespace in the AnnotationRegistry. +in a namespace and register this namespace in the ``AnnotationRegistry``. Annotation classes have to contain a class-level docblock with the text ``@Annotation``: From 2de650755784db730e102a5643679cf8a6605697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 19:42:22 +0100 Subject: [PATCH 03/16] punctuation --- docs/en/annotations.rst | 10 +++++----- docs/en/custom.rst | 7 ++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/en/annotations.rst b/docs/en/annotations.rst index b604cbfa5..a7fe774fa 100644 --- a/docs/en/annotations.rst +++ b/docs/en/annotations.rst @@ -178,15 +178,15 @@ class name you can wrap the reader in an ``IndexedReader``: .. warning:: - You should never wrap the indexed reader inside a cached reader only - the other way around. This way you can re-use the cache with indexed - or numeric keys, otherwise your code may experience failures due to - caching in an numerical or indexed format. + You should never wrap the indexed reader inside a cached reader, + only the other way around. This way you can re-use the cache with + indexed or numeric keys, otherwise your code may experience failures + due to caching in an numerical or indexed format. Registering Annotations ~~~~~~~~~~~~~~~~~~~~~~~ -As explained in the Introduction Doctrine Annotations uses its own +As explained in the Introduction, Doctrine Annotations uses its own autoloading mechanism to determine if a given annotation has a corresponding PHP class that can be autoloaded. For Annotation Autoloading you have to configure the diff --git a/docs/en/custom.rst b/docs/en/custom.rst index 430546824..c29fde61c 100644 --- a/docs/en/custom.rst +++ b/docs/en/custom.rst @@ -1,7 +1,7 @@ Custom Annotation Classes ========================= -If you want to define your own annotations you just have to group them +If you want to define your own annotations, you just have to group them in a namespace and register this namespace in the ``AnnotationRegistry``. Annotation classes have to contain a class-level docblock with the text ``@Annotation``: @@ -269,8 +269,9 @@ Be careful with constants and the cache ! Usage ----- -Using the library API is simple. Using the annotations described in the previous section -you can now annotate other classes with your annotations: +Using the library API is simple. Using the annotations described in the +previous section, you can now annotate other classes with your +annotations: .. code-block:: php From 55de5840d8712152925e8f220f5a812d987127ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 19:42:33 +0100 Subject: [PATCH 04/16] a vs an --- docs/en/annotations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/annotations.rst b/docs/en/annotations.rst index a7fe774fa..64fc772aa 100644 --- a/docs/en/annotations.rst +++ b/docs/en/annotations.rst @@ -181,7 +181,7 @@ class name you can wrap the reader in an ``IndexedReader``: You should never wrap the indexed reader inside a cached reader, only the other way around. This way you can re-use the cache with indexed or numeric keys, otherwise your code may experience failures - due to caching in an numerical or indexed format. + due to caching in a numerical or indexed format. Registering Annotations ~~~~~~~~~~~~~~~~~~~~~~~ From 644f850740057955d1c29a177c4d773aaf494b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 19:43:37 +0100 Subject: [PATCH 05/16] Use lowercase --- docs/en/annotations.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en/annotations.rst b/docs/en/annotations.rst index 64fc772aa..a788bb9c6 100644 --- a/docs/en/annotations.rst +++ b/docs/en/annotations.rst @@ -186,15 +186,15 @@ class name you can wrap the reader in an ``IndexedReader``: Registering Annotations ~~~~~~~~~~~~~~~~~~~~~~~ -As explained in the Introduction, Doctrine Annotations uses its own +As explained in the introduction, Doctrine Annotations uses its own autoloading mechanism to determine if a given annotation has a -corresponding PHP class that can be autoloaded. For Annotation -Autoloading you have to configure the +corresponding PHP class that can be autoloaded. For annotation +autoloading you have to configure the ``Doctrine\Common\Annotations\AnnotationRegistry``. There are three different mechanisms to configure annotation autoloading: - Calling ``AnnotationRegistry#registerFile($file)`` to register a file - that contains one or more Annotation classes. + that contains one or more annotation classes. - Calling ``AnnotationRegistry#registerNamespace($namespace, $dirs = null)`` to register that the given namespace contains annotations and that their base directory is located at the given $dirs or in the From ae17d1711054501b11899d84a12be039078b0f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 19:46:36 +0100 Subject: [PATCH 06/16] Makes sure function is recognized as such --- docs/en/annotations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/annotations.rst b/docs/en/annotations.rst index a788bb9c6..dc1e8e314 100644 --- a/docs/en/annotations.rst +++ b/docs/en/annotations.rst @@ -225,7 +225,7 @@ A sample loader callback could look like: $file = str_replace("\\", DIRECTORY_SEPARATOR, $class) . ".php"; if (file_exists("/my/base/path/" . $file)) { - // file exists makes sure that the loader fails silently + // file_exists() makes sure that the loader fails silently require "/my/base/path/" . $file; } }); From 50b9b37f5933c50a208eef63fe2c717b9aaad0d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 19:56:38 +0100 Subject: [PATCH 07/16] syntax --- docs/en/annotations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/annotations.rst b/docs/en/annotations.rst index dc1e8e314..031fb3478 100644 --- a/docs/en/annotations.rst +++ b/docs/en/annotations.rst @@ -257,7 +257,7 @@ PHP Imports By default the annotation reader parses the use-statement of a php file to gain access to the import rules and register them for the annotation -processing. Only if you are using PHP Imports you can validate the +processing. Only if you are using PHP Imports can you validate the correct usage of annotations and throw exceptions if you misspelled an annotation. This mechanism is enabled by default. From 987d9fe467b2b94402dd62ebd685fb561cb481ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 19:57:36 +0100 Subject: [PATCH 08/16] grammar --- docs/en/custom.rst | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/en/custom.rst b/docs/en/custom.rst index c29fde61c..542cf27e3 100644 --- a/docs/en/custom.rst +++ b/docs/en/custom.rst @@ -19,7 +19,7 @@ Annotation classes have to contain a class-level docblock with the text Inject annotation values ------------------------ -The annotation parser check if the annotation constructor has arguments, +The annotation parser checks if the annotation constructor has arguments, if so then we will pass the value array, otherwise will try to inject values into public properties directly: @@ -56,13 +56,13 @@ values into public properties directly: Annotation Target ----------------- -``@Target`` indicates the kinds of class element to which an annotation -type is applicable. Then you could define one or more targets: +``@Target`` indicates the kinds of class elements to which an annotation +type is applicable. Then you could define one or more targets: -- ``CLASS`` Allowed in the class docblock -- ``PROPERTY`` Allowed in the property docblock -- ``METHOD`` Allowed in the method docblock -- ``ALL`` Allowed in the class, property and method docblock +- ``CLASS`` Allowed in class docblocks +- ``PROPERTY`` Allowed in property docblocks +- ``METHOD`` Allowed in the method docblocks +- ``ALL`` Allowed in class, property and method docblocks - ``ANNOTATION`` Allowed inside other annotations If the annotations is not allowed in the current context you got an @@ -93,12 +93,12 @@ If the annotations is not allowed in the current context you got an Attribute types --------------- -Annotation parser check the given parameters using the phpdoc annotation -``@var``, The data type could be validated using the ``@var`` annotation -on the annotation properties or using the annotations ``@Attributes`` -and ``@Attribute``. +The annotation parser checks the given parameters using the phpdoc +annotation ``@var``, The data type could be validated using the ``@var`` +annotation on the annotation properties or using the ``@Attributes`` and +``@Attribute`` annotations. -If the data type not match you got an ``AnnotationException`` +If the data type does not match you get an ``AnnotationException`` .. code-block:: php @@ -195,12 +195,12 @@ Usage: Enumerated values ----------------- -- An annotation property marked with ``@Enum`` is a field that accept a +- An annotation property marked with ``@Enum`` is a field that accepts a fixed set of scalar values. - You should use ``@Enum`` fields any time you need to represent fixed values. -- The annotation parser check the given value and throws an - ``AnnotationException`` if the value not match. +- The annotation parser checks the given value and throws an + ``AnnotationException`` if the value does not match. Declaring an enumerated property: @@ -233,10 +233,10 @@ Annotation usage: Constants --------- -The use of constants and class constants are available on the -annotations parser. +The use of constants and class constants is available on the annotations +parser. -The following usage are allowed: +The following usages are allowed: .. code-block:: php From 49395f19bb45a0dadfbe275b8ec5829e423094f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 19:58:06 +0100 Subject: [PATCH 09/16] add missing word --- docs/en/custom.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/custom.rst b/docs/en/custom.rst index 542cf27e3..3513b6274 100644 --- a/docs/en/custom.rst +++ b/docs/en/custom.rst @@ -20,7 +20,7 @@ Inject annotation values ------------------------ The annotation parser checks if the annotation constructor has arguments, -if so then we will pass the value array, otherwise will try to inject +if so then we will pass the value array, otherwise we will try to inject values into public properties directly: From b35e6377e854269ea988588996ca12a2b0d92f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 20:00:01 +0100 Subject: [PATCH 10/16] Improve style --- docs/en/custom.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/custom.rst b/docs/en/custom.rst index 3513b6274..221c2de52 100644 --- a/docs/en/custom.rst +++ b/docs/en/custom.rst @@ -65,8 +65,8 @@ type is applicable. Then you could define one or more targets: - ``ALL`` Allowed in class, property and method docblocks - ``ANNOTATION`` Allowed inside other annotations -If the annotations is not allowed in the current context you got an -``AnnotationException`` +If the annotations is not allowed in the current context, an +``AnnotationException`` is thrown. .. code-block:: php From 1f9d20607c55321478b9acf31adb852f3520f95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 24 Jan 2020 20:06:20 +0100 Subject: [PATCH 11/16] Use a more appopriate verb --- docs/en/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/index.rst b/docs/en/index.rst index 5e39bfca9..60f3ffe9d 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -1,7 +1,7 @@ Introduction ============ -Doctrine Annotations offers to implement custom annotation +Doctrine Annotations allows to implement custom annotation functionality for PHP classes. .. code-block:: php From 09e57bb560ee3439c26b6850a764c837ce8b9301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Wed, 29 Jan 2020 07:44:08 +0100 Subject: [PATCH 12/16] Use more precise language --- docs/en/annotations.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/en/annotations.rst b/docs/en/annotations.rst index 031fb3478..e4996c4e7 100644 --- a/docs/en/annotations.rst +++ b/docs/en/annotations.rst @@ -90,16 +90,16 @@ with Doctrine Annotations requires this setup: The second block with the annotation registry calls registers all the three different annotation namespaces that are used. -Doctrine saves all its annotations in a single file, that is why -``AnnotationRegistry#registerFile`` is used in contrast to +Doctrine Annotations saves all its annotations in a single file, that is +why ``AnnotationRegistry#registerFile`` is used in contrast to ``AnnotationRegistry#registerAutoloadNamespace`` which creates a PSR-0 compatible loading mechanism for class to file names. In the third block, we create the actual ``AnnotationReader`` instance. -Note that we also add ``dummy`` to the global list of annotations for -which we do not throw exceptions. Setting this is necessary in our -example case, otherwise ``@dummy`` would trigger an exception to be -thrown during the parsing of the docblock of +Note that we also add ``dummy`` to the global list of ignored +annotations for which we do not throw exceptions. Setting this is +necessary in our example case, otherwise ``@dummy`` would trigger an +exception to be thrown during the parsing of the docblock of ``MyProject\Entities\User#id``. Setup and Configuration From aaf019b3d36c3a967ffbd087ec3f090df7992fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Wed, 5 Feb 2020 10:03:04 +0100 Subject: [PATCH 13/16] Refer to annotation parser with "it" --- docs/en/custom.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/custom.rst b/docs/en/custom.rst index 221c2de52..e589a5432 100644 --- a/docs/en/custom.rst +++ b/docs/en/custom.rst @@ -20,7 +20,7 @@ Inject annotation values ------------------------ The annotation parser checks if the annotation constructor has arguments, -if so then we will pass the value array, otherwise we will try to inject +if so then it will pass the value array, otherwise it will try to inject values into public properties directly: From fe56bdf7c1f3ba99e00663de2acd8a725bc1a86d Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Tue, 19 Feb 2019 12:06:35 +0100 Subject: [PATCH 14/16] fix ignored annotations with namespace alias When I set a namespace to ignored but use a namespace alias, there was no check if the class actually exists. Instead of ignoring, we ended up with an exception that the annotation could not be autoloaded. --- lib/Doctrine/Common/Annotations/DocParser.php | 9 +++++---- .../Common/Annotations/AnnotationReaderTest.php | 16 ++++++++++++++++ .../IgnoredNamespaces/AnnotatedWithAlias.php | 13 +++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 tests/Doctrine/Tests/Common/Annotations/Fixtures/IgnoredNamespaces/AnnotatedWithAlias.php diff --git a/lib/Doctrine/Common/Annotations/DocParser.php b/lib/Doctrine/Common/Annotations/DocParser.php index f076f36a4..56a06c21e 100644 --- a/lib/Doctrine/Common/Annotations/DocParser.php +++ b/lib/Doctrine/Common/Annotations/DocParser.php @@ -710,10 +710,11 @@ private function Annotation() } } } elseif (isset($this->imports[$loweredAlias])) { - $found = true; - $name = (false !== $pos) - ? $this->imports[$loweredAlias] . substr($name, $pos) - : $this->imports[$loweredAlias]; + $namespace = ltrim($this->imports[$loweredAlias], '\\'); + $name = (false !== $pos) + ? $namespace . substr($name, $pos) + : $namespace; + $found = $this->classExists($name); } elseif ( ! isset($this->ignoredAnnotationNames[$name]) && isset($this->imports['__NAMESPACE__']) && $this->classExists($this->imports['__NAMESPACE__'] . '\\' . $name) diff --git a/tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php b/tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php index c2633f29b..63a344959 100644 --- a/tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php +++ b/tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php @@ -12,6 +12,7 @@ use Doctrine\Tests\Common\Annotations\Fixtures\IgnoredNamespaces\AnnotatedAtClassLevel; use Doctrine\Tests\Common\Annotations\Fixtures\IgnoredNamespaces\AnnotatedAtMethodLevel; use Doctrine\Tests\Common\Annotations\Fixtures\IgnoredNamespaces\AnnotatedAtPropertyLevel; +use Doctrine\Tests\Common\Annotations\Fixtures\IgnoredNamespaces\AnnotatedWithAlias; class AnnotationReaderTest extends AbstractReaderTest { @@ -114,6 +115,21 @@ public function testPropertyAnnotationIsIgnored() self::assertEmpty($reader->getPropertyAnnotations($ref->getProperty('property'))); } + /** + * @group 244 + * + * @runInSeparateProcess + */ + public function testAnnotationWithAliasIsIgnored(): void + { + $reader = $this->getReader(); + $ref = new \ReflectionClass(AnnotatedWithAlias::class); + + $reader::addGlobalIgnoredNamespace('SomePropertyAnnotationNamespace'); + + self::assertEmpty($reader->getPropertyAnnotations($ref->getProperty('property'))); + } + public function testClassWithFullPathUseStatement() { if (class_exists(SingleUseAnnotation::class, false)) { diff --git a/tests/Doctrine/Tests/Common/Annotations/Fixtures/IgnoredNamespaces/AnnotatedWithAlias.php b/tests/Doctrine/Tests/Common/Annotations/Fixtures/IgnoredNamespaces/AnnotatedWithAlias.php new file mode 100644 index 000000000..ca4dfd15d --- /dev/null +++ b/tests/Doctrine/Tests/Common/Annotations/Fixtures/IgnoredNamespaces/AnnotatedWithAlias.php @@ -0,0 +1,13 @@ + Date: Fri, 25 Aug 2017 17:00:03 +0200 Subject: [PATCH 15/16] Add a test and fix the behavior of issue #141 When there is a leading backslash in front of a class name as annotation value, the leading backslash gets removed. --- lib/Doctrine/Common/Annotations/DocParser.php | 30 ++++++++-- .../Common/Annotations/Ticket/DCOM141Test.php | 60 +++++++++++++++++++ 2 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM141Test.php diff --git a/lib/Doctrine/Common/Annotations/DocParser.php b/lib/Doctrine/Common/Annotations/DocParser.php index f076f36a4..7d9c3151e 100644 --- a/lib/Doctrine/Common/Annotations/DocParser.php +++ b/lib/Doctrine/Common/Annotations/DocParser.php @@ -968,10 +968,14 @@ private function Constant() } } - // checks if identifier ends with ::class, \strlen('::class') === 7 - $classPos = stripos($identifier, '::class'); - if ($classPos === strlen($identifier) - 7) { - return substr($identifier, 0, $classPos); + /** + * Checks if identifier ends with ::class and remove the leading backslash if it exists. + */ + if ($this->identifierEndsWithClassConstant($identifier) && ! $this->identifierStartsWithBackslash($identifier)) { + return substr($identifier, 0, $this->getClassConstantPositionInIdentifier($identifier)); + } + if ($this->identifierEndsWithClassConstant($identifier) && $this->identifierStartsWithBackslash($identifier)) { + return substr($identifier, 1, $this->getClassConstantPositionInIdentifier($identifier) - 1); } if (!defined($identifier)) { @@ -981,6 +985,24 @@ private function Constant() return constant($identifier); } + private function identifierStartsWithBackslash(string $identifier) : bool + { + return '\\' === $identifier[0]; + } + + private function identifierEndsWithClassConstant(string $identifier) : bool + { + return $this->getClassConstantPositionInIdentifier($identifier) === strlen($identifier) - strlen('::class'); + } + + /** + * @return int|false + */ + private function getClassConstantPositionInIdentifier(string $identifier) + { + return stripos($identifier, '::class'); + } + /** * Identifier ::= string * diff --git a/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM141Test.php b/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM141Test.php new file mode 100644 index 000000000..031241c7f --- /dev/null +++ b/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM141Test.php @@ -0,0 +1,60 @@ +getClassAnnotations($class); + + self::assertCount(1, $annots); + self::assertInstanceOf(DCOM141Annotation::class, $annots[0]); + self::assertEquals('SimpleXMLElement', $annots[0]->classPath); + } + + public function testAnnotationNotPrefixed() + { + $class = new \ReflectionClass(DCOM141ConsumerNotPrefixed::class); + $reader = new AnnotationReader(); + $annots = $reader->getClassAnnotations($class); + + self::assertCount(1, $annots); + self::assertInstanceOf(DCOM141Annotation::class, $annots[0]); + self::assertEquals('SimpleXMLElement', $annots[0]->classPath); + } + +} + +/** + * @Annotation + */ +class DCOM141Annotation +{ + public $classPath; +} + +/** + * @DCOM141Annotation(\SimpleXMLElement::class) + */ +class DCOM141ConsumerPrefixed +{ + +} + +/** + * @DCOM141Annotation(SimpleXMLElement::class) + */ +class DCOM141ConsumerNotPrefixed +{ + +} From 7bd39e853d8caf7d467d13c0efb900eb5b647a16 Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Sat, 7 Mar 2020 10:14:31 +0100 Subject: [PATCH 16/16] Add precisions about annotations autoloading --- docs/en/index.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/en/index.rst b/docs/en/index.rst index 60f3ffe9d..7a6be485b 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -63,6 +63,12 @@ annotations of a class. A common one is .. code-block:: php + use Doctrine\Common\Annotations\AnnotationReader; + use Doctrine\Common\Annotations\AnnotationRegistry; + + // Deprecated and will be removed in 2.0 but currently needed + AnnotationRegistry::registerLoader('class_exists'); + $reflectionClass = new ReflectionClass(Foo::class); $property = $reflectionClass->getProperty('bar'); @@ -73,6 +79,13 @@ annotations of a class. A common one is A reader has multiple methods to access the annotations of a class. +Note that ``AnnotationRegistry::registerLoader('class_exists')`` only works +if you already have an autoloader configured (i.e. composer autoloader). +Otherwise, :ref:`please take a look to the other annotation autoload mechanisms `. + +A reader has multiple methods to access the annotations +of a class. + :ref:`Read more about handling annotations. ` IDE Support