.gitignore000064400000000055144760120550006540 0ustar00build.properties build/ logs/ reports/ dist/ .travis.yml000064400000000044144760120550006657 0ustar00language: php php: - 5.3 - 5.4 LICENSE000064400000063474144760120550005573 0ustar00 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! UPGRADE_TO_2_1000064400000004121144760120550006623 0ustar00This document details all the possible changes that you should investigate when updating your project from Doctrine Common 2.0.x to 2.1 ## AnnotationReader changes The annotation reader was heavily refactored between 2.0 and 2.1-RC1. In theory the operation of the new reader should be backwards compatible, but it has to be setup differently to work that way: $reader = new \Doctrine\Common\Annotations\AnnotationReader(); $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); // new code necessary starting here $reader->setIgnoreNotImportedAnnotations(true); $reader->setEnableParsePhpImports(false); $reader = new \Doctrine\Common\Annotations\CachedReader( new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache() ); ## Annotation Base class or @Annotation Beginning after 2.1-RC2 you have to either extend ``Doctrine\Common\Annotations\Annotation`` or add @Annotation to your annotations class-level docblock, otherwise the class will simply be ignored. ## Removed methods on AnnotationReader * AnnotationReader::setAutoloadAnnotations() * AnnotationReader::getAutoloadAnnotations() * AnnotationReader::isAutoloadAnnotations() ## AnnotationRegistry Autoloading through the PHP autoloader is removed from the 2.1 AnnotationReader. Instead you have to use the global AnnotationRegistry for loading purposes: \Doctrine\Common\Annotations\AnnotationRegistry::registerFile($fileWithAnnotations); \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace($namespace, $dirs = null); \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespaces($namespaces); \Doctrine\Common\Annotations\AnnotationRegistry::registerLoader($callable); The $callable for registering a loader accepts a class as first and only parameter and must try to silently autoload it. On success true has to be returned. The registerAutoloadNamespace function registers a PSR-0 compatible silent autoloader for all classes with the given namespace in the given directories. If null is passed as directory the include path will be used. build.properties.dev000064400000000437144760120550010546 0ustar00version=2.0.0BETA2 stability=beta build.dir=build dist.dir=dist report.dir=reports log.archive.dir=logs svn.path=/usr/bin/svn test.phpunit_configuration_file= test.phpunit_generate_coverage=0 test.pmd_reports=0 test.pdepend_exec= test.phpmd_exec= project.pirum_dir= project.download_dir=build.xml000064400000016324144760120550006377 0ustar00 DoctrineCommon Doctrine Common PHP Extensions pear.doctrine-project.org The Doctrine Common package contains shared code between the other packages. LGPL - composer.json000064400000001275144760120550007277 0ustar00{ "name": "doctrine/common", "type": "library", "description": "Common Library for Doctrine projects", "keywords": ["collections", "spl", "eventmanager", "annotations", "persistence"], "homepage": "http://www.doctrine-project.org", "license": "LGPL", "authors": [ {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, {"name": "Roman Borschel", "email": "roman@code-factory.org"}, {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} ], "require": { "php": ">=5.3.2" } } lib/Doctrine/Common/Annotations/Annotation.php000064400000004525144760120550015443 0ustar00. */ namespace Doctrine\Common\Annotations; /** * Annotations class * * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ class Annotation { /** * Value property. Common among all derived classes. * * @var string */ public $value; /** * Constructor * * @param array $data Key-value for properties to be defined in this class */ public final function __construct(array $data) { foreach ($data as $key => $value) { $this->$key = $value; } } /** * Error handler for unknown property accessor in Annotation class. * * @param string $name Unknown property name */ public function __get($name) { throw new \BadMethodCallException( sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this)) ); } /** * Error handler for unknown property mutator in Annotation class. * * @param string $name Unkown property name * @param mixed $value Property value */ public function __set($name, $value) { throw new \BadMethodCallException( sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this)) ); } }lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php000064400000003242144760120550020714 0ustar00. */ namespace Doctrine\Common\Annotations\Annotation; /** * Annotation that can be used to signal to the parser to ignore specific * annotations during the parsing process. * * @author Johannes M. Schmitt */ final class IgnoreAnnotation { public $names; public function __construct(array $values) { if (is_string($values['value'])) { $values['value'] = array($values['value']); } if (!is_array($values['value'])) { throw new \RuntimeException(sprintf('@IgnoreAnnotation expects either a string name, or an array of strings, but got %s.', json_encode($values['value']))); } $this->names = $values['value']; } }lib/Doctrine/Common/Annotations/AnnotationException.php000064400000003620144760120550017315 0ustar00. */ namespace Doctrine\Common\Annotations; /** * Description of AnnotationException * * @since 2.0 * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ class AnnotationException extends \Exception { /** * Creates a new AnnotationException describing a Syntax error. * * @param string $message Exception message * @return AnnotationException */ public static function syntaxError($message) { return new self('[Syntax Error] ' . $message); } /** * Creates a new AnnotationException describing a Semantical error. * * @param string $message Exception message * @return AnnotationException */ public static function semanticalError($message) { return new self('[Semantical Error] ' . $message); } }lib/Doctrine/Common/Annotations/AnnotationReader.php000064400000031306144760120550016563 0ustar00. */ namespace Doctrine\Common\Annotations; use Doctrine\Common\Annotations\Annotation\IgnoreAnnotation; use Closure; use ReflectionClass; use ReflectionMethod; use ReflectionProperty; require_once __DIR__ . '/Annotation/IgnoreAnnotation.php'; /** * A reader for docblock annotations. * * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author Johannes M. Schmitt */ final class AnnotationReader implements Reader { /** * Global map for imports. * * @var array */ private static $globalImports = array( 'ignoreannotation' => 'Doctrine\Common\Annotations\Annotation\IgnoreAnnotation', ); /** * A list with annotations that are not causing exceptions when not resolved to an annotation class. * * The names are case sensitive. * * @var array */ private static $globalIgnoredNames = array( 'access'=> true, 'author'=> true, 'copyright'=> true, 'deprecated'=> true, 'example'=> true, 'ignore'=> true, 'internal'=> true, 'link'=> true, 'see'=> true, 'since'=> true, 'tutorial'=> true, 'version'=> true, 'package'=> true, 'subpackage'=> true, 'name'=> true, 'global'=> true, 'param'=> true, 'return'=> true, 'staticvar'=> true, 'category'=> true, 'staticVar'=> true, 'static'=> true, 'var'=> true, 'throws'=> true, 'inheritdoc'=> true, 'inheritDoc'=> true, 'license'=> true, 'todo'=> true, 'deprecated'=> true, 'deprec'=> true, 'author'=> true, 'property' => true, 'method' => true, 'abstract'=> true, 'exception'=> true, 'magic' => true, 'api' => true, 'final'=> true, 'filesource'=> true, 'throw' => true, 'uses' => true, 'usedby'=> true, 'private' => true, 'Annotation' => true, 'override' => true, 'codeCoverageIgnoreStart' => true, 'codeCoverageIgnoreEnd' => true, 'Required' => true, 'Attribute' => true, 'Attributes' => true, 'Target' => true, 'SuppressWarnings' => true, ); /** * Add a new annotation to the globally ignored annotation names with regard to exception handling. * * @param string $name */ static public function addGlobalIgnoredName($name) { self::$globalIgnoredNames[$name] = true; } /** * Annotations Parser * * @var Doctrine\Common\Annotations\DocParser */ private $parser; /** * Annotations Parser used to collect parsing metadata * * @var Doctrine\Common\Annotations\DocParser */ private $preParser; /** * PHP Parser used to collect imports. * * @var Doctrine\Common\Annotations\PhpParser */ private $phpParser; /** * In-memory cache mechanism to store imported annotations per class. * * @var array */ private $imports = array(); /** * In-memory cache mechanism to store ignored annotations per class. * * @var array */ private $ignoredAnnotationNames = array(); /** * @var string */ private $defaultAnnotationNamespace = false; /** * @var bool */ private $enablePhpImports = true; /** * Constructor. Initializes a new AnnotationReader that uses the given Cache provider. * * @param DocParser $parser The parser to use. If none is provided, the default parser is used. */ public function __construct() { AnnotationRegistry::registerFile(__DIR__ . '/Annotation/IgnoreAnnotation.php'); $this->parser = new DocParser; $this->preParser = new DocParser; $this->preParser->setImports(self::$globalImports); $this->preParser->setIgnoreNotImportedAnnotations(true); $this->phpParser = new PhpParser; } /** * Ignore not imported annotations and not throw an exception. * * @param bool $bool */ public function setIgnoreNotImportedAnnotations($bool) { $this->parser->setIgnoreNotImportedAnnotations($bool); } /** * Detect imports by parsing the use statements of affected files. * * @deprecated Will be removed in 3.0, imports will always be enabled. * @param bool $flag */ public function setEnableParsePhpImports($flag) { $this->enablePhpImports = $flag; } /** * @deprecated Will be removed in 3.0, imports will always be enabled. * @return bool */ public function isParsePhpImportsEnabled() { return $this->enablePhpImports; } /** * Sets the default namespace that the AnnotationReader should assume for annotations * with not fully qualified names. * * @deprecated This method will be removed in Doctrine Common 3.0 * @param string $defaultNamespace */ public function setDefaultAnnotationNamespace($defaultNamespace) { $this->defaultAnnotationNamespace = $defaultNamespace; } /** * Sets the custom function to use for creating new annotations on the * underlying parser. * * The function is supplied two arguments. The first argument is the name * of the annotation and the second argument an array of values for this * annotation. The function is assumed to return an object or NULL. * Whenever the function returns NULL for an annotation, the implementation falls * back to the default annotation creation process of the underlying parser. * * @deprecated This method will be removed in Doctrine Common 3.0 * @param Closure $func */ public function setAnnotationCreationFunction(Closure $func) { $this->parser->setAnnotationCreationFunction($func); } /** * Sets an alias for an annotation namespace. * * @param string $namespace * @param string $alias */ public function setAnnotationNamespaceAlias($namespace, $alias) { $this->parser->setAnnotationNamespaceAlias($namespace, $alias); } /** * Gets the annotations applied to a class. * * @param string|ReflectionClass $class The name or ReflectionClass of the class from which * the class annotations should be read. * @return array An array of Annotations. */ public function getClassAnnotations(ReflectionClass $class) { $this->parser->setImports($this->getImports($class)); $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class)); return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName()); } /** * Gets a class annotation. * * @param ReflectionClass $class The ReflectionClass of the class from which * the class annotations should be read. * @param string $annotationName The name of the annotation. * @return The Annotation or NULL, if the requested annotation does not exist. */ public function getClassAnnotation(ReflectionClass $class, $annotationName) { $annotations = $this->getClassAnnotations($class); foreach ($annotations as $annotation) { if ($annotation instanceof $annotationName) { return $annotation; } } return null; } /** * Gets the annotations applied to a property. * * @param string|ReflectionProperty $property The name or ReflectionProperty of the property * from which the annotations should be read. * @return array An array of Annotations. */ public function getPropertyAnnotations(ReflectionProperty $property) { $class = $property->getDeclaringClass(); $context = 'property ' . $class->getName() . "::\$" . $property->getName(); $this->parser->setImports($this->getImports($class)); $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class)); return $this->parser->parse($property->getDocComment(), $context); } /** * Gets a property annotation. * * @param ReflectionProperty $property * @param string $annotationName The name of the annotation. * @return The Annotation or NULL, if the requested annotation does not exist. */ public function getPropertyAnnotation(ReflectionProperty $property, $annotationName) { $annotations = $this->getPropertyAnnotations($property); foreach ($annotations as $annotation) { if ($annotation instanceof $annotationName) { return $annotation; } } return null; } /** * Gets the annotations applied to a method. * * @param ReflectionMethod $property The name or ReflectionMethod of the method from which * the annotations should be read. * @return array An array of Annotations. */ public function getMethodAnnotations(ReflectionMethod $method) { $class = $method->getDeclaringClass(); $context = 'method ' . $class->getName() . '::' . $method->getName() . '()'; $this->parser->setImports($this->getImports($class)); $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class)); return $this->parser->parse($method->getDocComment(), $context); } /** * Gets a method annotation. * * @param ReflectionMethod $method * @param string $annotationName The name of the annotation. * @return The Annotation or NULL, if the requested annotation does not exist. */ public function getMethodAnnotation(ReflectionMethod $method, $annotationName) { $annotations = $this->getMethodAnnotations($method); foreach ($annotations as $annotation) { if ($annotation instanceof $annotationName) { return $annotation; } } return null; } /** * Returns the ignored annotations for the given class. * * @param ReflectionClass $class * @return array */ private function getIgnoredAnnotationNames(ReflectionClass $class) { if (isset($this->ignoredAnnotationNames[$name = $class->getName()])) { return $this->ignoredAnnotationNames[$name]; } $this->collectParsingMetadata($class); return $this->ignoredAnnotationNames[$name]; } private function getImports(ReflectionClass $class) { if (isset($this->imports[$name = $class->getName()])) { return $this->imports[$name]; } $this->collectParsingMetadata($class); return $this->imports[$name]; } /** * Collects parsing metadata for a given class * * @param ReflectionClass $class */ private function collectParsingMetadata(ReflectionClass $class) { $imports = self::$globalImports; $ignoredAnnotationNames = self::$globalIgnoredNames; if ($this->enablePhpImports) { $annotations = $this->preParser->parse($class->getDocComment()); foreach ($annotations as $annotation) { if ($annotation instanceof IgnoreAnnotation) { foreach ($annotation->names AS $annot) { $ignoredAnnotationNames[$annot] = true; } } } } $name = $class->getName(); $this->imports[$name] = array_merge( self::$globalImports, ($this->enablePhpImports) ? $this->phpParser->parseClass($class) : array(), ($this->enablePhpImports) ? array('__NAMESPACE__' => $class->getNamespaceName()) : array() ); if ($this->defaultAnnotationNamespace) { $this->imports[$name]['__DEFAULT__'] = $this->defaultAnnotationNamespace; } $this->ignoredAnnotationNames[$name] = $ignoredAnnotationNames; } } lib/Doctrine/Common/Annotations/AnnotationRegistry.php000064400000010570144760120550017171 0ustar00. */ namespace Doctrine\Common\Annotations; final class AnnotationRegistry { /** * A map of namespaces to use for autoloading purposes based on a PSR-0 convention. * * Contains the namespace as key and an array of direectories as value. If the value is NULL * the include path is used for checking for the corresponding file. * * This autoloading mechanism does not utilize the PHP autoloading but implements autoloading on its own. * * @var array */ static private $autoloadNamespaces = array(); /** * A map of autoloader callables. * * @var array */ static private $loaders = array(); static public function reset() { self::$autoloadNamespaces = array(); self::$loaders = array(); } static public function registerFile($file) { require_once $file; } /** * Add a namespace with one or many directories to look for files or null for the include path. * * Loading of this namespaces will be done with a PSR-0 namespace loading algorithm. * * @param string $namespace * @param string|array|null $dirs */ static public function registerAutoloadNamespace($namespace, $dirs = null) { self::$autoloadNamespaces[$namespace] = $dirs; } /** * Register multiple namespaces * * Loading of this namespaces will be done with a PSR-0 namespace loading algorithm. * * @param array $namespaces */ static public function registerAutoloadNamespaces(array $namespaces) { self::$autoloadNamespaces = array_merge(self::$autoloadNamespaces, $namespaces); } /** * Register an autoloading callabale for annotations, much like spl_autoload_register(). * * NOTE: These class loaders HAVE to be silent when a class was not found! * IMPORTANT: Loaders have to return true if they loaded a class that could contain the searched annotation class. * * @param callabale $callabale */ static public function registerLoader($callabale) { if (!is_callable($callabale)) { throw new \InvalidArgumentException("A callable is expected in AnnotationRegistry::registerLoader()."); } self::$loaders[] = $callabale; } /** * Autoload an annotation class silently. * * @param string $class * @return void */ static public function loadAnnotationClass($class) { foreach (self::$autoloadNamespaces AS $namespace => $dirs) { if (strpos($class, $namespace) === 0) { $file = str_replace("\\", DIRECTORY_SEPARATOR, $class) . ".php"; if ($dirs === null) { if ($path = stream_resolve_include_path($file)) { require $path; return true; } } else { foreach((array)$dirs AS $dir) { if (file_exists($dir . DIRECTORY_SEPARATOR . $file)) { require $dir . DIRECTORY_SEPARATOR . $file; return true; } } } } } foreach (self::$loaders AS $loader) { if (call_user_func($loader, $class) === true) { return true; } } return false; } }lib/Doctrine/Common/Annotations/CachedReader.php000064400000012415144760120550015620 0ustar00. */ namespace Doctrine\Common\Annotations; use Doctrine\Common\Cache\Cache; /** * A cache aware annotation reader. * * @author Johannes M. Schmitt * @author Benjamin Eberlei */ final class CachedReader implements Reader { private static $CACHE_SALT = '@[Annot]'; /** * @var Reader */ private $delegate; /** * @var Cache */ private $cache; /** * @var boolean */ private $debug; /** * @var array */ private $loadedAnnotations; /** * @param Reader $reader * @param Cache $cache */ public function __construct(Reader $reader, Cache $cache, $debug = false) { $this->delegate = $reader; $this->cache = $cache; $this->debug = $debug; } public function getClassAnnotations(\ReflectionClass $class) { $cacheKey = $class->getName() . self::$CACHE_SALT; if (isset($this->loadedAnnotations[$cacheKey])) { return $this->loadedAnnotations[$cacheKey]; } // Attempt to grab data from cache if (($data = $this->cache->fetch($cacheKey)) !== false) { if (!$this->debug || $this->isCacheFresh($cacheKey, $class)) { return $data; } } $annots = $this->delegate->getClassAnnotations($class); $this->cache->save($cacheKey, $annots); $this->cache->save('[C]'.$cacheKey, time()); return $this->loadedAnnotations[$cacheKey] = $annots; } public function getClassAnnotation(\ReflectionClass $class, $annotationName) { foreach ($this->getClassAnnotations($class) as $annot) { if ($annot instanceof $annotationName) { return $annot; } } return null; } public function getPropertyAnnotations(\ReflectionProperty $property) { $class = $property->getDeclaringClass(); $cacheKey = $class->getName().'$'.$property->getName().self::$CACHE_SALT; if (isset($this->loadedAnnotations[$cacheKey])) { return $this->loadedAnnotations[$cacheKey]; } // Attempt to grab data from cache if (($data = $this->cache->fetch($cacheKey)) !== false) { if (!$this->debug || $this->isCacheFresh($cacheKey, $class)) { return $data; } } $annots = $this->delegate->getPropertyAnnotations($property); $this->cache->save($cacheKey, $annots); $this->cache->save('[C]'.$cacheKey, time()); return $this->loadedAnnotations[$cacheKey] = $annots; } public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) { foreach ($this->getPropertyAnnotations($property) as $annot) { if ($annot instanceof $annotationName) { return $annot; } } return null; } public function getMethodAnnotations(\ReflectionMethod $method) { $class = $method->getDeclaringClass(); $cacheKey = $class->getName().'#'.$method->getName().self::$CACHE_SALT; if (isset($this->loadedAnnotations[$cacheKey])) { return $this->loadedAnnotations[$cacheKey]; } // Attempt to grab data from cache if (($data = $this->cache->fetch($cacheKey)) !== false) { if (!$this->debug || $this->isCacheFresh($cacheKey, $class)) { return $data; } } $annots = $this->delegate->getMethodAnnotations($method); $this->cache->save($cacheKey, $annots); $this->cache->save('[C]'.$cacheKey, time()); return $this->loadedAnnotations[$cacheKey] = $annots; } public function getMethodAnnotation(\ReflectionMethod $method, $annotationName) { foreach ($this->getMethodAnnotations($method) as $annot) { if ($annot instanceof $annotationName) { return $annot; } } return null; } public function clearLoadedAnnotations() { $this->loadedAnnotations = array(); } private function isCacheFresh($cacheKey, \ReflectionClass $class) { if (false === $filename = $class->getFilename()) { return true; } return $this->cache->fetch('[C]'.$cacheKey) >= filemtime($filename); } }lib/Doctrine/Common/Annotations/DocLexer.php000064400000007664144760120550015045 0ustar00. */ namespace Doctrine\Common\Annotations; use Doctrine\Common\Lexer; /** * Simple lexer for docblock annotations. * * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author Johannes M. Schmitt */ final class DocLexer extends Lexer { const T_NONE = 1; const T_IDENTIFIER = 2; const T_INTEGER = 3; const T_STRING = 4; const T_FLOAT = 5; const T_AT = 101; const T_CLOSE_CURLY_BRACES = 102; const T_CLOSE_PARENTHESIS = 103; const T_COMMA = 104; const T_EQUALS = 105; const T_FALSE = 106; const T_NAMESPACE_SEPARATOR = 107; const T_OPEN_CURLY_BRACES = 108; const T_OPEN_PARENTHESIS = 109; const T_TRUE = 110; const T_NULL = 111; /** * @inheritdoc */ protected function getCatchablePatterns() { return array( '[a-z_][a-z0-9_:]*', '(?:[0-9]+(?:[\.][0-9]+)*)(?:e[+-]?[0-9]+)?', '"(?:[^"]|"")*"', ); } /** * @inheritdoc */ protected function getNonCatchablePatterns() { return array('\s+', '\*+', '(.)'); } /** * @inheritdoc */ protected function getType(&$value) { $type = self::T_NONE; // Checking numeric value if (is_numeric($value)) { return (strpos($value, '.') !== false || stripos($value, 'e') !== false) ? self::T_FLOAT : self::T_INTEGER; } if ($value[0] === '"') { $value = str_replace('""', '"', substr($value, 1, strlen($value) - 2)); return self::T_STRING; } else { switch (strtolower($value)) { case '@': return self::T_AT; case ',': return self::T_COMMA; case '(': return self::T_OPEN_PARENTHESIS; case ')': return self::T_CLOSE_PARENTHESIS; case '{': return self::T_OPEN_CURLY_BRACES; case '}': return self::T_CLOSE_CURLY_BRACES; case '=': return self::T_EQUALS; case '\\': return self::T_NAMESPACE_SEPARATOR; case 'true': return self::T_TRUE; case 'false': return self::T_FALSE; case 'null': return self::T_NULL; default: if (ctype_alpha($value[0]) || $value[0] === '_') { return self::T_IDENTIFIER; } break; } } return $type; } }lib/Doctrine/Common/Annotations/DocParser.php000064400000045023144760120550015211 0ustar00. */ namespace Doctrine\Common\Annotations; use Closure; use ReflectionClass; /** * A parser for docblock annotations. * * It is strongly discouraged to change the default annotation parsing process. * * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author Johannes M. Schmitt */ final class DocParser { /** * An array of all valid tokens for a class name. * * @var array */ private static $classIdentifiers = array(DocLexer::T_IDENTIFIER, DocLexer::T_TRUE, DocLexer::T_FALSE, DocLexer::T_NULL); /** * The lexer. * * @var Doctrine\Common\Annotations\DocLexer */ private $lexer; /** * Flag to control if the current annotation is nested or not. * * @var boolean */ private $isNestedAnnotation = false; /** * Hashmap containing all use-statements that are to be used when parsing * the given doc block. * * @var array */ private $imports = array(); /** * This hashmap is used internally to cache results of class_exists() * look-ups. * * @var array */ private $classExists = array(); /** * * @var This hashmap is used internally to cache if a class is an annotation or not. * * @var array */ private $isAnnotation = array(); /** * Whether annotations that have not been imported should be ignored. * * @var boolean */ private $ignoreNotImportedAnnotations = false; /** * A list with annotations that are not causing exceptions when not resolved to an annotation class. * * The names must be the raw names as used in the class, not the fully qualified * class names. * * @var array */ private $ignoredAnnotationNames = array(); /** * @var array */ private $namespaceAliases = array(); /** * @var string */ private $context = ''; /** * @var Closure */ private $creationFn = null; /** * Constructs a new DocParser. */ public function __construct() { $this->lexer = new DocLexer; } /** * Sets the annotation names that are ignored during the parsing process. * * The names are supposed to be the raw names as used in the class, not the * fully qualified class names. * * @param array $names */ public function setIgnoredAnnotationNames(array $names) { $this->ignoredAnnotationNames = $names; } /** * @deprecated Will be removed in 3.0 * @param \Closure $func */ public function setAnnotationCreationFunction(\Closure $func) { $this->creationFn = $func; } public function setImports(array $imports) { $this->imports = $imports; } public function setIgnoreNotImportedAnnotations($bool) { $this->ignoreNotImportedAnnotations = (Boolean) $bool; } public function setAnnotationNamespaceAlias($namespace, $alias) { $this->namespaceAliases[$alias] = $namespace; } /** * Parses the given docblock string for annotations. * * @param string $input The docblock string to parse. * @param string $context The parsing context. * @return array Array of annotations. If no annotations are found, an empty array is returned. */ public function parse($input, $context = '') { if (false === $pos = strpos($input, '@')) { return array(); } // also parse whatever character is before the @ if ($pos > 0) { $pos -= 1; } $this->context = $context; $this->lexer->setInput(trim(substr($input, $pos), '* /')); $this->lexer->moveNext(); return $this->Annotations(); } /** * Attempts to match the given token with the current lookahead token. * If they match, updates the lookahead token; otherwise raises a syntax error. * * @param int Token type. * @return bool True if tokens match; false otherwise. */ private function match($token) { if ( ! $this->lexer->isNextToken($token) ) { $this->syntaxError($this->lexer->getLiteral($token)); } return $this->lexer->moveNext(); } /** * Attempts to match the current lookahead token with any of the given tokens. * * If any of them matches, this method updates the lookahead token; otherwise * a syntax error is raised. * * @param array $tokens * @return bool */ private function matchAny(array $tokens) { if ( ! $this->lexer->isNextTokenAny($tokens)) { $this->syntaxError(implode(' or ', array_map(array($this->lexer, 'getLiteral'), $tokens))); } return $this->lexer->moveNext(); } /** * Generates a new syntax error. * * @param string $expected Expected string. * @param array $token Optional token. * @throws SyntaxException */ private function syntaxError($expected, $token = null) { if ($token === null) { $token = $this->lexer->lookahead; } $message = "Expected {$expected}, got "; if ($this->lexer->lookahead === null) { $message .= 'end of string'; } else { $message .= "'{$token['value']}' at position {$token['position']}"; } if (strlen($this->context)) { $message .= ' in ' . $this->context; } $message .= '.'; throw AnnotationException::syntaxError($message); } /** * Attempt to check if a class exists or not. This never goes through the PHP autoloading mechanism * but uses the {@link AnnotationRegistry} to load classes. * * @param string $fqcn * @return boolean */ private function classExists($fqcn) { if (isset($this->classExists[$fqcn])) { return $this->classExists[$fqcn]; } // first check if the class already exists, maybe loaded through another AnnotationReader if (class_exists($fqcn, false)) { return $this->classExists[$fqcn] = true; } // final check, does this class exist? return $this->classExists[$fqcn] = AnnotationRegistry::loadAnnotationClass($fqcn); } /** * Annotations ::= Annotation {[ "*" ]* [Annotation]}* * * @return array */ private function Annotations() { $annotations = array(); while (null !== $this->lexer->lookahead) { if (DocLexer::T_AT !== $this->lexer->lookahead['type']) { $this->lexer->moveNext(); continue; } // make sure the @ is preceded by non-catchable pattern if (null !== $this->lexer->token && $this->lexer->lookahead['position'] === $this->lexer->token['position'] + strlen($this->lexer->token['value'])) { $this->lexer->moveNext(); continue; } // make sure the @ is followed by either a namespace separator, or // an identifier token if ((null === $peek = $this->lexer->glimpse()) || (DocLexer::T_NAMESPACE_SEPARATOR !== $peek['type'] && !in_array($peek['type'], self::$classIdentifiers, true)) || $peek['position'] !== $this->lexer->lookahead['position'] + 1) { $this->lexer->moveNext(); continue; } $this->isNestedAnnotation = false; if (false !== $annot = $this->Annotation()) { $annotations[] = $annot; } } return $annotations; } /** * Annotation ::= "@" AnnotationName ["(" [Values] ")"] * AnnotationName ::= QualifiedName | SimpleName * QualifiedName ::= NameSpacePart "\" {NameSpacePart "\"}* SimpleName * NameSpacePart ::= identifier | null | false | true * SimpleName ::= identifier | null | false | true * * @return mixed False if it is not a valid annotation. */ private function Annotation() { $this->match(DocLexer::T_AT); // check if we have an annotation if ($this->lexer->isNextTokenAny(self::$classIdentifiers)) { $this->lexer->moveNext(); $name = $this->lexer->token['value']; } else if ($this->lexer->isNextToken(DocLexer::T_NAMESPACE_SEPARATOR)) { $name = ''; } else { $this->syntaxError('namespace separator or identifier'); } while ($this->lexer->lookahead['position'] === $this->lexer->token['position'] + strlen($this->lexer->token['value']) && $this->lexer->isNextToken(DocLexer::T_NAMESPACE_SEPARATOR)) { $this->match(DocLexer::T_NAMESPACE_SEPARATOR); $this->matchAny(self::$classIdentifiers); $name .= '\\'.$this->lexer->token['value']; } if (strpos($name, ":") !== false) { list ($alias, $name) = explode(':', $name); // If the namespace alias doesnt exist, skip until next annotation if ( ! isset($this->namespaceAliases[$alias])) { $this->lexer->skipUntil(DocLexer::T_AT); return false; } $name = $this->namespaceAliases[$alias] . $name; } // only process names which are not fully qualified, yet // fully qualified names must start with a \ $originalName = $name; if ('\\' !== $name[0]) { $alias = (false === $pos = strpos($name, '\\'))? $name : substr($name, 0, $pos); if (isset($this->imports[$loweredAlias = strtolower($alias)])) { if (false !== $pos) { $name = $this->imports[$loweredAlias].substr($name, $pos); } else { $name = $this->imports[$loweredAlias]; } } elseif (isset($this->imports['__DEFAULT__']) && $this->classExists($this->imports['__DEFAULT__'].$name)) { $name = $this->imports['__DEFAULT__'].$name; } elseif (isset($this->imports['__NAMESPACE__']) && $this->classExists($this->imports['__NAMESPACE__'].'\\'.$name)) { $name = $this->imports['__NAMESPACE__'].'\\'.$name; } elseif (!$this->classExists($name)) { if ($this->ignoreNotImportedAnnotations || isset($this->ignoredAnnotationNames[$name])) { return false; } throw AnnotationException::semanticalError(sprintf('The annotation "@%s" in %s was never imported. Did you maybe forget to add a "use" statement for this annotation?', $name, $this->context)); } } if (!$this->classExists($name)) { throw AnnotationException::semanticalError(sprintf('The annotation "@%s" in %s does not exist, or could not be auto-loaded.', $name, $this->context)); } if (!$this->isAnnotation($name)) { return false; } // Verifies that the annotation class extends any class that contains "Annotation". // This is done to avoid coupling of Doctrine Annotations against other libraries. // at this point, $name contains the fully qualified class name of the // annotation, and it is also guaranteed that this class exists, and // that it is loaded // Next will be nested $this->isNestedAnnotation = true; $values = array(); if ($this->lexer->isNextToken(DocLexer::T_OPEN_PARENTHESIS)) { $this->match(DocLexer::T_OPEN_PARENTHESIS); if ( ! $this->lexer->isNextToken(DocLexer::T_CLOSE_PARENTHESIS)) { $values = $this->Values(); } $this->match(DocLexer::T_CLOSE_PARENTHESIS); } return $this->newAnnotation($name, $values); } /** * Verify that the found class is actually an annotation. * * This can be detected through two mechanisms: * 1. Class extends Doctrine\Common\Annotations\Annotation * 2. The class level docblock contains the string "@Annotation" * * @param string $name * @return bool */ private function isAnnotation($name) { if (!isset($this->isAnnotation[$name])) { if (is_subclass_of($name, 'Doctrine\Common\Annotations\Annotation')) { $this->isAnnotation[$name] = true; } else { $reflClass = new \ReflectionClass($name); $this->isAnnotation[$name] = strpos($reflClass->getDocComment(), "@Annotation") !== false; } } return $this->isAnnotation[$name]; } private function newAnnotation($name, $values) { if ($this->creationFn !== null) { $fn = $this->creationFn; return $fn($name, $values); } return new $name($values); } /** * Values ::= Array | Value {"," Value}* * * @return array */ private function Values() { $values = array(); // Handle the case of a single array as value, i.e. @Foo({....}) if ($this->lexer->isNextToken(DocLexer::T_OPEN_CURLY_BRACES)) { $values['value'] = $this->Value(); return $values; } $values[] = $this->Value(); while ($this->lexer->isNextToken(DocLexer::T_COMMA)) { $this->match(DocLexer::T_COMMA); $token = $this->lexer->lookahead; $value = $this->Value(); if ( ! is_object($value) && ! is_array($value)) { $this->syntaxError('Value', $token); } $values[] = $value; } foreach ($values as $k => $value) { if (is_object($value) && $value instanceof \stdClass) { $values[$value->name] = $value->value; } else if ( ! isset($values['value'])){ $values['value'] = $value; } else { if ( ! is_array($values['value'])) { $values['value'] = array($values['value']); } $values['value'][] = $value; } unset($values[$k]); } return $values; } /** * Value ::= PlainValue | FieldAssignment * * @return mixed */ private function Value() { $peek = $this->lexer->glimpse(); if (DocLexer::T_EQUALS === $peek['type']) { return $this->FieldAssignment(); } return $this->PlainValue(); } /** * PlainValue ::= integer | string | float | boolean | Array | Annotation * * @return mixed */ private function PlainValue() { if ($this->lexer->isNextToken(DocLexer::T_OPEN_CURLY_BRACES)) { return $this->Arrayx(); } if ($this->lexer->isNextToken(DocLexer::T_AT)) { return $this->Annotation(); } switch ($this->lexer->lookahead['type']) { case DocLexer::T_STRING: $this->match(DocLexer::T_STRING); return $this->lexer->token['value']; case DocLexer::T_INTEGER: $this->match(DocLexer::T_INTEGER); return (int)$this->lexer->token['value']; case DocLexer::T_FLOAT: $this->match(DocLexer::T_FLOAT); return (float)$this->lexer->token['value']; case DocLexer::T_TRUE: $this->match(DocLexer::T_TRUE); return true; case DocLexer::T_FALSE: $this->match(DocLexer::T_FALSE); return false; case DocLexer::T_NULL: $this->match(DocLexer::T_NULL); return null; default: $this->syntaxError('PlainValue'); } } /** * FieldAssignment ::= FieldName "=" PlainValue * FieldName ::= identifier * * @return array */ private function FieldAssignment() { $this->match(DocLexer::T_IDENTIFIER); $fieldName = $this->lexer->token['value']; $this->match(DocLexer::T_EQUALS); $item = new \stdClass(); $item->name = $fieldName; $item->value = $this->PlainValue(); return $item; } /** * Array ::= "{" ArrayEntry {"," ArrayEntry}* "}" * * @return array */ private function Arrayx() { $array = $values = array(); $this->match(DocLexer::T_OPEN_CURLY_BRACES); $values[] = $this->ArrayEntry(); while ($this->lexer->isNextToken(DocLexer::T_COMMA)) { $this->match(DocLexer::T_COMMA); $values[] = $this->ArrayEntry(); } $this->match(DocLexer::T_CLOSE_CURLY_BRACES); foreach ($values as $value) { list ($key, $val) = $value; if ($key !== null) { $array[$key] = $val; } else { $array[] = $val; } } return $array; } /** * ArrayEntry ::= Value | KeyValuePair * KeyValuePair ::= Key "=" PlainValue * Key ::= string | integer * * @return array */ private function ArrayEntry() { $peek = $this->lexer->glimpse(); if (DocLexer::T_EQUALS === $peek['type']) { $this->match( $this->lexer->isNextToken(DocLexer::T_INTEGER) ? DocLexer::T_INTEGER : DocLexer::T_STRING ); $key = $this->lexer->token['value']; $this->match(DocLexer::T_EQUALS); return array($key, $this->PlainValue()); } return array(null, $this->Value()); } }lib/Doctrine/Common/Annotations/FileCacheReader.php000064400000015541144760120550016257 0ustar00. */ namespace Doctrine\Common\Annotations; /** * File cache reader for annotations. * * @author Johannes M. Schmitt * @author Benjamin Eberlei */ class FileCacheReader implements Reader { /** * @var Reader */ private $reader; private $dir; private $debug; private $loadedAnnotations = array(); public function __construct(Reader $reader, $cacheDir, $debug = false) { $this->reader = $reader; if (!is_dir($cacheDir)) { throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist.', $cacheDir)); } if (!is_writable($cacheDir)) { throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable.', $cacheDir)); } $this->dir = rtrim($cacheDir, '\\/'); $this->debug = $debug; } public function getClassAnnotations(\ReflectionClass $class) { $key = $class->getName(); if (isset($this->loadedAnnotations[$key])) { return $this->loadedAnnotations[$key]; } $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; if (!file_exists($path)) { $annot = $this->reader->getClassAnnotations($class); $this->saveCacheFile($path, $annot); return $this->loadedAnnotations[$key] = $annot; } if ($this->debug && (false !== $filename = $class->getFilename()) && filemtime($path) < filemtime($filename)) { @unlink($path); $annot = $this->reader->getClassAnnotations($class); $this->saveCacheFile($path, $annot); return $this->loadedAnnotations[$key] = $annot; } return $this->loadedAnnotations[$key] = include $path; } public function getPropertyAnnotations(\ReflectionProperty $property) { $class = $property->getDeclaringClass(); $key = $class->getName().'$'.$property->getName(); if (isset($this->loadedAnnotations[$key])) { return $this->loadedAnnotations[$key]; } $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; if (!file_exists($path)) { $annot = $this->reader->getPropertyAnnotations($property); $this->saveCacheFile($path, $annot); return $this->loadedAnnotations[$key] = $annot; } if ($this->debug && (false !== $filename = $class->getFilename()) && filemtime($path) < filemtime($filename)) { unlink($path); $annot = $this->reader->getPropertyAnnotations($property); $this->saveCacheFile($path, $annot); return $this->loadedAnnotations[$key] = $annot; } return $this->loadedAnnotations[$key] = include $path; } public function getMethodAnnotations(\ReflectionMethod $method) { $class = $method->getDeclaringClass(); $key = $class->getName().'#'.$method->getName(); if (isset($this->loadedAnnotations[$key])) { return $this->loadedAnnotations[$key]; } $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; if (!file_exists($path)) { $annot = $this->reader->getMethodAnnotations($method); $this->saveCacheFile($path, $annot); return $this->loadedAnnotations[$key] = $annot; } if ($this->debug && (false !== $filename = $class->getFilename()) && filemtime($path) < filemtime($filename)) { unlink($path); $annot = $this->reader->getMethodAnnotations($method); $this->saveCacheFile($path, $annot); return $this->loadedAnnotations[$key] = $annot; } return $this->loadedAnnotations[$key] = include $path; } private function saveCacheFile($path, $data) { file_put_contents($path, 'getClassAnnotations($class); foreach ($annotations as $annotation) { if ($annotation instanceof $annotationName) { return $annotation; } } return null; } /** * Gets a method annotation. * * @param ReflectionMethod $method * @param string $annotationName The name of the annotation. * @return The Annotation or NULL, if the requested annotation does not exist. */ public function getMethodAnnotation(\ReflectionMethod $method, $annotationName) { $annotations = $this->getMethodAnnotations($method); foreach ($annotations as $annotation) { if ($annotation instanceof $annotationName) { return $annotation; } } return null; } /** * Gets a property annotation. * * @param ReflectionProperty $property * @param string $annotationName The name of the annotation. * @return The Annotation or NULL, if the requested annotation does not exist. */ public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) { $annotations = $this->getPropertyAnnotations($property); foreach ($annotations as $annotation) { if ($annotation instanceof $annotationName) { return $annotation; } } return null; } public function clearLoadedAnnotations() { $this->loadedAnnotations = array(); } }lib/Doctrine/Common/Annotations/IndexedReader.php000064400000005661144760120550016036 0ustar00. */ namespace Doctrine\Common\Annotations; use Doctrine\Common\Annotations\Reader; /** * Allows the reader to be used in-place of Doctrine's reader. * * @author Johannes M. Schmitt */ class IndexedReader implements Reader { private $delegate; public function __construct(Reader $reader) { $this->delegate = $reader; } public function getClassAnnotations(\ReflectionClass $class) { $annotations = array(); foreach ($this->delegate->getClassAnnotations($class) as $annot) { $annotations[get_class($annot)] = $annot; } return $annotations; } public function getClassAnnotation(\ReflectionClass $class, $annotation) { return $this->delegate->getClassAnnotation($class, $annotation); } public function getMethodAnnotations(\ReflectionMethod $method) { $annotations = array(); foreach ($this->delegate->getMethodAnnotations($method) as $annot) { $annotations[get_class($annot)] = $annot; } return $annotations; } public function getMethodAnnotation(\ReflectionMethod $method, $annotation) { return $this->delegate->getMethodAnnotation($method, $annotation); } public function getPropertyAnnotations(\ReflectionProperty $property) { $annotations = array(); foreach ($this->delegate->getPropertyAnnotations($property) as $annot) { $annotations[get_class($annot)] = $annot; } return $annotations; } public function getPropertyAnnotation(\ReflectionProperty $property, $annotation) { return $this->delegate->getPropertyAnnotation($property, $annotation); } /** * Proxy all methods to the delegate. * * @param type $method * @param type $args * @return type */ public function __call($method, $args) { return call_user_func_array(array($this->delegate, $method), $args); } }lib/Doctrine/Common/Annotations/PhpParser.php000064400000011524144760120550015232 0ustar00. */ namespace Doctrine\Common\Annotations; /** * Parses a file for namespaces/use/class declarations. * * @author Fabien Potencier */ final class PhpParser { private $tokens; /** * Parses a class. * * @param \ReflectionClass $class */ public function parseClass(\ReflectionClass $class) { if (false === $filename = $class->getFilename()) { return array(); } $src = file_get_contents($filename); $name = $class->getName(); // This is a short-cut for code that follows some conventions: // - namespaced // - one class per file if (preg_match_all('#\bnamespace\s+'.str_replace('\\', '\\\\', $class->getNamespaceName()).'\s*;.*?\b(?:class|interface)\s+'.$class->getShortName().'\b#s', $src, $matches)) { foreach ($matches[0] as $match) { $classes = $this->parse('parse($src, $name); return $classes[$name]; } private function parse($src, $interestedClass = null) { $this->tokens = token_get_all($src); $classes = $uses = array(); $namespace = ''; while ($token = $this->next()) { if (T_NAMESPACE === $token[0]) { $namespace = $this->parseNamespace(); $uses = array(); } elseif (T_CLASS === $token[0] || T_INTERFACE === $token[0]) { if ('' !== $namespace) { $class = $namespace.'\\'.$this->nextValue(); } else { $class = $this->nextValue(); } $classes[$class] = $uses; if (null !== $interestedClass && $interestedClass === $class) { return $classes; } } elseif (T_USE === $token[0]) { foreach ($this->parseUseStatement() as $useStatement) { list($alias, $class) = $useStatement; $uses[strtolower($alias)] = $class; } } } return $classes; } private function parseNamespace() { $namespace = ''; while ($token = $this->next()) { if (T_NS_SEPARATOR === $token[0] || T_STRING === $token[0]) { $namespace .= $token[1]; } elseif (is_string($token) && in_array($token, array(';', '{'))) { return $namespace; } } } private function parseUseStatement() { $statements = $class = array(); $alias = ''; while ($token = $this->next()) { if (T_NS_SEPARATOR === $token[0] || T_STRING === $token[0]) { $class[] = $token[1]; } else if (T_AS === $token[0]) { $alias = $this->nextValue(); } else if (is_string($token)) { if (',' === $token || ';' === $token) { $statements[] = array( $alias ? $alias : $class[count($class) - 1], implode('', $class) ); } if (';' === $token) { return $statements; } if (',' === $token) { $class = array(); $alias = ''; continue; } } } } private function next() { while ($token = array_shift($this->tokens)) { if (in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT))) { continue; } return $token; } } private function nextValue() { $token = $this->next(); return is_array($token) ? $token[1] : $token; } } lib/Doctrine/Common/Annotations/Reader.php000064400000003042144760120550014524 0ustar00. */ namespace Doctrine\Common\Annotations; /** * Interface for annotation readers. * * @author Johannes M. Schmitt */ interface Reader { function getClassAnnotations(\ReflectionClass $class); function getClassAnnotation(\ReflectionClass $class, $annotationName); function getMethodAnnotations(\ReflectionMethod $method); function getMethodAnnotation(\ReflectionMethod $method, $annotationName); function getPropertyAnnotations(\ReflectionProperty $property); function getPropertyAnnotation(\ReflectionProperty $property, $annotationName); }lib/Doctrine/Common/Cache/AbstractCache.php000064400000013510144760120550014520 0ustar00. */ namespace Doctrine\Common\Cache; /** * Base class for cache driver implementations. * * @since 2.0 * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ abstract class AbstractCache implements Cache { /** @var string The namespace to prefix all cache ids with */ private $_namespace = ''; /** * Set the namespace to prefix all cache ids with. * * @param string $namespace * @return void */ public function setNamespace($namespace) { $this->_namespace = (string) $namespace; } /** * {@inheritdoc} */ public function fetch($id) { return $this->_doFetch($this->_getNamespacedId($id)); } /** * {@inheritdoc} */ public function contains($id) { return $this->_doContains($this->_getNamespacedId($id)); } /** * {@inheritdoc} */ public function save($id, $data, $lifeTime = 0) { return $this->_doSave($this->_getNamespacedId($id), $data, $lifeTime); } /** * {@inheritdoc} */ public function delete($id) { $id = $this->_getNamespacedId($id); if (strpos($id, '*') !== false) { return $this->deleteByRegex('/' . str_replace('*', '.*', $id) . '/'); } return $this->_doDelete($id); } /** * Delete all cache entries. * * @return array $deleted Array of the deleted cache ids */ public function deleteAll() { $ids = $this->getIds(); foreach ($ids as $id) { $this->_doDelete($id); } return $ids; } /** * Delete cache entries where the id matches a PHP regular expressions * * @param string $regex * @return array $deleted Array of the deleted cache ids */ public function deleteByRegex($regex) { $ids = $this->getIds(); $deleted = array(); foreach ($ids as $id) { if (preg_match($regex, $id)) { $this->_doDelete($id); $deleted[] = $id; } } return $deleted; } /** * Delete cache entries where the id has the passed prefix * * @param string $prefix * @return array $deleted Array of the deleted cache ids */ public function deleteByPrefix($prefix) { $prefix = $this->_getNamespacedId($prefix); $ids = $this->getIds(); $deleted = array(); foreach ($ids as $id) { if (strpos($id, $prefix) === 0) { $this->_doDelete($id); $deleted[] = $id; } } return $deleted; } /** * Delete cache entries where the id has the passed suffix * * @param string $suffix * @return array $deleted Array of the deleted cache ids */ public function deleteBySuffix($suffix) { $ids = $this->getIds(); $deleted = array(); foreach ($ids as $id) { if (substr($id, -1 * strlen($suffix)) === $suffix) { $this->_doDelete($id); $deleted[] = $id; } } return $deleted; } /** * Prefix the passed id with the configured namespace value * * @param string $id The id to namespace * @return string $id The namespaced id */ private function _getNamespacedId($id) { return $this->_namespace . $id; } /** * Fetches an entry from the cache. * * @param string $id cache id The id of the cache entry to fetch. * @return string The cached data or FALSE, if no cache entry exists for the given id. */ abstract protected function _doFetch($id); /** * Test if an entry exists in the cache. * * @param string $id cache id The cache id of the entry to check for. * @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise. */ abstract protected function _doContains($id); /** * Puts data into the cache. * * @param string $id The cache id. * @param string $data The cache entry/data. * @param int $lifeTime The lifetime. If != false, sets a specific lifetime for this cache entry (null => infinite lifeTime). * @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise. */ abstract protected function _doSave($id, $data, $lifeTime = false); /** * Deletes a cache entry. * * @param string $id cache id * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise. */ abstract protected function _doDelete($id); /** * Get an array of all the cache ids stored * * @return array $ids */ abstract public function getIds(); }lib/Doctrine/Common/Cache/ApcCache.php000064400000004501144760120550013460 0ustar00. */ namespace Doctrine\Common\Cache; /** * APC cache driver. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision$ * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author David Abdemoulaie * @todo Rename: APCCache */ class ApcCache extends AbstractCache { /** * {@inheritdoc} */ public function getIds() { $ci = apc_cache_info('user'); $keys = array(); foreach ($ci['cache_list'] as $entry) { $keys[] = $entry['info']; } return $keys; } /** * {@inheritdoc} */ protected function _doFetch($id) { return apc_fetch($id); } /** * {@inheritdoc} */ protected function _doContains($id) { $found = false; apc_fetch($id, $found); return $found; } /** * {@inheritdoc} */ protected function _doSave($id, $data, $lifeTime = 0) { return (bool) apc_store($id, $data, (int) $lifeTime); } /** * {@inheritdoc} */ protected function _doDelete($id) { return apc_delete($id); } }lib/Doctrine/Common/Cache/ArrayCache.php000064400000004447144760120550014044 0ustar00. */ namespace Doctrine\Common\Cache; /** * Array cache driver. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision: 3938 $ * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author David Abdemoulaie */ class ArrayCache extends AbstractCache { /** * @var array $data */ private $data = array(); /** * {@inheritdoc} */ public function getIds() { return array_keys($this->data); } /** * {@inheritdoc} */ protected function _doFetch($id) { if (isset($this->data[$id])) { return $this->data[$id]; } return false; } /** * {@inheritdoc} */ protected function _doContains($id) { return isset($this->data[$id]); } /** * {@inheritdoc} */ protected function _doSave($id, $data, $lifeTime = 0) { $this->data[$id] = $data; return true; } /** * {@inheritdoc} */ protected function _doDelete($id) { unset($this->data[$id]); return true; } }lib/Doctrine/Common/Cache/Cache.php000064400000005023144760120550013034 0ustar00. */ namespace Doctrine\Common\Cache; /** * Interface for cache drivers. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision: 3938 $ * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ interface Cache { /** * Fetches an entry from the cache. * * @param string $id cache id The id of the cache entry to fetch. * @return string The cached data or FALSE, if no cache entry exists for the given id. */ function fetch($id); /** * Test if an entry exists in the cache. * * @param string $id cache id The cache id of the entry to check for. * @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise. */ function contains($id); /** * Puts data into the cache. * * @param string $id The cache id. * @param string $data The cache entry/data. * @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this cache entry (0 => infinite lifeTime). * @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise. */ function save($id, $data, $lifeTime = 0); /** * Deletes a cache entry. * * @param string $id cache id * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise. */ function delete($id); }lib/Doctrine/Common/Cache/MemcacheCache.php000064400000006373144760120550014470 0ustar00. */ namespace Doctrine\Common\Cache; use \Memcache; /** * Memcache cache driver. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision: 3938 $ * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author David Abdemoulaie */ class MemcacheCache extends AbstractCache { /** * @var Memcache */ private $_memcache; /** * Sets the memcache instance to use. * * @param Memcache $memcache */ public function setMemcache(Memcache $memcache) { $this->_memcache = $memcache; } /** * Gets the memcache instance used by the cache. * * @return Memcache */ public function getMemcache() { return $this->_memcache; } /** * {@inheritdoc} */ public function getIds() { $keys = array(); $allSlabs = $this->_memcache->getExtendedStats('slabs'); foreach ($allSlabs as $server => $slabs) { if (is_array($slabs)) { foreach (array_keys($slabs) as $slabId) { $dump = $this->_memcache->getExtendedStats('cachedump', (int) $slabId); if ($dump) { foreach ($dump as $entries) { if ($entries) { $keys = array_merge($keys, array_keys($entries)); } } } } } } return $keys; } /** * {@inheritdoc} */ protected function _doFetch($id) { return $this->_memcache->get($id); } /** * {@inheritdoc} */ protected function _doContains($id) { return (bool) $this->_memcache->get($id); } /** * {@inheritdoc} */ protected function _doSave($id, $data, $lifeTime = 0) { return $this->_memcache->set($id, $data, 0, (int) $lifeTime); } /** * {@inheritdoc} */ protected function _doDelete($id) { return $this->_memcache->delete($id); } }lib/Doctrine/Common/Cache/XcacheCache.php000064400000005747144760120550014165 0ustar00. */ namespace Doctrine\Common\Cache; /** * Xcache cache driver. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision: 3938 $ * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author David Abdemoulaie */ class XcacheCache extends AbstractCache { /** * {@inheritdoc} */ public function getIds() { $this->_checkAuth(); $keys = array(); for ($i = 0, $count = xcache_count(XC_TYPE_VAR); $i < $count; $i++) { $entries = xcache_list(XC_TYPE_VAR, $i); if (is_array($entries['cache_list'])) { foreach ($entries['cache_list'] as $entry) { $keys[] = $entry['name']; } } } return $keys; } /** * {@inheritdoc} */ protected function _doFetch($id) { return $this->_doContains($id) ? unserialize(xcache_get($id)) : false; } /** * {@inheritdoc} */ protected function _doContains($id) { return xcache_isset($id); } /** * {@inheritdoc} */ protected function _doSave($id, $data, $lifeTime = 0) { return xcache_set($id, serialize($data), (int) $lifeTime); } /** * {@inheritdoc} */ protected function _doDelete($id) { return xcache_unset($id); } /** * Checks that xcache.admin.enable_auth is Off * * @throws \BadMethodCallException When xcache.admin.enable_auth is On * @return void */ protected function _checkAuth() { if (ini_get('xcache.admin.enable_auth')) { throw new \BadMethodCallException('To use all features of \Doctrine\Common\Cache\XcacheCache, you must set "xcache.admin.enable_auth" to "Off" in your php.ini.'); } } }lib/Doctrine/Common/Cache/ZendDataCache.php000064400000004167144760120550014457 0ustar00. */ namespace Doctrine\Common\Cache; /** * Zend Data Cache cache driver. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @author Ralph Schindler */ class ZendDataCache extends AbstractCache { public function __construct() { $this->setNamespace('doctrine::'); // zend data cache format for namespaces ends in :: } /** * {@inheritdoc} */ public function getIds() { throw new \BadMethodCallException("getIds() is not supported by ZendDataCache"); } /** * {@inheritdoc} */ protected function _doFetch($id) { return zend_shm_cache_fetch($id); } /** * {@inheritdoc} */ protected function _doContains($id) { return (zend_shm_cache_fetch($id) !== FALSE); } /** * {@inheritdoc} */ protected function _doSave($id, $data, $lifeTime = 0) { return zend_shm_cache_store($id, $data, $lifeTime); } /** * {@inheritdoc} */ protected function _doDelete($id) { return zend_shm_cache_delete($id); } }lib/Doctrine/Common/ClassLoader.php000064400000022016144760120550013223 0ustar00. */ namespace Doctrine\Common; /** * A ClassLoader is an autoloader for class files that can be * installed on the SPL autoload stack. It is a class loader that either loads only classes * of a specific namespace or all namespaces and it is suitable for working together * with other autoloaders in the SPL autoload stack. * * If no include path is configured through the constructor or {@link setIncludePath}, a ClassLoader * relies on the PHP include_path. * * @author Roman Borschel * @since 2.0 */ class ClassLoader { private $fileExtension = '.php'; private $namespace; private $includePath; private $namespaceSeparator = '\\'; /** * Creates a new ClassLoader that loads classes of the * specified namespace from the specified include path. * * If no include path is given, the ClassLoader relies on the PHP include_path. * If neither a namespace nor an include path is given, the ClassLoader will * be responsible for loading all classes, thereby relying on the PHP include_path. * * @param string $ns The namespace of the classes to load. * @param string $includePath The base include path to use. */ public function __construct($ns = null, $includePath = null) { $this->namespace = $ns; $this->includePath = $includePath; } /** * Sets the namespace separator used by classes in the namespace of this ClassLoader. * * @param string $sep The separator to use. */ public function setNamespaceSeparator($sep) { $this->namespaceSeparator = $sep; } /** * Gets the namespace separator used by classes in the namespace of this ClassLoader. * * @return string */ public function getNamespaceSeparator() { return $this->namespaceSeparator; } /** * Sets the base include path for all class files in the namespace of this ClassLoader. * * @param string $includePath */ public function setIncludePath($includePath) { $this->includePath = $includePath; } /** * Gets the base include path for all class files in the namespace of this ClassLoader. * * @return string */ public function getIncludePath() { return $this->includePath; } /** * Sets the file extension of class files in the namespace of this ClassLoader. * * @param string $fileExtension */ public function setFileExtension($fileExtension) { $this->fileExtension = $fileExtension; } /** * Gets the file extension of class files in the namespace of this ClassLoader. * * @return string */ public function getFileExtension() { return $this->fileExtension; } /** * Registers this ClassLoader on the SPL autoload stack. */ public function register() { spl_autoload_register(array($this, 'loadClass')); } /** * Removes this ClassLoader from the SPL autoload stack. */ public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); } /** * Loads the given class or interface. * * @param string $classname The name of the class to load. * @return boolean TRUE if the class has been successfully loaded, FALSE otherwise. */ public function loadClass($className) { if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) { return false; } require ($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '') . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->fileExtension; return true; } /** * Asks this ClassLoader whether it can potentially load the class (file) with * the given name. * * @param string $className The fully-qualified name of the class. * @return boolean TRUE if this ClassLoader can load the class, FALSE otherwise. */ public function canLoadClass($className) { if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) { return false; } $file = str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->fileExtension; if ($this->includePath !== null) { return file_exists($this->includePath . DIRECTORY_SEPARATOR . $file); } return self::fileExistsInIncludePath($file); } /** * Checks whether a class with a given name exists. A class "exists" if it is either * already defined in the current request or if there is an autoloader on the SPL * autoload stack that is a) responsible for the class in question and b) is able to * load a class file in which the class definition resides. * * If the class is not already defined, each autoloader in the SPL autoload stack * is asked whether it is able to tell if the class exists. If the autoloader is * a ClassLoader, {@link canLoadClass} is used, otherwise the autoload * function of the autoloader is invoked and expected to return a value that * evaluates to TRUE if the class (file) exists. As soon as one autoloader reports * that the class exists, TRUE is returned. * * Note that, depending on what kinds of autoloaders are installed on the SPL * autoload stack, the class (file) might already be loaded as a result of checking * for its existence. This is not the case with a ClassLoader, who separates * these responsibilities. * * @param string $className The fully-qualified name of the class. * @return boolean TRUE if the class exists as per the definition given above, FALSE otherwise. */ public static function classExists($className) { if (class_exists($className, false)) { return true; } foreach (spl_autoload_functions() as $loader) { if (is_array($loader)) { // array(???, ???) if (is_object($loader[0])) { if ($loader[0] instanceof ClassLoader) { // array($obj, 'methodName') if ($loader[0]->canLoadClass($className)) { return true; } } else if ($loader[0]->{$loader[1]}($className)) { return true; } } else if ($loader[0]::$loader[1]($className)) { // array('ClassName', 'methodName') return true; } } else if ($loader instanceof \Closure) { // function($className) {..} if ($loader($className)) { return true; } } else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass" return true; } } return false; } /** * Gets the ClassLoader from the SPL autoload stack that is responsible * for (and is able to load) the class with the given name. * * @param string $className The name of the class. * @return The ClassLoader for the class or NULL if no such ClassLoader exists. */ public static function getClassLoader($className) { foreach (spl_autoload_functions() as $loader) { if (is_array($loader) && $loader[0] instanceof ClassLoader && $loader[0]->canLoadClass($className) ) { return $loader[0]; } } return null; } /** * @param string $file The file relative path. * @return boolean Whether file exists in include_path. */ public static function fileExistsInIncludePath($file) { foreach (explode(PATH_SEPARATOR, get_include_path()) as $dir) { if (file_exists($dir . DIRECTORY_SEPARATOR . $file)) { return true; } } return false; } } lib/Doctrine/Common/Collections/ArrayCollection.php000064400000027250144760120550016404 0ustar00. */ namespace Doctrine\Common\Collections; use Closure, ArrayIterator; /** * An ArrayCollection is a Collection implementation that wraps a regular PHP array. * * @since 2.0 * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ class ArrayCollection implements Collection { /** * An array containing the entries of this collection. * * @var array */ private $_elements; /** * Initializes a new ArrayCollection. * * @param array $elements */ public function __construct(array $elements = array()) { $this->_elements = $elements; } /** * Gets the PHP array representation of this collection. * * @return array The PHP array representation of this collection. */ public function toArray() { return $this->_elements; } /** * Sets the internal iterator to the first element in the collection and * returns this element. * * @return mixed */ public function first() { return reset($this->_elements); } /** * Sets the internal iterator to the last element in the collection and * returns this element. * * @return mixed */ public function last() { return end($this->_elements); } /** * Gets the current key/index at the current internal iterator position. * * @return mixed */ public function key() { return key($this->_elements); } /** * Moves the internal iterator position to the next element. * * @return mixed */ public function next() { return next($this->_elements); } /** * Gets the element of the collection at the current internal iterator position. * * @return mixed */ public function current() { return current($this->_elements); } /** * Removes an element with a specific key/index from the collection. * * @param mixed $key * @return mixed The removed element or NULL, if no element exists for the given key. */ public function remove($key) { if (isset($this->_elements[$key])) { $removed = $this->_elements[$key]; unset($this->_elements[$key]); return $removed; } return null; } /** * Removes the specified element from the collection, if it is found. * * @param mixed $element The element to remove. * @return boolean TRUE if this collection contained the specified element, FALSE otherwise. */ public function removeElement($element) { $key = array_search($element, $this->_elements, true); if ($key !== false) { unset($this->_elements[$key]); return true; } return false; } /** * ArrayAccess implementation of offsetExists() * * @see containsKey() */ public function offsetExists($offset) { return $this->containsKey($offset); } /** * ArrayAccess implementation of offsetGet() * * @see get() */ public function offsetGet($offset) { return $this->get($offset); } /** * ArrayAccess implementation of offsetGet() * * @see add() * @see set() */ public function offsetSet($offset, $value) { if ( ! isset($offset)) { return $this->add($value); } return $this->set($offset, $value); } /** * ArrayAccess implementation of offsetUnset() * * @see remove() */ public function offsetUnset($offset) { return $this->remove($offset); } /** * Checks whether the collection contains a specific key/index. * * @param mixed $key The key to check for. * @return boolean TRUE if the given key/index exists, FALSE otherwise. */ public function containsKey($key) { return isset($this->_elements[$key]); } /** * Checks whether the given element is contained in the collection. * Only element values are compared, not keys. The comparison of two elements * is strict, that means not only the value but also the type must match. * For objects this means reference equality. * * @param mixed $element * @return boolean TRUE if the given element is contained in the collection, * FALSE otherwise. */ public function contains($element) { return in_array($element, $this->_elements, true); } /** * Tests for the existance of an element that satisfies the given predicate. * * @param Closure $p The predicate. * @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise. */ public function exists(Closure $p) { foreach ($this->_elements as $key => $element) { if ($p($key, $element)) { return true; } } return false; } /** * Searches for a given element and, if found, returns the corresponding key/index * of that element. The comparison of two elements is strict, that means not * only the value but also the type must match. * For objects this means reference equality. * * @param mixed $element The element to search for. * @return mixed The key/index of the element or FALSE if the element was not found. */ public function indexOf($element) { return array_search($element, $this->_elements, true); } /** * Gets the element with the given key/index. * * @param mixed $key The key. * @return mixed The element or NULL, if no element exists for the given key. */ public function get($key) { if (isset($this->_elements[$key])) { return $this->_elements[$key]; } return null; } /** * Gets all keys/indexes of the collection elements. * * @return array */ public function getKeys() { return array_keys($this->_elements); } /** * Gets all elements. * * @return array */ public function getValues() { return array_values($this->_elements); } /** * Returns the number of elements in the collection. * * Implementation of the Countable interface. * * @return integer The number of elements in the collection. */ public function count() { return count($this->_elements); } /** * Adds/sets an element in the collection at the index / with the specified key. * * When the collection is a Map this is like put(key,value)/add(key,value). * When the collection is a List this is like add(position,value). * * @param mixed $key * @param mixed $value */ public function set($key, $value) { $this->_elements[$key] = $value; } /** * Adds an element to the collection. * * @param mixed $value * @return boolean Always TRUE. */ public function add($value) { $this->_elements[] = $value; return true; } /** * Checks whether the collection is empty. * * Note: This is preferrable over count() == 0. * * @return boolean TRUE if the collection is empty, FALSE otherwise. */ public function isEmpty() { return ! $this->_elements; } /** * Gets an iterator for iterating over the elements in the collection. * * @return ArrayIterator */ public function getIterator() { return new ArrayIterator($this->_elements); } /** * Applies the given function to each element in the collection and returns * a new collection with the elements returned by the function. * * @param Closure $func * @return Collection */ public function map(Closure $func) { return new static(array_map($func, $this->_elements)); } /** * Returns all the elements of this collection that satisfy the predicate p. * The order of the elements is preserved. * * @param Closure $p The predicate used for filtering. * @return Collection A collection with the results of the filter operation. */ public function filter(Closure $p) { return new static(array_filter($this->_elements, $p)); } /** * Applies the given predicate p to all elements of this collection, * returning true, if the predicate yields true for all elements. * * @param Closure $p The predicate. * @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise. */ public function forAll(Closure $p) { foreach ($this->_elements as $key => $element) { if ( ! $p($key, $element)) { return false; } } return true; } /** * Partitions this collection in two collections according to a predicate. * Keys are preserved in the resulting collections. * * @param Closure $p The predicate on which to partition. * @return array An array with two elements. The first element contains the collection * of elements where the predicate returned TRUE, the second element * contains the collection of elements where the predicate returned FALSE. */ public function partition(Closure $p) { $coll1 = $coll2 = array(); foreach ($this->_elements as $key => $element) { if ($p($key, $element)) { $coll1[$key] = $element; } else { $coll2[$key] = $element; } } return array(new static($coll1), new static($coll2)); } /** * Returns a string representation of this object. * * @return string */ public function __toString() { return __CLASS__ . '@' . spl_object_hash($this); } /** * Clears the collection. */ public function clear() { $this->_elements = array(); } /** * Extract a slice of $length elements starting at position $offset from the Collection. * * If $length is null it returns all elements from $offset to the end of the Collection. * Keys have to be preserved by this method. Calling this method will only return the * selected slice and NOT change the elements contained in the collection slice is called on. * * @param int $offset * @param int $length * @return array */ public function slice($offset, $length = null) { return array_slice($this->_elements, $offset, $length, true); } } lib/Doctrine/Common/Collections/Collection.php000064400000020132144760120550015375 0ustar00. */ namespace Doctrine\Common\Collections; use Closure, Countable, IteratorAggregate, ArrayAccess; /** * The missing (SPL) Collection/Array/OrderedMap interface. * * A Collection resembles the nature of a regular PHP array. That is, * it is essentially an ordered map that can also be used * like a list. * * A Collection has an internal iterator just like a PHP array. In addition, * a Collection can be iterated with external iterators, which is preferrable. * To use an external iterator simply use the foreach language construct to * iterate over the collection (which calls {@link getIterator()} internally) or * explicitly retrieve an iterator though {@link getIterator()} which can then be * used to iterate over the collection. * You can not rely on the internal iterator of the collection being at a certain * position unless you explicitly positioned it before. Prefer iteration with * external iterators. * * @since 2.0 * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ interface Collection extends Countable, IteratorAggregate, ArrayAccess { /** * Adds an element at the end of the collection. * * @param mixed $element The element to add. * @return boolean Always TRUE. */ function add($element); /** * Clears the collection, removing all elements. */ function clear(); /** * Checks whether an element is contained in the collection. * This is an O(n) operation, where n is the size of the collection. * * @param mixed $element The element to search for. * @return boolean TRUE if the collection contains the element, FALSE otherwise. */ function contains($element); /** * Checks whether the collection is empty (contains no elements). * * @return boolean TRUE if the collection is empty, FALSE otherwise. */ function isEmpty(); /** * Removes the element at the specified index from the collection. * * @param string|integer $key The kex/index of the element to remove. * @return mixed The removed element or NULL, if the collection did not contain the element. */ function remove($key); /** * Removes the specified element from the collection, if it is found. * * @param mixed $element The element to remove. * @return boolean TRUE if this collection contained the specified element, FALSE otherwise. */ function removeElement($element); /** * Checks whether the collection contains an element with the specified key/index. * * @param string|integer $key The key/index to check for. * @return boolean TRUE if the collection contains an element with the specified key/index, * FALSE otherwise. */ function containsKey($key); /** * Gets the element at the specified key/index. * * @param string|integer $key The key/index of the element to retrieve. * @return mixed */ function get($key); /** * Gets all keys/indices of the collection. * * @return array The keys/indices of the collection, in the order of the corresponding * elements in the collection. */ function getKeys(); /** * Gets all values of the collection. * * @return array The values of all elements in the collection, in the order they * appear in the collection. */ function getValues(); /** * Sets an element in the collection at the specified key/index. * * @param string|integer $key The key/index of the element to set. * @param mixed $value The element to set. */ function set($key, $value); /** * Gets a native PHP array representation of the collection. * * @return array */ function toArray(); /** * Sets the internal iterator to the first element in the collection and * returns this element. * * @return mixed */ function first(); /** * Sets the internal iterator to the last element in the collection and * returns this element. * * @return mixed */ function last(); /** * Gets the key/index of the element at the current iterator position. * */ function key(); /** * Gets the element of the collection at the current iterator position. * */ function current(); /** * Moves the internal iterator position to the next element. * */ function next(); /** * Tests for the existence of an element that satisfies the given predicate. * * @param Closure $p The predicate. * @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise. */ function exists(Closure $p); /** * Returns all the elements of this collection that satisfy the predicate p. * The order of the elements is preserved. * * @param Closure $p The predicate used for filtering. * @return Collection A collection with the results of the filter operation. */ function filter(Closure $p); /** * Applies the given predicate p to all elements of this collection, * returning true, if the predicate yields true for all elements. * * @param Closure $p The predicate. * @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise. */ function forAll(Closure $p); /** * Applies the given function to each element in the collection and returns * a new collection with the elements returned by the function. * * @param Closure $func * @return Collection */ function map(Closure $func); /** * Partitions this collection in two collections according to a predicate. * Keys are preserved in the resulting collections. * * @param Closure $p The predicate on which to partition. * @return array An array with two elements. The first element contains the collection * of elements where the predicate returned TRUE, the second element * contains the collection of elements where the predicate returned FALSE. */ function partition(Closure $p); /** * Gets the index/key of a given element. The comparison of two elements is strict, * that means not only the value but also the type must match. * For objects this means reference equality. * * @param mixed $element The element to search for. * @return mixed The key/index of the element or FALSE if the element was not found. */ function indexOf($element); /** * Extract a slice of $length elements starting at position $offset from the Collection. * * If $length is null it returns all elements from $offset to the end of the Collection. * Keys have to be preserved by this method. Calling this method will only return the * selected slice and NOT change the elements contained in the collection slice is called on. * * @param int $offset * @param int $length * @return array */ public function slice($offset, $length = null); }lib/Doctrine/Common/CommonException.php000064400000002161144760120550014135 0ustar00. */ namespace Doctrine\Common; /** * Base exception class for package Doctrine\Common * @author heinrich * */ class CommonException extends \Exception { }lib/Doctrine/Common/EventArgs.php000064400000005043144760120550012726 0ustar00. */ namespace Doctrine\Common; /** * EventArgs is the base class for classes containing event data. * * This class contains no event data. It is used by events that do not pass state * information to an event handler when an event is raised. The single empty EventArgs * instance can be obtained through {@link getEmptyInstance}. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision: 3938 $ * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ class EventArgs { /** * @var EventArgs Single instance of EventArgs * @static */ private static $_emptyEventArgsInstance; /** * Gets the single, empty and immutable EventArgs instance. * * This instance will be used when events are dispatched without any parameter, * like this: EventManager::dispatchEvent('eventname'); * * The benefit from this is that only one empty instance is instantiated and shared * (otherwise there would be instances for every dispatched in the abovementioned form) * * @see EventManager::dispatchEvent * @link http://msdn.microsoft.com/en-us/library/system.eventargs.aspx * @static * @return EventArgs */ public static function getEmptyInstance() { if ( ! self::$_emptyEventArgsInstance) { self::$_emptyEventArgsInstance = new EventArgs; } return self::$_emptyEventArgsInstance; } } lib/Doctrine/Common/EventManager.php000064400000011454144760120550013407 0ustar00. */ namespace Doctrine\Common; use Doctrine\Common\Events\Event; /** * The EventManager is the central point of Doctrine's event listener system. * Listeners are registered on the manager and events are dispatched through the * manager. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision: 3938 $ * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ class EventManager { /** * Map of registered listeners. * => * * @var array */ private $_listeners = array(); /** * Dispatches an event to all registered listeners. * * @param string $eventName The name of the event to dispatch. The name of the event is * the name of the method that is invoked on listeners. * @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners. * If not supplied, the single empty EventArgs instance is used. * @return boolean */ public function dispatchEvent($eventName, EventArgs $eventArgs = null) { if (isset($this->_listeners[$eventName])) { $eventArgs = $eventArgs === null ? EventArgs::getEmptyInstance() : $eventArgs; foreach ($this->_listeners[$eventName] as $listener) { $listener->$eventName($eventArgs); } } } /** * Gets the listeners of a specific event or all listeners. * * @param string $event The name of the event. * @return array The event listeners for the specified event, or all event listeners. */ public function getListeners($event = null) { return $event ? $this->_listeners[$event] : $this->_listeners; } /** * Checks whether an event has any registered listeners. * * @param string $event * @return boolean TRUE if the specified event has any listeners, FALSE otherwise. */ public function hasListeners($event) { return isset($this->_listeners[$event]) && $this->_listeners[$event]; } /** * Adds an event listener that listens on the specified events. * * @param string|array $events The event(s) to listen on. * @param object $listener The listener object. */ public function addEventListener($events, $listener) { // Picks the hash code related to that listener $hash = spl_object_hash($listener); foreach ((array) $events as $event) { // Overrides listener if a previous one was associated already // Prevents duplicate listeners on same event (same instance only) $this->_listeners[$event][$hash] = $listener; } } /** * Removes an event listener from the specified events. * * @param string|array $events * @param object $listener */ public function removeEventListener($events, $listener) { // Picks the hash code related to that listener $hash = spl_object_hash($listener); foreach ((array) $events as $event) { // Check if actually have this listener associated if (isset($this->_listeners[$event][$hash])) { unset($this->_listeners[$event][$hash]); } } } /** * Adds an EventSubscriber. The subscriber is asked for all the events he is * interested in and added as a listener for these events. * * @param Doctrine\Common\EventSubscriber $subscriber The subscriber. */ public function addEventSubscriber(EventSubscriber $subscriber) { $this->addEventListener($subscriber->getSubscribedEvents(), $subscriber); } }lib/Doctrine/Common/EventSubscriber.php000064400000003405144760120550014135 0ustar00. */ namespace Doctrine\Common; /** * An EventSubscriber knows himself what events he is interested in. * If an EventSubscriber is added to an EventManager, the manager invokes * {@link getSubscribedEvents} and registers the subscriber as a listener for all * returned events. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ interface EventSubscriber { /** * Returns an array of events this subscriber wants to listen to. * * @return array */ public function getSubscribedEvents(); } lib/Doctrine/Common/Lexer.php000064400000016115144760120550012111 0ustar00. */ namespace Doctrine\Common; /** * Base class for writing simple lexers, i.e. for creating small DSLs. * * @since 2.0 * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @todo Rename: AbstractLexer */ abstract class Lexer { /** * @var array Array of scanned tokens */ private $tokens = array(); /** * @var integer Current lexer position in input string */ private $position = 0; /** * @var integer Current peek of current lexer position */ private $peek = 0; /** * @var array The next token in the input. */ public $lookahead; /** * @var array The last matched/seen token. */ public $token; /** * Sets the input data to be tokenized. * * The Lexer is immediately reset and the new input tokenized. * Any unprocessed tokens from any previous input are lost. * * @param string $input The input to be tokenized. */ public function setInput($input) { $this->tokens = array(); $this->reset(); $this->scan($input); } /** * Resets the lexer. */ public function reset() { $this->lookahead = null; $this->token = null; $this->peek = 0; $this->position = 0; } /** * Resets the peek pointer to 0. */ public function resetPeek() { $this->peek = 0; } /** * Resets the lexer position on the input to the given position. * * @param integer $position Position to place the lexical scanner */ public function resetPosition($position = 0) { $this->position = $position; } /** * Checks whether a given token matches the current lookahead. * * @param integer|string $token * @return boolean */ public function isNextToken($token) { return null !== $this->lookahead && $this->lookahead['type'] === $token; } /** * Checks whether any of the given tokens matches the current lookahead * * @param array $tokens * @return boolean */ public function isNextTokenAny(array $tokens) { return null !== $this->lookahead && in_array($this->lookahead['type'], $tokens, true); } /** * Moves to the next token in the input string. * * A token is an associative array containing three items: * - 'value' : the string value of the token in the input string * - 'type' : the type of the token (identifier, numeric, string, input * parameter, none) * - 'position' : the position of the token in the input string * * @return array|null the next token; null if there is no more tokens left */ public function moveNext() { $this->peek = 0; $this->token = $this->lookahead; $this->lookahead = (isset($this->tokens[$this->position])) ? $this->tokens[$this->position++] : null; return $this->lookahead !== null; } /** * Tells the lexer to skip input tokens until it sees a token with the given value. * * @param $type The token type to skip until. */ public function skipUntil($type) { while ($this->lookahead !== null && $this->lookahead['type'] !== $type) { $this->moveNext(); } } /** * Checks if given value is identical to the given token * * @param mixed $value * @param integer $token * @return boolean */ public function isA($value, $token) { return $this->getType($value) === $token; } /** * Moves the lookahead token forward. * * @return array | null The next token or NULL if there are no more tokens ahead. */ public function peek() { if (isset($this->tokens[$this->position + $this->peek])) { return $this->tokens[$this->position + $this->peek++]; } else { return null; } } /** * Peeks at the next token, returns it and immediately resets the peek. * * @return array|null The next token or NULL if there are no more tokens ahead. */ public function glimpse() { $peek = $this->peek(); $this->peek = 0; return $peek; } /** * Scans the input string for tokens. * * @param string $input a query string */ protected function scan($input) { static $regex; if ( ! isset($regex)) { $regex = '/(' . implode(')|(', $this->getCatchablePatterns()) . ')|' . implode('|', $this->getNonCatchablePatterns()) . '/i'; } $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE; $matches = preg_split($regex, $input, -1, $flags); foreach ($matches as $match) { // Must remain before 'value' assignment since it can change content $type = $this->getType($match[0]); $this->tokens[] = array( 'value' => $match[0], 'type' => $type, 'position' => $match[1], ); } } /** * Gets the literal for a given token. * * @param integer $token * @return string */ public function getLiteral($token) { $className = get_class($this); $reflClass = new \ReflectionClass($className); $constants = $reflClass->getConstants(); foreach ($constants as $name => $value) { if ($value === $token) { return $className . '::' . $name; } } return $token; } /** * Lexical catchable patterns. * * @return array */ abstract protected function getCatchablePatterns(); /** * Lexical non-catchable patterns. * * @return array */ abstract protected function getNonCatchablePatterns(); /** * Retrieve token type. Also processes the token value if necessary. * * @param string $value * @return integer */ abstract protected function getType(&$value); }lib/Doctrine/Common/NotifyPropertyChanged.php000064400000003252144760120550015317 0ustar00. */ namespace Doctrine\Common; /** * Contract for classes that provide the service of notifying listeners of * changes to their properties. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision: 3938 $ * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ interface NotifyPropertyChanged { /** * Adds a listener that wants to be notified about property changes. * * @param PropertyChangedListener $listener */ function addPropertyChangedListener(PropertyChangedListener $listener); } lib/Doctrine/Common/Persistence/Mapping/ClassMetadata.php000064400000007605144760120550017423 0ustar00. */ namespace Doctrine\Common\Persistence\Mapping; /** * Contract for a Doctrine persistence layer ClassMetadata class to implement. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.1 * @author Benjamin Eberlei * @author Jonathan Wage */ interface ClassMetadata { /** * Get fully-qualified class name of this persistent class. * * @return string */ public function getName(); /** * Gets the mapped identifier field name. * * The returned structure is an array of the identifier field names. * * @return array */ public function getIdentifier(); /** * Gets the ReflectionClass instance for this mapped class. * * @return ReflectionClass */ public function getReflectionClass(); /** * Checks if the given field name is a mapped identifier for this class. * * @param string $fieldName * @return boolean */ public function isIdentifier($fieldName); /** * Checks if the given field is a mapped property for this class. * * @param string $fieldName * @return boolean */ public function hasField($fieldName); /** * Checks if the given field is a mapped association for this class. * * @param string $fieldName * @return boolean */ public function hasAssociation($fieldName); /** * Checks if the given field is a mapped single valued association for this class. * * @param string $fieldName * @return boolean */ public function isSingleValuedAssociation($fieldName); /** * Checks if the given field is a mapped collection valued association for this class. * * @param string $fieldName * @return boolean */ public function isCollectionValuedAssociation($fieldName); /** * A numerically indexed list of field names of this persistent class. * * This array includes identifier fields if present on this class. * * @return array */ public function getFieldNames(); /** * A numerically indexed list of association names of this persistent class. * * This array includes identifier associations if present on this class. * * @return array */ public function getAssociationNames(); /** * Returns a type name of this field. * * This type names can be implementation specific but should at least include the php types: * integer, string, boolean, float/double, datetime. * * @param string $fieldName * @return string */ public function getTypeOfField($fieldName); /** * Returns the target class name of the given association. * * @param string $assocName * @return string */ public function getAssociationTargetClass($assocName); }lib/Doctrine/Common/Persistence/Mapping/ClassMetadataFactory.php000064400000004454144760120550020752 0ustar00. */ namespace Doctrine\Common\Persistence\Mapping; /** * Contract for a Doctrine persistence layer ClassMetadata class to implement. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.1 * @author Benjamin Eberlei * @author Jonathan Wage */ interface ClassMetadataFactory { /** * Forces the factory to load the metadata of all classes known to the underlying * mapping driver. * * @return array The ClassMetadata instances of all mapped classes. */ public function getAllMetadata(); /** * Gets the class metadata descriptor for a class. * * @param string $className The name of the class. * @return Doctrine\ODM\MongoDB\Mapping\ClassMetadata */ public function getMetadataFor($className); /** * Checks whether the factory has the metadata for a class loaded already. * * @param string $className * @return boolean TRUE if the metadata of the class in question is already loaded, FALSE otherwise. */ public function hasMetadataFor($className); /** * Sets the metadata descriptor for a specific class. * * @param string $className * @param ClassMetadata $class */ public function setMetadataFor($className, $class); }lib/Doctrine/Common/Persistence/ObjectManager.php000064400000010476144760120550016023 0ustar00. */ namespace Doctrine\Common\Persistence; /** * Contract for a Doctrine persistence layer ObjectManager class to implement. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.1 * @author Benjamin Eberlei * @author Jonathan Wage */ interface ObjectManager { /** * Finds a object by its identifier. * * This is just a convenient shortcut for getRepository($className)->find($id). * * @param string * @param mixed * @return object */ public function find($className, $id); /** * Tells the ObjectManager to make an instance managed and persistent. * * The object will be entered into the database as a result of the flush operation. * * NOTE: The persist operation always considers objects that are not yet known to * this ObjectManager as NEW. Do not pass detached objects to the persist operation. * * @param object $object The instance to make managed and persistent. */ public function persist($object); /** * Removes an object instance. * * A removed object will be removed from the database as a result of the flush operation. * * @param object $object The object instance to remove. */ public function remove($object); /** * Merges the state of a detached object into the persistence context * of this ObjectManager and returns the managed copy of the object. * The object passed to merge will not become associated/managed with this ObjectManager. * * @param object $object */ public function merge($object); /** * Detaches an object from the ObjectManager, causing a managed object to * become detached. Unflushed changes made to the object if any * (including removal of the object), will not be synchronized to the database. * Objects which previously referenced the detached object will continue to * reference it. * * @param object $object The object to detach. */ public function detach($object); /** * Refreshes the persistent state of an object from the database, * overriding any local changes that have not yet been persisted. * * @param object $object The object to refresh. */ public function refresh($object); /** * Flushes all changes to objects that have been queued up to now to the database. * This effectively synchronizes the in-memory state of managed objects with the * database. */ public function flush(); /** * Gets the repository for a class. * * @param string $className * @return \Doctrine\Common\Persistence\ObjectRepository */ public function getRepository($className); /** * Returns the ClassMetadata descriptor for a class. * * The class name must be the fully-qualified class name without a leading backslash * (as it is returned by get_class($obj)). * * @param string $className * @return \Doctrine\Common\Persistence\Mapping\ClassMetadata */ public function getClassMetadata($className); /** * Gets the metadata factory used to gather the metadata of classes. * * @return Doctrine\Common\Persistence\Mapping\ClassMetadataFactory */ public function getMetadataFactory(); }lib/Doctrine/Common/Persistence/ObjectRepository.php000064400000004607144760120550016627 0ustar00. */ namespace Doctrine\Common\Persistence; /** * Contract for a Doctrine persistence layer ObjectRepository class to implement. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.1 * @author Benjamin Eberlei * @author Jonathan Wage */ interface ObjectRepository { /** * Finds an object by its primary key / identifier. * * @param $id The identifier. * @return object The object. */ public function find($id); /** * Finds all objects in the repository. * * @return mixed The objects. */ public function findAll(); /** * Finds objects by a set of criteria. * * Optionally sorting and limiting details can be passed. An implementation may throw * an UnexpectedValueException if certain values of the sorting or limiting details are * not supported. * * @throws UnexpectedValueException * @param array $criteria * @param array|null $orderBy * @param int|null $limit * @param int|null $offset * @return mixed The objects. */ public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null); /** * Finds a single object by a set of criteria. * * @param array $criteria * @return object The object. */ public function findOneBy(array $criteria); } lib/Doctrine/Common/PropertyChangedListener.php000064400000003611144760120550015633 0ustar00. */ namespace Doctrine\Common; /** * Contract for classes that are potential listeners of a NotifyPropertyChanged * implementor. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision: 3938 $ * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ interface PropertyChangedListener { /** * Notifies the listener of a property change. * * @param object $sender The object on which the property changed. * @param string $propertyName The name of the property that changed. * @param mixed $oldValue The old value of the property that changed. * @param mixed $newValue The new value of the property that changed. */ function propertyChanged($sender, $propertyName, $oldValue, $newValue); } lib/Doctrine/Common/Util/Debug.php000064400000011402144760120550012767 0ustar00. */ namespace Doctrine\Common\Util; /** * Static class containing most used debug methods. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision: 3938 $ * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author Giorgio Sironi */ final class Debug { /** * Private constructor (prevents from instantiation) * */ private function __construct() {} /** * Prints a dump of the public, protected and private properties of $var. * * @static * @link http://xdebug.org/ * @param mixed $var * @param integer $maxDepth Maximum nesting level for object properties */ public static function dump($var, $maxDepth = 2) { ini_set('html_errors', 'On'); if (extension_loaded('xdebug')) { ini_set('xdebug.var_display_max_depth', $maxDepth); } $var = self::export($var, $maxDepth++); ob_start(); var_dump($var); $dump = ob_get_contents(); ob_end_clean(); echo strip_tags(html_entity_decode($dump)); ini_set('html_errors', 'Off'); } public static function export($var, $maxDepth) { $return = null; $isObj = is_object($var); if ($isObj && in_array('Doctrine\Common\Collections\Collection', class_implements($var))) { $var = $var->toArray(); } if ($maxDepth) { if (is_array($var)) { $return = array(); foreach ($var as $k => $v) { $return[$k] = self::export($v, $maxDepth - 1); } } else if ($isObj) { if ($var instanceof \DateTime) { $return = $var->format('c'); } else { $reflClass = new \ReflectionClass(get_class($var)); $return = new \stdclass(); $return->{'__CLASS__'} = get_class($var); if ($var instanceof \Doctrine\ORM\Proxy\Proxy && ! $var->__isInitialized__) { $reflProperty = $reflClass->getProperty('_identifier'); $reflProperty->setAccessible(true); foreach ($reflProperty->getValue($var) as $name => $value) { $return->$name = self::export($value, $maxDepth - 1); } } else { $excludeProperties = array(); if ($var instanceof \Doctrine\ORM\Proxy\Proxy) { $excludeProperties = array('_entityPersister', '__isInitialized__', '_identifier'); } foreach ($reflClass->getProperties() as $reflProperty) { $name = $reflProperty->getName(); if ( ! in_array($name, $excludeProperties)) { $reflProperty->setAccessible(true); $return->$name = self::export($reflProperty->getValue($var), $maxDepth - 1); } } } } } else { $return = $var; } } else { $return = is_object($var) ? get_class($var) : (is_array($var) ? 'Array(' . count($var) . ')' : $var); } return $return; } public static function toString($obj) { return method_exists('__toString', $obj) ? (string) $obj : get_class($obj) . '@' . spl_object_hash($obj); } } lib/Doctrine/Common/Util/Inflector.php000064400000005073144760120550013675 0ustar00. */ namespace Doctrine\Common\Util; /** * Doctrine inflector has static methods for inflecting text * * The methods in these classes are from several different sources collected * across several different php projects and several different authors. The * original author names and emails are not known * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 1.0 * @version $Revision: 3189 $ * @author Konsta Vesterinen * @author Jonathan H. Wage */ class Inflector { /** * Convert word in to the format for a Doctrine table name. Converts 'ModelName' to 'model_name' * * @param string $word Word to tableize * @return string $word Tableized word */ public static function tableize($word) { return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $word)); } /** * Convert a word in to the format for a Doctrine class name. Converts 'table_name' to 'TableName' * * @param string $word Word to classify * @return string $word Classified word */ public static function classify($word) { return str_replace(" ", "", ucwords(strtr($word, "_-", " "))); } /** * Camelize a word. This uses the classify() method and turns the first character to lowercase * * @param string $word * @return string $word */ public static function camelize($word) { return lcfirst(self::classify($word)); } }lib/Doctrine/Common/Version.php000064400000003755144760120550012465 0ustar00. */ namespace Doctrine\Common; /** * Class to store and retrieve the version of Doctrine * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision$ * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ class Version { /** * Current Doctrine Version */ const VERSION = '2.1.3'; /** * Compares a Doctrine version with the current one. * * @param string $version Doctrine version to compare. * @return int Returns -1 if older, 0 if it is the same, 1 if version * passed as argument is newer. */ public static function compare($version) { $currentVersion = str_replace(' ', '', strtolower(self::VERSION)); $version = str_replace(' ', '', $version); return version_compare($version, $currentVersion); } } phpunit.xml.dist000064400000001462144760120550007726 0ustar00 ./tests/Doctrine/ ./lib/Doctrine/ performance tests/.gitignore000064400000000143144760120550007700 0ustar00Doctrine/Tests/Proxies/ Doctrine/Tests/ORM/Proxy/generated/ Doctrine/Tests/ORM/Tools/Export/export tests/Doctrine/Tests/Common/Annotations/AbstractReaderTest.php000064400000030013144760120550020544 0ustar00getReader(); $class = new ReflectionClass('Doctrine\Tests\Common\Annotations\DummyClass'); $this->assertEquals(1, count($reader->getClassAnnotations($class))); $this->assertInstanceOf($annotName = 'Doctrine\Tests\Common\Annotations\DummyAnnotation', $annot = $reader->getClassAnnotation($class, $annotName)); $this->assertEquals("hello", $annot->dummyValue); $field1Prop = $class->getProperty('field1'); $propAnnots = $reader->getPropertyAnnotations($field1Prop); $this->assertEquals(1, count($propAnnots)); $this->assertInstanceOf($annotName, $annot = $reader->getPropertyAnnotation($field1Prop, $annotName)); $this->assertEquals("fieldHello", $annot->dummyValue); $getField1Method = $class->getMethod('getField1'); $methodAnnots = $reader->getMethodAnnotations($getField1Method); $this->assertEquals(1, count($methodAnnots)); $this->assertInstanceOf($annotName, $annot = $reader->getMethodAnnotation($getField1Method, $annotName)); $this->assertEquals(array(1, 2, "three"), $annot->value); $field2Prop = $class->getProperty('field2'); $propAnnots = $reader->getPropertyAnnotations($field2Prop); $this->assertEquals(1, count($propAnnots)); $this->assertInstanceOf($annotName = 'Doctrine\Tests\Common\Annotations\DummyJoinTable', $joinTableAnnot = $reader->getPropertyAnnotation($field2Prop, $annotName)); $this->assertEquals(1, count($joinTableAnnot->joinColumns)); $this->assertEquals(1, count($joinTableAnnot->inverseJoinColumns)); $this->assertTrue($joinTableAnnot->joinColumns[0] instanceof DummyJoinColumn); $this->assertTrue($joinTableAnnot->inverseJoinColumns[0] instanceof DummyJoinColumn); $this->assertEquals('col1', $joinTableAnnot->joinColumns[0]->name); $this->assertEquals('col2', $joinTableAnnot->joinColumns[0]->referencedColumnName); $this->assertEquals('col3', $joinTableAnnot->inverseJoinColumns[0]->name); $this->assertEquals('col4', $joinTableAnnot->inverseJoinColumns[0]->referencedColumnName); $dummyAnnot = $reader->getMethodAnnotation($class->getMethod('getField1'), 'Doctrine\Tests\Common\Annotations\DummyAnnotation'); $this->assertEquals('', $dummyAnnot->dummyValue); $this->assertEquals(array(1, 2, 'three'), $dummyAnnot->value); $dummyAnnot = $reader->getPropertyAnnotation($class->getProperty('field1'), 'Doctrine\Tests\Common\Annotations\DummyAnnotation'); $this->assertEquals('fieldHello', $dummyAnnot->dummyValue); $classAnnot = $reader->getClassAnnotation($class, 'Doctrine\Tests\Common\Annotations\DummyAnnotation'); $this->assertEquals('hello', $classAnnot->dummyValue); } /** * @expectedException Doctrine\Common\Annotations\AnnotationException * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 18 in class Doctrine\Tests\Common\Annotations\DummyClassSyntaxError. */ public function testClassSyntaxErrorContext() { $reader = $this->getReader(); $reader->getClassAnnotations(new \ReflectionClass('Doctrine\Tests\Common\Annotations\DummyClassSyntaxError')); } /** * @expectedException Doctrine\Common\Annotations\AnnotationException * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 18 in method Doctrine\Tests\Common\Annotations\DummyClassMethodSyntaxError::foo(). */ public function testMethodSyntaxErrorContext() { $reader = $this->getReader(); $reader->getMethodAnnotations(new \ReflectionMethod('Doctrine\Tests\Common\Annotations\DummyClassMethodSyntaxError', 'foo')); } /** * @expectedException Doctrine\Common\Annotations\AnnotationException * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 18 in property Doctrine\Tests\Common\Annotations\DummyClassPropertySyntaxError::$foo. */ public function testPropertySyntaxErrorContext() { $reader = $this->getReader(); $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\DummyClassPropertySyntaxError', 'foo')); } /** * @group regression */ public function testMultipleAnnotationsOnSameLine() { $reader = $this->getReader(); $annots = $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\DummyClass2', 'id')); $this->assertEquals(3, count($annots)); } public function testNonAnnotationProblem() { $reader = $this->getReader(); $this->assertNotNull($annot = $reader->getPropertyAnnotation(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\DummyClassNonAnnotationProblem', 'foo'), $name = 'Doctrine\Tests\Common\Annotations\DummyAnnotation')); $this->assertInstanceOf($name, $annot); } public function testImportWithConcreteAnnotation() { $reader = $this->getReader(); $property = new \ReflectionProperty('Doctrine\Tests\Common\Annotations\TestImportWithConcreteAnnotation', 'field'); $annotations = $reader->getPropertyAnnotations($property); $this->assertEquals(1, count($annotations)); $this->assertNotNull($reader->getPropertyAnnotation($property, 'Doctrine\Tests\Common\Annotations\DummyAnnotation')); } public function testImportWithInheritance() { $reader = $this->getReader(); $class = new TestParentClass(); $ref = new \ReflectionClass($class); $childAnnotations = $reader->getPropertyAnnotations($ref->getProperty('child')); $this->assertEquals(1, count($childAnnotations)); $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Foo\Name', reset($childAnnotations)); $parentAnnotations = $reader->getPropertyAnnotations($ref->getProperty('parent')); $this->assertEquals(1, count($parentAnnotations)); $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Bar\Name', reset($parentAnnotations)); } /** * @expectedException Doctrine\Common\Annotations\AnnotationException * @expectedExceptionMessage The annotation "@NameFoo" in property Doctrine\Tests\Common\Annotations\TestAnnotationNotImportedClass::$field was never imported. */ public function testImportDetectsNotImportedAnnotation() { $reader = $this->getReader(); $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\TestAnnotationNotImportedClass', 'field')); } /** * @expectedException Doctrine\Common\Annotations\AnnotationException * @expectedExceptionMessage The annotation "@Foo\Bar\Name" in property Doctrine\Tests\Common\Annotations\TestNonExistentAnnotationClass::$field was never imported. */ public function testImportDetectsNonExistentAnnotation() { $reader = $this->getReader(); $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\TestNonExistentAnnotationClass', 'field')); } public function testTopLevelAnnotation() { $reader = $this->getReader(); $annotations = $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\TestTopLevelAnnotationClass', 'field')); $this->assertEquals(1, count($annotations)); $this->assertInstanceOf('\TopLevelAnnotation', reset($annotations)); } public function testIgnoresAnnotationsNotPrefixedWithWhitespace() { $reader = $this->getReader(); $annotation = $reader->getClassAnnotation(new \ReflectionClass(new TestIgnoresNonAnnotationsClass()), 'Doctrine\Tests\Common\Annotations\Name'); $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Name', $annotation); } abstract protected function getReader(); } /** * @parseAnnotation("var") * @author Johannes M. Schmitt * */ class TestParseAnnotationClass { /** * @var */ private $field; } /** * @Name * @author Johannes M. Schmitt */ class TestIgnoresNonAnnotationsClass { } class TestTopLevelAnnotationClass { /** * @\TopLevelAnnotation */ private $field; } class TestNonExistentAnnotationClass { /** * @Foo\Bar\Name */ private $field; } class TestAnnotationNotImportedClass { /** * @NameFoo */ private $field; } class TestChildClass { /** * @\Doctrine\Tests\Common\Annotations\Foo\Name(name = "foo") */ protected $child; } class TestParentClass extends TestChildClass { /** * @\Doctrine\Tests\Common\Annotations\Bar\Name(name = "bar") */ private $parent; } class TestImportWithConcreteAnnotation { /** * @DummyAnnotation(dummyValue = "bar") */ private $field; } /** * A description of this class. * * Let's see if the parser recognizes that this @ is not really referring to an * annotation. Also make sure that @var \ is not concated to "@var\is". * * @author robo * @since 2.0 * @DummyAnnotation(dummyValue="hello") */ class DummyClass { /** * A nice property. * * @var mixed * @DummyAnnotation(dummyValue="fieldHello") */ private $field1; /** * @DummyJoinTable(name="join_table", * joinColumns={@DummyJoinColumn(name="col1", referencedColumnName="col2")}, * inverseJoinColumns={ * @DummyJoinColumn(name="col3", referencedColumnName="col4") * }) */ private $field2; /** * Gets the value of field1. * * @return mixed * @DummyAnnotation({1,2,"three"}) */ public function getField1() { } } /** * @ignoreAnnotation("var") */ class DummyClass2 { /** * @DummyId @DummyColumn(type="integer") @DummyGeneratedValue * @var integer */ private $id; } class DummyId extends \Doctrine\Common\Annotations\Annotation {} class DummyColumn extends \Doctrine\Common\Annotations\Annotation { public $type; } class DummyGeneratedValue extends \Doctrine\Common\Annotations\Annotation {} class DummyAnnotation extends \Doctrine\Common\Annotations\Annotation { public $dummyValue; } class DummyJoinColumn extends \Doctrine\Common\Annotations\Annotation { public $name; public $referencedColumnName; } class DummyJoinTable extends \Doctrine\Common\Annotations\Annotation { public $name; public $joinColumns; public $inverseJoinColumns; } /** * @DummyAnnotation(@) */ class DummyClassSyntaxError { } class DummyClassMethodSyntaxError { /** * @DummyAnnotation(@) */ public function foo() { } } class DummyClassPropertySyntaxError { /** * @DummyAnnotation(@) */ public $foo; } /** * @ignoreAnnotation({"since", "var"}) */ class DummyClassNonAnnotationProblem { /** * @DummyAnnotation * * @var \Test * @since 0.1 */ public $foo; } /** * @DummyAnnotation Foo bar */ class DummyClassWithEmail { } namespace Doctrine\Tests\Common\Annotations\Foo; class Name extends \Doctrine\Common\Annotations\Annotation { public $name; } namespace Doctrine\Tests\Common\Annotations\Bar; class Name extends \Doctrine\Common\Annotations\Annotation { public $name; } tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php000064400000000367144760120550021124 0ustar00getMock('Doctrine\Common\Cache\Cache'); $cache ->expects($this->at(0)) ->method('fetch') ->with($this->equalTo($cacheKey)) ->will($this->returnValue(array())) ; $cache ->expects($this->at(1)) ->method('fetch') ->with($this->equalTo('[C]'.$cacheKey)) ->will($this->returnValue(time() - 10)) ; $cache ->expects($this->at(2)) ->method('save') ->with($this->equalTo($cacheKey)) ; $cache ->expects($this->at(3)) ->method('save') ->with($this->equalTo('[C]'.$cacheKey)) ; $reader = new CachedReader(new AnnotationReader(), $cache, true); $this->assertEquals(array( new Route(array('value' => '/someprefix')), ), $reader->getClassAnnotations(new \ReflectionClass($name))); } protected function getReader() { $this->cache = new ArrayCache(); return new CachedReader(new AnnotationReader(), $this->cache); } }tests/Doctrine/Tests/Common/Annotations/DocLexerTest.php000064400000001340144760120550017364 0ustar00setInput("@Name"); $this->assertNull($lexer->token); $this->assertNull($lexer->lookahead); $this->assertTrue($lexer->moveNext()); $this->assertNull($lexer->token); $this->assertEquals('@', $lexer->lookahead['value']); $this->assertTrue($lexer->moveNext()); $this->assertEquals('@', $lexer->token['value']); $this->assertEquals('Name', $lexer->lookahead['value']); $this->assertFalse($lexer->moveNext()); } }tests/Doctrine/Tests/Common/Annotations/DocParserTest.php000064400000026342144760120550017552 0ustar00createTestParser(); // Nested arrays with nested annotations $result = $parser->parse('@Name(foo={1,2, {"key"=@Name}})'); $annot = $result[0]; $this->assertTrue($annot instanceof Name); $this->assertNull($annot->value); $this->assertEquals(3, count($annot->foo)); $this->assertEquals(1, $annot->foo[0]); $this->assertEquals(2, $annot->foo[1]); $this->assertTrue(is_array($annot->foo[2])); $nestedArray = $annot->foo[2]; $this->assertTrue(isset($nestedArray['key'])); $this->assertTrue($nestedArray['key'] instanceof Name); } public function testBasicAnnotations() { $parser = $this->createTestParser(); // Marker annotation $result = $parser->parse("@Name"); $annot = $result[0]; $this->assertTrue($annot instanceof Name); $this->assertNull($annot->value); $this->assertNull($annot->foo); // Associative arrays $result = $parser->parse('@Name(foo={"key1" = "value1"})'); $annot = $result[0]; $this->assertNull($annot->value); $this->assertTrue(is_array($annot->foo)); $this->assertTrue(isset($annot->foo['key1'])); // Numerical arrays $result = $parser->parse('@Name({2="foo", 4="bar"})'); $annot = $result[0]; $this->assertTrue(is_array($annot->value)); $this->assertEquals('foo', $annot->value[2]); $this->assertEquals('bar', $annot->value[4]); $this->assertFalse(isset($annot->value[0])); $this->assertFalse(isset($annot->value[1])); $this->assertFalse(isset($annot->value[3])); // Multiple values $result = $parser->parse('@Name(@Name, @Name)'); $annot = $result[0]; $this->assertTrue($annot instanceof Name); $this->assertTrue(is_array($annot->value)); $this->assertTrue($annot->value[0] instanceof Name); $this->assertTrue($annot->value[1] instanceof Name); // Multiple types as values $result = $parser->parse('@Name(foo="Bar", @Name, {"key1"="value1", "key2"="value2"})'); $annot = $result[0]; $this->assertTrue($annot instanceof Name); $this->assertTrue(is_array($annot->value)); $this->assertTrue($annot->value[0] instanceof Name); $this->assertTrue(is_array($annot->value[1])); $this->assertEquals('value1', $annot->value[1]['key1']); $this->assertEquals('value2', $annot->value[1]['key2']); // Complete docblock $docblock = <<parse($docblock); $this->assertEquals(1, count($result)); $annot = $result[0]; $this->assertTrue($annot instanceof Name); $this->assertEquals("bar", $annot->foo); $this->assertNull($annot->value); } public function testNamespacedAnnotations() { $parser = new DocParser; $parser->setIgnoreNotImportedAnnotations(true); $docblock = << * @Doctrine\Tests\Common\Annotations\Name(foo="bar") * @ignore */ DOCBLOCK; $result = $parser->parse($docblock); $this->assertEquals(1, count($result)); $annot = $result[0]; $this->assertTrue($annot instanceof Name); $this->assertEquals("bar", $annot->foo); } /** * @group debug */ public function testTypicalMethodDocBlock() { $parser = $this->createTestParser(); $docblock = <<parse($docblock); $this->assertEquals(2, count($result)); $this->assertTrue(isset($result[0])); $this->assertTrue(isset($result[1])); $annot = $result[0]; $this->assertTrue($annot instanceof Name); $this->assertEquals("bar", $annot->foo); $marker = $result[1]; $this->assertTrue($marker instanceof Marker); } /** * @group DDC-575 */ public function testRegressionDDC575() { $parser = $this->createTestParser(); $docblock = <<parse($docblock); $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Name", $result[0]); $docblock = <<parse($docblock); $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Name", $result[0]); } /** * @group DDC-77 */ public function testAnnotationWithoutClassIsIgnoredWithoutWarning() { $parser = new DocParser(); $parser->setIgnoreNotImportedAnnotations(true); $result = $parser->parse("@param"); $this->assertEquals(0, count($result)); } /** * @expectedException Doctrine\Common\Annotations\AnnotationException * @expectedExceptionMessage Expected PlainValue, got ''' at position 10. */ public function testAnnotationDontAcceptSingleQuotes() { $parser = $this->createTestParser(); $parser->parse("@Name(foo='bar')"); } /** * @group DCOM-41 */ public function testAnnotationDoesntThrowExceptionWhenAtSignIsNotFollowedByIdentifier() { $parser = new DocParser(); $result = $parser->parse("'@'"); $this->assertEquals(0, count($result)); } /** * @group DCOM-41 * @expectedException Doctrine\Common\Annotations\AnnotationException */ public function testAnnotationThrowsExceptionWhenAtSignIsNotFollowedByIdentifierInNestedAnnotation() { $parser = new DocParser(); $result = $parser->parse("@Doctrine\Tests\Common\Annotations\Name(@')"); } /** * @group DCOM-56 */ public function testAutoloadAnnotation() { $this->assertFalse(class_exists('Doctrine\Tests\Common\Annotations\Fixture\Annotation\Autoload', false), 'Pre-condition: Doctrine\Tests\Common\Annotations\Fixture\Annotation\Autoload not allowed to be loaded.'); $parser = new DocParser(); AnnotationRegistry::registerAutoloadNamespace('Doctrine\Tests\Common\Annotations\Fixtures\Annotation', __DIR__ . '/../../../../'); $parser->setImports(array( 'autoload' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Autoload', )); $annotations = $parser->parse('@Autoload'); $this->assertEquals(1, count($annotations)); $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Autoload', $annotations[0]); } public function createTestParser() { $parser = new DocParser(); $parser->setIgnoreNotImportedAnnotations(true); $parser->setImports(array( 'name' => 'Doctrine\Tests\Common\Annotations\Name', '__NAMESPACE__' => 'Doctrine\Tests\Common\Annotations', )); return $parser; } /** * @group DDC-78 * @expectedException Doctrine\Common\Annotations\AnnotationException * @expectedExceptionMessage Expected PlainValue, got ''' at position 10 in class \Doctrine\Tests\Common\Annotations\Name */ public function testSyntaxErrorWithContextDescription() { $parser = $this->createTestParser(); $parser->parse("@Name(foo='bar')", "class \Doctrine\Tests\Common\Annotations\Name"); } /** * @group DDC-183 */ public function testSyntaxErrorWithUnknownCharacters() { $docblock = <<setInput(trim($docblock, '/ *')); //var_dump($lexer); try { $parser = $this->createTestParser(); $result = $parser->parse($docblock); } catch (Exception $e) { $this->fail($e->getMessage()); } } /** * @group DCOM-14 */ public function testIgnorePHPDocThrowTag() { $docblock = <<createTestParser(); $result = $parser->parse($docblock); } catch (Exception $e) { $this->fail($e->getMessage()); } } /** * @group DCOM-38 */ public function testCastInt() { $parser = $this->createTestParser(); $result = $parser->parse("@Name(foo=1234)"); $annot = $result[0]; $this->assertInternalType('int', $annot->foo); } /** * @group DCOM-38 */ public function testCastFloat() { $parser = $this->createTestParser(); $result = $parser->parse("@Name(foo=1234.345)"); $annot = $result[0]; $this->assertInternalType('float', $annot->foo); } public function testReservedKeywordsInAnnotations() { $parser = $this->createTestParser(); $result = $parser->parse('@Doctrine\Tests\Common\Annotations\True'); $this->assertTrue($result[0] instanceof True); $result = $parser->parse('@Doctrine\Tests\Common\Annotations\False'); $this->assertTrue($result[0] instanceof False); $result = $parser->parse('@Doctrine\Tests\Common\Annotations\Null'); $this->assertTrue($result[0] instanceof Null); $result = $parser->parse('@True'); $this->assertTrue($result[0] instanceof True); $result = $parser->parse('@False'); $this->assertTrue($result[0] instanceof False); $result = $parser->parse('@Null'); $this->assertTrue($result[0] instanceof Null); } /** * @expectedException Doctrine\Common\Annotations\AnnotationException * @expectedExceptionMessage [Syntax Error] Expected Doctrine\Common\Annotations\DocLexer::T_IDENTIFIER or Doctrine\Common\Annotations\DocLexer::T_TRUE or Doctrine\Common\Annotations\DocLexer::T_FALSE or Doctrine\Common\Annotations\DocLexer::T_NULL, got '3.42' at position 5. */ public function testInvalidIdentifierInAnnotation() { $parser = $this->createTestParser(); $result = $parser->parse('@Foo\3.42'); } } class Name extends \Doctrine\Common\Annotations\Annotation { public $foo; } class Marker extends \Doctrine\Common\Annotations\Annotation {} class True extends \Doctrine\Common\Annotations\Annotation {} class False extends \Doctrine\Common\Annotations\Annotation {} class Null extends \Doctrine\Common\Annotations\Annotation {} namespace Doctrine\Tests\Common\Annotations\FooBar; class Name extends \Doctrine\Common\Annotations\Annotation { } tests/Doctrine/Tests/Common/Annotations/FileCacheReaderTest.php000064400000001205144760120550020605 0ustar00cacheDir = sys_get_temp_dir() . "/annotations_". uniqid(); @mkdir($this->cacheDir); return new FileCacheReader(new AnnotationReader(), $this->cacheDir); } public function tearDown() { foreach (glob($this->cacheDir.'/*.php') AS $file) { unlink($file); } rmdir($this->cacheDir); } }tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Autoload.php000064400000000247144760120550022517 0ustar00roles = $values['value']; } }tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Template.php000064400000000363144760120550022521 0ustar00name = isset($values['value']) ? $values['value'] : null; } }tests/Doctrine/Tests/Common/Annotations/Fixtures/Controller.php000064400000024604144760120550020763 0ustar00 */ class Controller { /** * @Route("/", name="_demo") * @Template() */ public function indexAction() { return array(); } /** * @Route("/hello/{name}", name="_demo_hello") * @Template() */ public function helloAction($name) { return array('name' => $name); } /** * @Route("/contact", name="_demo_contact") * @Template() */ public function contactAction() { $form = ContactForm::create($this->get('form.context'), 'contact'); $form->bind($this->container->get('request'), $form); if ($form->isValid()) { $form->send($this->get('mailer')); $this->get('session')->setFlash('notice', 'Message sent!'); return new RedirectResponse($this->generateUrl('_demo')); } return array('form' => $form); } /** * Creates the ACL for the passed object identity * * @param ObjectIdentityInterface $oid * @return void */ private function createObjectIdentity(ObjectIdentityInterface $oid) { $classId = $this->createOrRetrieveClassId($oid->getType()); $this->connection->executeQuery($this->getInsertObjectIdentitySql($oid->getIdentifier(), $classId, true)); } /** * Returns the primary key for the passed class type. * * If the type does not yet exist in the database, it will be created. * * @param string $classType * @return integer */ private function createOrRetrieveClassId($classType) { if (false !== $id = $this->connection->executeQuery($this->getSelectClassIdSql($classType))->fetchColumn()) { return $id; } $this->connection->executeQuery($this->getInsertClassSql($classType)); return $this->connection->executeQuery($this->getSelectClassIdSql($classType))->fetchColumn(); } /** * Returns the primary key for the passed security identity. * * If the security identity does not yet exist in the database, it will be * created. * * @param SecurityIdentityInterface $sid * @return integer */ private function createOrRetrieveSecurityIdentityId(SecurityIdentityInterface $sid) { if (false !== $id = $this->connection->executeQuery($this->getSelectSecurityIdentityIdSql($sid))->fetchColumn()) { return $id; } $this->connection->executeQuery($this->getInsertSecurityIdentitySql($sid)); return $this->connection->executeQuery($this->getSelectSecurityIdentityIdSql($sid))->fetchColumn(); } /** * Deletes all ACEs for the given object identity primary key. * * @param integer $oidPK * @return void */ private function deleteAccessControlEntries($oidPK) { $this->connection->executeQuery($this->getDeleteAccessControlEntriesSql($oidPK)); } /** * Deletes the object identity from the database. * * @param integer $pk * @return void */ private function deleteObjectIdentity($pk) { $this->connection->executeQuery($this->getDeleteObjectIdentitySql($pk)); } /** * Deletes all entries from the relations table from the database. * * @param integer $pk * @return void */ private function deleteObjectIdentityRelations($pk) { $this->connection->executeQuery($this->getDeleteObjectIdentityRelationsSql($pk)); } /** * This regenerates the ancestor table which is used for fast read access. * * @param AclInterface $acl * @return void */ private function regenerateAncestorRelations(AclInterface $acl) { $pk = $acl->getId(); $this->connection->executeQuery($this->getDeleteObjectIdentityRelationsSql($pk)); $this->connection->executeQuery($this->getInsertObjectIdentityRelationSql($pk, $pk)); $parentAcl = $acl->getParentAcl(); while (null !== $parentAcl) { $this->connection->executeQuery($this->getInsertObjectIdentityRelationSql($pk, $parentAcl->getId())); $parentAcl = $parentAcl->getParentAcl(); } } /** * This processes changes on an ACE related property (classFieldAces, or objectFieldAces). * * @param string $name * @param array $changes * @return void */ private function updateFieldAceProperty($name, array $changes) { $sids = new \SplObjectStorage(); $classIds = new \SplObjectStorage(); $currentIds = array(); foreach ($changes[1] as $field => $new) { for ($i=0,$c=count($new); $i<$c; $i++) { $ace = $new[$i]; if (null === $ace->getId()) { if ($sids->contains($ace->getSecurityIdentity())) { $sid = $sids->offsetGet($ace->getSecurityIdentity()); } else { $sid = $this->createOrRetrieveSecurityIdentityId($ace->getSecurityIdentity()); } $oid = $ace->getAcl()->getObjectIdentity(); if ($classIds->contains($oid)) { $classId = $classIds->offsetGet($oid); } else { $classId = $this->createOrRetrieveClassId($oid->getType()); } $objectIdentityId = $name === 'classFieldAces' ? null : $ace->getAcl()->getId(); $this->connection->executeQuery($this->getInsertAccessControlEntrySql($classId, $objectIdentityId, $field, $i, $sid, $ace->getStrategy(), $ace->getMask(), $ace->isGranting(), $ace->isAuditSuccess(), $ace->isAuditFailure())); $aceId = $this->connection->executeQuery($this->getSelectAccessControlEntryIdSql($classId, $objectIdentityId, $field, $i))->fetchColumn(); $this->loadedAces[$aceId] = $ace; $aceIdProperty = new \ReflectionProperty('Symfony\Component\Security\Acl\Domain\Entry', 'id'); $aceIdProperty->setAccessible(true); $aceIdProperty->setValue($ace, intval($aceId)); } else { $currentIds[$ace->getId()] = true; } } } foreach ($changes[0] as $old) { for ($i=0,$c=count($old); $i<$c; $i++) { $ace = $old[$i]; if (!isset($currentIds[$ace->getId()])) { $this->connection->executeQuery($this->getDeleteAccessControlEntrySql($ace->getId())); unset($this->loadedAces[$ace->getId()]); } } } } /** * This processes changes on an ACE related property (classAces, or objectAces). * * @param string $name * @param array $changes * @return void */ private function updateAceProperty($name, array $changes) { list($old, $new) = $changes; $sids = new \SplObjectStorage(); $classIds = new \SplObjectStorage(); $currentIds = array(); for ($i=0,$c=count($new); $i<$c; $i++) { $ace = $new[$i]; if (null === $ace->getId()) { if ($sids->contains($ace->getSecurityIdentity())) { $sid = $sids->offsetGet($ace->getSecurityIdentity()); } else { $sid = $this->createOrRetrieveSecurityIdentityId($ace->getSecurityIdentity()); } $oid = $ace->getAcl()->getObjectIdentity(); if ($classIds->contains($oid)) { $classId = $classIds->offsetGet($oid); } else { $classId = $this->createOrRetrieveClassId($oid->getType()); } $objectIdentityId = $name === 'classAces' ? null : $ace->getAcl()->getId(); $this->connection->executeQuery($this->getInsertAccessControlEntrySql($classId, $objectIdentityId, null, $i, $sid, $ace->getStrategy(), $ace->getMask(), $ace->isGranting(), $ace->isAuditSuccess(), $ace->isAuditFailure())); $aceId = $this->connection->executeQuery($this->getSelectAccessControlEntryIdSql($classId, $objectIdentityId, null, $i))->fetchColumn(); $this->loadedAces[$aceId] = $ace; $aceIdProperty = new \ReflectionProperty($ace, 'id'); $aceIdProperty->setAccessible(true); $aceIdProperty->setValue($ace, intval($aceId)); } else { $currentIds[$ace->getId()] = true; } } for ($i=0,$c=count($old); $i<$c; $i++) { $ace = $old[$i]; if (!isset($currentIds[$ace->getId()])) { $this->connection->executeQuery($this->getDeleteAccessControlEntrySql($ace->getId())); unset($this->loadedAces[$ace->getId()]); } } } /** * Persists the changes which were made to ACEs to the database. * * @param \SplObjectStorage $aces * @return void */ private function updateAces(\SplObjectStorage $aces) { foreach ($aces as $ace) { $propertyChanges = $aces->offsetGet($ace); $sets = array(); if (isset($propertyChanges['mask'])) { $sets[] = sprintf('mask = %d', $propertyChanges['mask'][1]); } if (isset($propertyChanges['strategy'])) { $sets[] = sprintf('granting_strategy = %s', $this->connection->quote($propertyChanges['strategy'])); } if (isset($propertyChanges['aceOrder'])) { $sets[] = sprintf('ace_order = %d', $propertyChanges['aceOrder'][1]); } if (isset($propertyChanges['auditSuccess'])) { $sets[] = sprintf('audit_success = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditSuccess'][1])); } if (isset($propertyChanges['auditFailure'])) { $sets[] = sprintf('audit_failure = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditFailure'][1])); } $this->connection->executeQuery($this->getUpdateAccessControlEntrySql($ace->getId(), $sets)); } } }tests/Doctrine/Tests/Common/Annotations/Fixtures/MultipleClassesInFile.php000064400000000371144760120550023033 0ustar00getMethod(); $time = microtime(true); for ($i=0,$c=500; $i<$c; $i++) { $reader->getMethodAnnotations($method); } $time = microtime(true) - $time; $this->printResults('cached reader (in-memory)', $time, $c); } /** * @group performance */ public function testCachedReadPerformanceWithFileCache() { $method = $this->getMethod(); // prime cache $reader = new FileCacheReader(new AnnotationReader(), sys_get_temp_dir()); $reader->getMethodAnnotations($method); $time = microtime(true); for ($i=0,$c=500; $i<$c; $i++) { $reader = new FileCacheReader(new AnnotationReader(), sys_get_temp_dir()); $reader->getMethodAnnotations($method); clearstatcache(); } $time = microtime(true) - $time; $this->printResults('cached reader (file)', $time, $c); } /** * @group performance */ public function testReadPerformance() { $reader = new AnnotationReader(); $method = $this->getMethod(); $time = microtime(true); for ($i=0,$c=150; $i<$c; $i++) { $reader = new AnnotationReader(); $reader->getMethodAnnotations($method); } $time = microtime(true) - $time; $this->printResults('reader', $time, $c); } /** * @group performance */ public function testDocParsePerformance() { $imports = array( 'ignorephpdoc' => 'Annotations\Annotation\IgnorePhpDoc', 'ignoreannotation' => 'Annotations\Annotation\IgnoreAnnotation', 'route' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Route', 'template' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Template', '__NAMESPACE__' => 'Doctrine\Tests\Common\Annotations\Fixtures', ); $ignored = array( 'access', 'author', 'copyright', 'deprecated', 'example', 'ignore', 'internal', 'link', 'see', 'since', 'tutorial', 'version', 'package', 'subpackage', 'name', 'global', 'param', 'return', 'staticvar', 'static', 'var', 'throws', 'inheritdoc', ); $parser = new DocParser(); $method = $this->getMethod(); $methodComment = $method->getDocComment(); $classComment = $method->getDeclaringClass()->getDocComment(); $time = microtime(true); for ($i=0,$c=200; $i<$c; $i++) { $parser = new DocParser(); $parser->setImports($imports); $parser->setIgnoredAnnotationNames($ignored); $parser->parse($methodComment); $parser->parse($classComment); } $time = microtime(true) - $time; $this->printResults('doc-parser', $time, $c); } /** * @group performance */ public function testDocLexerPerformance() { $lexer = new DocLexer(); $method = $this->getMethod(); $methodComment = $method->getDocComment(); $classComment = $method->getDeclaringClass()->getDocComment(); $time = microtime(true); for ($i=0,$c=500; $i<$c; $i++) { $lexer = new DocLexer(); $lexer->setInput($methodComment); $lexer->setInput($classComment); } $time = microtime(true) - $time; $this->printResults('doc-lexer', $time, $c); } private function getMethod() { return new \ReflectionMethod('Doctrine\Tests\Common\Annotations\Fixtures\Controller', 'helloAction'); } private function printResults($test, $time, $iterations) { if (0 == $iterations) { throw new \InvalidArgumentException('$iterations cannot be zero.'); } $title = $test." results:\n"; $iterationsText = sprintf("Iterations: %d\n", $iterations); $totalTime = sprintf("Total Time: %.3f s\n", $time); $iterationTime = sprintf("Time per iteration: %.3f ms\n", $time/$iterations * 1000); $max = max(strlen($title), strlen($iterationTime)) - 1; echo "\n".str_repeat('-', $max)."\n"; echo $title; echo str_repeat('=', $max)."\n"; echo $iterationsText; echo $totalTime; echo $iterationTime; echo str_repeat('-', $max)."\n"; } }tests/Doctrine/Tests/Common/Annotations/PhpParserTest.php000064400000004272144760120550017572 0ustar00assertEquals(array( 'route' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Route', 'secure' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Secure', ), $parser->parseClass($class)); } public function testParseClassWithMultipleImportsInUseStatement() { $class = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\MultipleImportsInUseStatement'); $parser = new PhpParser(); $this->assertEquals(array( 'route' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Route', 'secure' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Secure', ), $parser->parseClass($class)); } public function testParseClassWhenNotUserDefined() { $parser = new PhpParser(); $this->assertEquals(array(), $parser->parseClass(new \ReflectionClass('\stdClass'))); } public function testParseClassWhenClassIsNotNamespaced() { $parser = new PhpParser(); $class = new \ReflectionClass('\AnnotationsTestsFixturesNonNamespacedClass'); $this->assertEquals(array( 'route' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Route', 'template' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Template', ), $parser->parseClass($class)); } public function testParseClassWhenClassIsInterface() { $parser = new PhpParser(); $class = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\TestInterface'); $this->assertEquals(array( 'secure' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Secure', ), $parser->parseClass($class)); } }tests/Doctrine/Tests/Common/Annotations/Regression/BCAnnotationReaderTest.php000064400000022736144760120550023455 0ustar00createAnnotationReader(); $class = new ReflectionClass('Doctrine\Tests\Common\Annotations\Regression\DummyClass'); $classAnnots = $reader->getClassAnnotations($class); $annotName = 'Doctrine\Tests\Common\Annotations\DummyAnnotation'; $this->assertEquals(1, count($classAnnots)); $this->assertTrue($classAnnots[$annotName] instanceof \Doctrine\Tests\Common\Annotations\DummyAnnotation); // no use! $this->assertEquals("hello", $classAnnots[$annotName]->dummyValue); $field1Prop = $class->getProperty('field1'); $propAnnots = $reader->getPropertyAnnotations($field1Prop); $this->assertEquals(1, count($propAnnots)); $this->assertTrue($propAnnots[$annotName] instanceof \Doctrine\Tests\Common\Annotations\DummyAnnotation); // no use! $this->assertEquals("fieldHello", $propAnnots[$annotName]->dummyValue); $getField1Method = $class->getMethod('getField1'); $methodAnnots = $reader->getMethodAnnotations($getField1Method); $this->assertEquals(1, count($methodAnnots)); $this->assertTrue($methodAnnots[$annotName] instanceof \Doctrine\Tests\Common\Annotations\DummyAnnotation); // no use! $this->assertEquals(array(1, 2, "three"), $methodAnnots[$annotName]->value); $field2Prop = $class->getProperty('field2'); $propAnnots = $reader->getPropertyAnnotations($field2Prop); $this->assertEquals(1, count($propAnnots)); $this->assertTrue(isset($propAnnots['Doctrine\Tests\Common\Annotations\DummyJoinTable'])); $joinTableAnnot = $propAnnots['Doctrine\Tests\Common\Annotations\DummyJoinTable']; $this->assertEquals(1, count($joinTableAnnot->joinColumns)); $this->assertEquals(1, count($joinTableAnnot->inverseJoinColumns)); $this->assertTrue($joinTableAnnot->joinColumns[0] instanceof \Doctrine\Tests\Common\Annotations\DummyJoinColumn); // no use! $this->assertTrue($joinTableAnnot->inverseJoinColumns[0] instanceof \Doctrine\Tests\Common\Annotations\DummyJoinColumn); // no use! $this->assertEquals('col1', $joinTableAnnot->joinColumns[0]->name); $this->assertEquals('col2', $joinTableAnnot->joinColumns[0]->referencedColumnName); $this->assertEquals('col3', $joinTableAnnot->inverseJoinColumns[0]->name); $this->assertEquals('col4', $joinTableAnnot->inverseJoinColumns[0]->referencedColumnName); $dummyAnnot = $reader->getMethodAnnotation($class->getMethod('getField1'), 'Doctrine\Tests\Common\Annotations\DummyAnnotation'); $this->assertEquals('', $dummyAnnot->dummyValue); $this->assertEquals(array(1, 2, 'three'), $dummyAnnot->value); $dummyAnnot = $reader->getPropertyAnnotation($class->getProperty('field1'), 'Doctrine\Tests\Common\Annotations\DummyAnnotation'); $this->assertEquals('fieldHello', $dummyAnnot->dummyValue); $classAnnot = $reader->getClassAnnotation($class, 'Doctrine\Tests\Common\Annotations\DummyAnnotation'); $this->assertEquals('hello', $classAnnot->dummyValue); } /** * @group regression */ public function testMultipleAnnotationsOnSameLine() { $reader = $this->createAnnotationReader(); $class = new ReflectionClass('\Doctrine\Tests\Common\Annotations\Regression\DummyClass2'); $annotations = $reader->getPropertyAnnotations($class->getProperty('id')); $this->assertEquals(3, count($annotations)); } public function testCustomAnnotationCreationFunction() { $reader = $this->createAnnotationReader(); $reader->setAnnotationCreationFunction(function($name, $values) { if ($name == 'Doctrine\Tests\Common\Annotations\DummyAnnotation') { $a = new CustomDummyAnnotationClass; $a->setDummyValue($values['dummyValue']); return $a; } }); $class = new ReflectionClass('Doctrine\Tests\Common\Annotations\Regression\DummyClass'); $classAnnots = $reader->getClassAnnotations($class); $this->assertTrue(isset($classAnnots['Doctrine\Tests\Common\Annotations\Regression\CustomDummyAnnotationClass'])); $annot = $classAnnots['Doctrine\Tests\Common\Annotations\Regression\CustomDummyAnnotationClass']; $this->assertEquals('hello', $annot->getDummyValue()); } public function testNonAnnotationProblem() { $reader = $this->createAnnotationReader(); $class = new ReflectionClass('Doctrine\Tests\Common\Annotations\Regression\DummyClassNonAnnotationProblem'); $annotations = $reader->getPropertyAnnotations($class->getProperty('foo')); $this->assertArrayHasKey('Doctrine\Tests\Common\Annotations\DummyAnnotation', $annotations); $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\DummyAnnotation', $annotations['Doctrine\Tests\Common\Annotations\DummyAnnotation']); } /** * @return AnnotationReader */ public function createAnnotationReader() { $reader = new IndexedReader(new AnnotationReader(new \Doctrine\Common\Cache\ArrayCache)); $reader->setDefaultAnnotationNamespace('Doctrine\Tests\Common\Annotations\\'); $reader->setEnableParsePhpImports(false); return $reader; } public function testEmailAsAnnotation() { $reader = new AnnotationReader(new \Doctrine\Common\Cache\ArrayCache); $reader->setDefaultAnnotationNamespace('Doctrine\Tests\Common\Annotations\\'); $class = new ReflectionClass('Doctrine\Tests\Common\Annotations\Regression\DummyClassWithEmail'); $classAnnots = $reader->getClassAnnotations($class); $this->assertEquals(1, count($classAnnots)); } public function testNamespaceAliasedAnnotations() { $reader = new IndexedReader(new AnnotationReader(new \Doctrine\Common\Cache\ArrayCache)); $reader->setAnnotationNamespaceAlias('Doctrine\Tests\Common\Annotations\\', 'alias'); $reflClass = new ReflectionClass('Doctrine\Tests\Common\Annotations\Regression\AliasNamespace'); $result = $reader->getPropertyAnnotations($reflClass->getProperty('bar')); $this->assertEquals(1, count($result)); $annot = $result['Doctrine\Tests\Common\Annotations\Name']; $this->assertTrue($annot instanceof \Doctrine\Tests\Common\Annotations\Name); // no use! $this->assertEquals('bar', $annot->foo); } /** * @group DCOM-4 */ public function testNamespaceAliasAnnotationWithSeparator() { $reader = new IndexedReader(new AnnotationReader(new \Doctrine\Common\Cache\ArrayCache)); $reader->setAnnotationNamespaceAlias('Doctrine\Tests\Common\\', 'alias'); $reflClass = new ReflectionClass('Doctrine\Tests\Common\Annotations\Regression\AliasNamespace'); $result = $reader->getPropertyAnnotations($reflClass->getProperty('foo')); $this->assertEquals(1, count($result)); $annot = $result['Doctrine\Tests\Common\Annotations\Name']; $this->assertTrue($annot instanceof \Doctrine\Tests\Common\Annotations\Name); // no use! $this->assertEquals('bar', $annot->foo); } } class CustomDummyAnnotationClass { private $dummyValue; public function setDummyValue($value) { $this->dummyValue = $value; } public function getDummyValue() { return $this->dummyValue; } } class AliasNamespace { /** * @alias:Name(foo="bar") */ public $bar; /** * @alias:Annotations\Name(foo="bar") */ public $foo; } /** * A description of this class. * * Let's see if the parser recognizes that this @ is not really referring to an * annotation. Also make sure that @var \ is not concated to "@var\is". * * Copy of the class one namespace up to avoid matches against __NAMESPACE__ * * @author robo * @since 2.0 * @DummyAnnotation(dummyValue="hello") */ class DummyClass { /** * A nice property. * * @var mixed * @DummyAnnotation(dummyValue="fieldHello") */ private $field1; /** * @DummyJoinTable(name="join_table", * joinColumns={@DummyJoinColumn(name="col1", referencedColumnName="col2")}, * inverseJoinColumns={ * @DummyJoinColumn(name="col3", referencedColumnName="col4") * }) */ private $field2; /** * Gets the value of field1. * * @return mixed * @DummyAnnotation({1,2,"three"}) */ public function getField1() { } } /** * @ignoreAnnotation("var") */ class DummyClass2 { /** * @DummyId @DummyColumn(type="integer") @DummyGeneratedValue * @var integer */ private $id; } /** * @ignoreAnnotation({"since", "var"}) */ class DummyClassNonAnnotationProblem { /** * @DummyAnnotation * * @var \Test * @since 0.1 */ public $foo; } /** * @DummyAnnotation Foo bar */ class DummyClassWithEmail { }tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM55Test.php000064400000003024144760120550017777 0ustar00getClassAnnotations($class); $this->assertEquals(0, count($annots)); } public function testAnnotation() { $class = new \ReflectionClass(__NAMESPACE__ . '\\DCOM55Consumer'); $reader = new \Doctrine\Common\Annotations\AnnotationReader(); $annots = $reader->getClassAnnotations($class); $this->assertEquals(1, count($annots)); $this->assertInstanceOf(__NAMESPACE__.'\\DCOM55Annotation', $annots[0]); } public function testParseAnnotationDocblocks() { $class = new \ReflectionClass(__NAMESPACE__ . '\\DCOM55Annotation'); $reader = new \Doctrine\Common\Annotations\AnnotationReader(); $annots = $reader->getClassAnnotations($class); $this->assertEquals(0, count($annots)); } } /** * @Controller */ class Dummy { } /** * @Annotation */ class DCOM55Annotation { } /** * @DCOM55Annotation */ class DCOM55Consumer { }tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM58Entity.php000064400000000141144760120550020334 0ustar00getClassAnnotations(new \ReflectionClass(__NAMESPACE__."\MappedClass")); foreach ($result as $annot) { $classAnnotations[get_class($annot)] = $annot; } // Evaluate Entity annotation if (!isset($classAnnotations['Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping\Entity'])) { throw new \RuntimeException('Class "xxx" is not a valid entity or mapped super class.'); } } public function testIssueGlobalNamespace() { $docblock = "@Entity"; $parser = new \Doctrine\Common\Annotations\DocParser(); $parser->setImports(array( "__NAMESPACE__" =>"Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping" )); $annots = $parser->parse($docblock); $this->assertEquals(1, count($annots)); $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping\Entity", $annots[0]); } } /** * @Entity */ class MappedClass { } namespace Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping; /** * @Annotation */ class Entity { } namespace Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM; /** * @Annotation */ class Entity { } tests/Doctrine/Tests/Common/Annotations/TopLevelAnnotation.php000064400000000144144760120550020605 0ustar00markTestSkipped('The ' . __CLASS__ .' requires the use of APC'); } } protected function _getCacheDriver() { return new ApcCache(); } }tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php000064400000000326144760120550016372 0ustar00_getCacheDriver(); // Test save $cache->save('test_key', 'testing this out'); // Test contains to test that save() worked $this->assertTrue($cache->contains('test_key')); // Test fetch $this->assertEquals('testing this out', $cache->fetch('test_key')); // Test delete $cache->save('test_key2', 'test2'); $cache->delete('test_key2'); $this->assertFalse($cache->contains('test_key2')); } public function testDeleteAll() { $cache = $this->_getCacheDriver(); $cache->save('test_key1', '1'); $cache->save('test_key2', '2'); $cache->deleteAll(); $this->assertFalse($cache->contains('test_key1')); $this->assertFalse($cache->contains('test_key2')); } public function testDeleteByRegex() { $cache = $this->_getCacheDriver(); $cache->save('test_key1', '1'); $cache->save('test_key2', '2'); $cache->deleteByRegex('/test_key[0-9]/'); $this->assertFalse($cache->contains('test_key1')); $this->assertFalse($cache->contains('test_key2')); } public function testDeleteByPrefix() { $cache = $this->_getCacheDriver(); $cache->save('test_key1', '1'); $cache->save('test_key2', '2'); $cache->deleteByPrefix('test_key'); $this->assertFalse($cache->contains('test_key1')); $this->assertFalse($cache->contains('test_key2')); } public function testDeleteBySuffix() { $cache = $this->_getCacheDriver(); $cache->save('1test_key', '1'); $cache->save('2test_key', '2'); $cache->deleteBySuffix('test_key'); $this->assertFalse($cache->contains('1test_key')); $this->assertFalse($cache->contains('2test_key')); } public function testDeleteByWildcard() { $cache = $this->_getCacheDriver(); $cache->save('test_key1', '1'); $cache->save('test_key2', '2'); $cache->delete('test_key*'); $this->assertFalse($cache->contains('test_key1')); $this->assertFalse($cache->contains('test_key2')); } public function testNamespace() { $cache = $this->_getCacheDriver(); $cache->setNamespace('test_'); $cache->save('key1', 'test'); $this->assertTrue($cache->contains('key1')); $ids = $cache->getIds(); $this->assertTrue(in_array('test_key1', $ids)); } abstract protected function _getCacheDriver(); }tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php000064400000001377144760120550017025 0ustar00_memcache = new \Memcache; $ok = @$this->_memcache->connect('localhost', 11211); if (!$ok) { $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); } } else { $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); } } protected function _getCacheDriver() { $driver = new MemcacheCache(); $driver->setMemcache($this->_memcache); return $driver; } }tests/Doctrine/Tests/Common/Cache/XcacheCacheTest.php000064400000000620144760120550016504 0ustar00markTestSkipped('The ' . __CLASS__ .' requires the use of xcache'); } } protected function _getCacheDriver() { return new XcacheCache(); } }tests/Doctrine/Tests/Common/Cache/ZendDataCacheTest.php000064400000002137144760120550017010 0ustar00markTestSkipped('The ' . __CLASS__ .' requires the use of Zend Data Cache which only works in apache2handler SAPI'); } } protected function _getCacheDriver() { return new ZendDataCache(); } public function testBasics() { $cache = $this->_getCacheDriver(); // Test save $cache->save('test_key', 'testing this out'); // Test contains to test that save() worked $this->assertTrue($cache->contains('test_key')); // Test fetch $this->assertEquals('testing this out', $cache->fetch('test_key')); // Test delete $cache->save('test_key2', 'test2'); $cache->delete('test_key2'); $this->assertFalse($cache->contains('test_key2')); } }tests/Doctrine/Tests/Common/ClassLoaderTest.php000064400000003371144760120550015564 0ustar00setIncludePath(__DIR__); $classLoader->setFileExtension('.class.php'); $classLoader->setNamespaceSeparator('_'); $this->assertTrue($classLoader->canLoadClass('ClassLoaderTest_ClassA')); $this->assertTrue($classLoader->canLoadClass('ClassLoaderTest_ClassB')); $this->assertTrue($classLoader->canLoadClass('ClassLoaderTest_ClassC')); $this->assertFalse($classLoader->canLoadClass('OtherClass')); $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassA'), true); $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassB'), true); $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassC'), true); } public function testClassExists() { $this->assertFalse(ClassLoader::classExists('ClassLoaderTest\ClassD')); $badLoader = function($className) { require __DIR__ . '/ClassLoaderTest/ClassD.php'; return true; }; spl_autoload_register($badLoader); $this->assertTrue(ClassLoader::classExists('ClassLoaderTest\ClassD')); spl_autoload_unregister($badLoader); } public function testGetClassLoader() { $cl = new ClassLoader('ClassLoaderTest', __DIR__); $cl->register(); $this->assertTrue(ClassLoader::getClassLoader('ClassLoaderTest\ClassD') instanceof \Doctrine\Common\ClassLoader); $this->assertNull(ClassLoader::getClassLoader('This\Class\Does\Not\Exist')); $cl->unregister(); } } tests/Doctrine/Tests/Common/ClassLoaderTest/ClassA.class.php000064400000000054144760120550020031 0ustar00_coll = new \Doctrine\Common\Collections\ArrayCollection; } public function testIssetAndUnset() { $this->assertFalse(isset($this->_coll[0])); $this->_coll->add('testing'); $this->assertTrue(isset($this->_coll[0])); unset($this->_coll[0]); $this->assertFalse(isset($this->_coll[0])); } public function testToString() { $this->_coll->add('testing'); $this->assertTrue(is_string((string) $this->_coll)); } public function testRemovingNonExistentEntryReturnsNull() { $this->assertEquals(null, $this->_coll->remove('testing_does_not_exist')); } public function testExists() { $this->_coll->add("one"); $this->_coll->add("two"); $exists = $this->_coll->exists(function($k, $e) { return $e == "one"; }); $this->assertTrue($exists); $exists = $this->_coll->exists(function($k, $e) { return $e == "other"; }); $this->assertFalse($exists); } public function testMap() { $this->_coll->add(1); $this->_coll->add(2); $res = $this->_coll->map(function($e) { return $e * 2; }); $this->assertEquals(array(2, 4), $res->toArray()); } public function testFilter() { $this->_coll->add(1); $this->_coll->add("foo"); $this->_coll->add(3); $res = $this->_coll->filter(function($e) { return is_numeric($e); }); $this->assertEquals(array(0 => 1, 2 => 3), $res->toArray()); } public function testFirstAndLast() { $this->_coll->add('one'); $this->_coll->add('two'); $this->assertEquals($this->_coll->first(), 'one'); $this->assertEquals($this->_coll->last(), 'two'); } public function testArrayAccess() { $this->_coll[] = 'one'; $this->_coll[] = 'two'; $this->assertEquals($this->_coll[0], 'one'); $this->assertEquals($this->_coll[1], 'two'); unset($this->_coll[0]); $this->assertEquals($this->_coll->count(), 1); } public function testContainsKey() { $this->_coll[5] = 'five'; $this->assertTrue($this->_coll->containsKey(5)); } public function testContains() { $this->_coll[0] = 'test'; $this->assertTrue($this->_coll->contains('test')); } public function testSearch() { $this->_coll[0] = 'test'; $this->assertEquals(0, $this->_coll->indexOf('test')); } public function testGet() { $this->_coll[0] = 'test'; $this->assertEquals('test', $this->_coll->get(0)); } public function testGetKeys() { $this->_coll[] = 'one'; $this->_coll[] = 'two'; $this->assertEquals(array(0, 1), $this->_coll->getKeys()); } public function testGetValues() { $this->_coll[] = 'one'; $this->_coll[] = 'two'; $this->assertEquals(array('one', 'two'), $this->_coll->getValues()); } public function testCount() { $this->_coll[] = 'one'; $this->_coll[] = 'two'; $this->assertEquals($this->_coll->count(), 2); $this->assertEquals(count($this->_coll), 2); } public function testForAll() { $this->_coll[] = 'one'; $this->_coll[] = 'two'; $this->assertEquals($this->_coll->forAll(function($k, $e) { return is_string($e); }), true); $this->assertEquals($this->_coll->forAll(function($k, $e) { return is_array($e); }), false); } public function testPartition() { $this->_coll[] = true; $this->_coll[] = false; $partition = $this->_coll->partition(function($k, $e) { return $e == true; }); $this->assertEquals($partition[0][0], true); $this->assertEquals($partition[1][0], false); } public function testClear() { $this->_coll[] = 'one'; $this->_coll[] = 'two'; $this->_coll->clear(); $this->assertEquals($this->_coll->isEmpty(), true); } public function testRemove() { $this->_coll[] = 'one'; $this->_coll[] = 'two'; $el = $this->_coll->remove(0); $this->assertEquals('one', $el); $this->assertEquals($this->_coll->contains('one'), false); $this->assertNull($this->_coll->remove(0)); } public function testRemoveElement() { $this->_coll[] = 'one'; $this->_coll[] = 'two'; $this->assertTrue($this->_coll->removeElement('two')); $this->assertFalse($this->_coll->contains('two')); $this->assertFalse($this->_coll->removeElement('two')); } public function testSlice() { $this->_coll[] = 'one'; $this->_coll[] = 'two'; $this->_coll[] = 'three'; $slice = $this->_coll->slice(0, 1); $this->assertInternalType('array', $slice); $this->assertEquals(array('one'), $slice); $slice = $this->_coll->slice(1); $this->assertEquals(array(1 => 'two', 2 => 'three'), $slice); $slice = $this->_coll->slice(1, 1); $this->assertEquals(array(1 => 'two'), $slice); } }tests/Doctrine/Tests/Common/DoctrineExceptionTest.php000064400000000000144760120550017000 0ustar00tests/Doctrine/Tests/Common/EventManagerTest.php000064400000005376144760120550015753 0ustar00_eventManager = new EventManager; $this->_preFooInvoked = false; $this->_postFooInvoked = false; } public function testInitialState() { $this->assertEquals(array(), $this->_eventManager->getListeners()); $this->assertFalse($this->_eventManager->hasListeners(self::preFoo)); $this->assertFalse($this->_eventManager->hasListeners(self::postFoo)); } public function testAddEventListener() { $this->_eventManager->addEventListener(array('preFoo', 'postFoo'), $this); $this->assertTrue($this->_eventManager->hasListeners(self::preFoo)); $this->assertTrue($this->_eventManager->hasListeners(self::postFoo)); $this->assertEquals(1, count($this->_eventManager->getListeners(self::preFoo))); $this->assertEquals(1, count($this->_eventManager->getListeners(self::postFoo))); $this->assertEquals(2, count($this->_eventManager->getListeners())); } public function testDispatchEvent() { $this->_eventManager->addEventListener(array('preFoo', 'postFoo'), $this); $this->_eventManager->dispatchEvent(self::preFoo); $this->assertTrue($this->_preFooInvoked); $this->assertFalse($this->_postFooInvoked); } public function testRemoveEventListener() { $this->_eventManager->addEventListener(array('preBar'), $this); $this->assertTrue($this->_eventManager->hasListeners(self::preBar)); $this->_eventManager->removeEventListener(array('preBar'), $this); $this->assertFalse($this->_eventManager->hasListeners(self::preBar)); } public function testAddEventSubscriber() { $eventSubscriber = new TestEventSubscriber(); $this->_eventManager->addEventSubscriber($eventSubscriber); $this->assertTrue($this->_eventManager->hasListeners(self::preFoo)); $this->assertTrue($this->_eventManager->hasListeners(self::postFoo)); } /* Listener methods */ public function preFoo(EventArgs $e) { $this->_preFooInvoked = true; } public function postFoo(EventArgs $e) { $this->_postFooInvoked = true; } } class TestEventSubscriber implements \Doctrine\Common\EventSubscriber { public function getSubscribedEvents() { return array('preFoo', 'postFoo'); } }tests/Doctrine/Tests/DoctrineTestCase.php000064400000000244144760120550014477 0ustar00 */ class NativePhpunitTask extends Task { private $test; private $testfile; private $testdirectory; private $configuration = null; private $coverageClover = null; private $junitlogfile = null; private $haltonfailure = true; private $haltonerror = true; public function setTestdirectory($directory) { $this->testdirectory = $directory; } public function setTest($test) { $this->test = $test; } public function setTestfile($testfile) { $this->testfile = $testfile; } public function setJunitlogfile($junitlogfile) { if (strlen($junitlogfile) == 0) { $junitlogfile = NULL; } $this->junitlogfile = $junitlogfile; } public function setConfiguration($configuration) { if (strlen($configuration) == 0) { $configuration = NULL; } $this->configuration = $configuration; } public function setCoverageClover($coverageClover) { if (strlen($coverageClover) == 0) { $coverageClover = NULL; } $this->coverageClover = $coverageClover; } public function setHaltonfailure($haltonfailures) { $this->haltonfailure = $haltonfailures; } public function setHaltonerror($haltonerrors) { $this->haltonerror = $haltonerrors; } public function init() { require_once "PHPUnit/Runner/Version.php"; $version = PHPUnit_Runner_Version::id(); if (version_compare($version, '3.4.0') < 0) { throw new BuildException("NativePHPUnitTask requires PHPUnit version >= 3.2.0", $this->getLocation()); } require_once 'PHPUnit/Util/Filter.php'; // point PHPUnit_MAIN_METHOD define to non-existing method if (!defined('PHPUnit_MAIN_METHOD')) { define('PHPUnit_MAIN_METHOD', 'PHPUnitTask::undefined'); } } public function main() { if (!is_dir(realpath($this->testdirectory))) { throw new BuildException("NativePHPUnitTask requires a Test Directory path given, '".$this->testdirectory."' given."); } set_include_path(realpath($this->testdirectory) . PATH_SEPARATOR . get_include_path()); $printer = new NativePhpunitPrinter(); $arguments = array( 'configuration' => $this->configuration, 'coverageClover' => $this->coverageClover, 'junitLogfile' => $this->junitlogfile, 'printer' => $printer, ); $runner = new PHPUnit_TextUI_TestRunner(); $suite = $runner->getTest($this->test, $this->testfile, true); try { $result = $runner->doRun($suite, $arguments); /* @var $result PHPUnit_Framework_TestResult */ if ( ($this->haltonfailure && $result->failureCount() > 0) || ($this->haltonerror && $result->errorCount() > 0) ) { throw new BuildException("PHPUnit: ".$result->failureCount()." Failures and ".$result->errorCount()." Errors, ". "last failure message: ".$printer->getMessages()); } $this->log("PHPUnit Success: ".count($result->passed())." tests passed, no ". "failures (".$result->skippedCount()." skipped, ".$result->notImplementedCount()." not implemented)"); // Hudson for example doesn't like the backslash in class names if (file_exists($this->coverageClover)) { $this->log("Generated Clover Coverage XML to: ".$this->coverageClover); $content = file_get_contents($this->coverageClover); $content = str_replace("\\", ".", $content); file_put_contents($this->coverageClover, $content); unset($content); } } catch(\Exception $e) { throw new BuildException("NativePhpunitTask failed: ".$e->getMessage()); } } } class NativePhpunitPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener { private $_messages = array(); public function write($buffer) { // do nothing } public function getMessages() { return $this->_messages; } /** * An error occurred. * * @param PHPUnit_Framework_Test $test * @param Exception $e * @param float $time */ public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) { $this->_messages[] = "Test ERROR: ".$test->getName().": ".$e->getMessage(); } /** * A failure occurred. * * @param PHPUnit_Framework_Test $test * @param PHPUnit_Framework_AssertionFailedError $e * @param float $time */ public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) { $this->_messages[] = "Test FAILED: ".$test->getName().": ".$e->getMessage(); } /** * Incomplete test. * * @param PHPUnit_Framework_Test $test * @param Exception $e * @param float $time */ public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) { } /** * Skipped test. * * @param PHPUnit_Framework_Test $test * @param Exception $e * @param float $time * @since Method available since Release 3.0.0 */ public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) { } /** * A test suite started. * * @param PHPUnit_Framework_TestSuite $suite * @since Method available since Release 2.2.0 */ public function startTestSuite(PHPUnit_Framework_TestSuite $suite) { } /** * A test suite ended. * * @param PHPUnit_Framework_TestSuite $suite * @since Method available since Release 2.2.0 */ public function endTestSuite(PHPUnit_Framework_TestSuite $suite) { } /** * A test started. * * @param PHPUnit_Framework_Test $test */ public function startTest(PHPUnit_Framework_Test $test) { } /** * A test ended. * * @param PHPUnit_Framework_Test $test * @param float $time */ public function endTest(PHPUnit_Framework_Test $test, $time) { } } tests/README.markdown000064400000001523144760120550010414 0ustar00# Running the Doctrine 2 Testsuite ## Running tests Execute PHPUnit in the root folder of your doctrine-common clone. phpunit ## Testing Lock-Support The Lock support in Doctrine 2 is tested using Gearman, which allows to run concurrent tasks in parallel. Install Gearman with PHP as follows: 1. Go to http://www.gearman.org and download the latest Gearman Server 2. Compile it and then call ldconfig 3. Start it up "gearmand -vvvv" 4. Install pecl/gearman by calling "gearman-beta" You can then go into tests/ and start up two workers: php Doctrine/Tests/ORM/Functional/Locking/LockAgentWorker.php Then run the locking test-suite: phpunit --configuration Doctrine/Tests/ORM/Functional/Locking/GearmanLockTest.php This can run considerable time, because it is using sleep() to test for the timing ranges of locks.