Kaynağa Gözat

Updating vendor

Julio Montoya 12 yıl önce
ebeveyn
işleme
32682a9ca8
100 değiştirilmiş dosya ile 11878 ekleme ve 161 silme
  1. 9 15
      vendor/dflydev/doctrine-orm-service-provider/.travis.yml
  2. 1 1
      vendor/dflydev/doctrine-orm-service-provider/composer.json
  3. 4 1
      vendor/dflydev/doctrine-orm-service-provider/src/Dflydev/Silex/Provider/DoctrineOrm/DoctrineOrmServiceProvider.php
  4. 3 1
      vendor/doctrine/common/LICENSE
  5. 139 0
      vendor/doctrine/common/composer.lock
  6. 5 1
      vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation.php
  7. 1 7
      vendor/doctrine/common/lib/Doctrine/Common/Collections/ArrayCollection.php
  8. 22 31
      vendor/doctrine/common/lib/Doctrine/Common/Collections/Collection.php
  9. 1 1
      vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/StaticReflectionService.php
  10. 93 0
      vendor/doctrine/common/lib/Doctrine/Common/PropertyChangedListener.php
  11. 81 0
      vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/InvalidArgumentException.php
  12. 31 0
      vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/ProxyException.php
  13. 61 0
      vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/UnexpectedValueException.php
  14. 83 0
      vendor/doctrine/common/lib/Doctrine/Common/Proxy/Proxy.php
  15. 921 0
      vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyGenerator.php
  16. 76 0
      vendor/doctrine/common/lib/Doctrine/Common/Reflection/ClassFinderInterface.php
  17. 5 45
      vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionClass.php
  18. 1 4
      vendor/doctrine/common/lib/Doctrine/Common/Version.php
  19. 19 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NamespacedSingleClassLOC1000.php
  20. 5 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest/ClassA.class.php
  21. 8 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/ClosureExpressionVisitorTest.php
  22. 72 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticPHPDriverTest.php
  23. 16 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/InvalidTypeHintClass.php
  24. 115 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/LazyLoadableObject.php
  25. 195 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/LazyLoadableObjectClassMetadata.php
  26. 161 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/ProxyClassGeneratorTest.php
  27. 696 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/ProxyLogicTest.php
  28. 19 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/SleepClass.php
  29. 192 0
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/DeeperNamespaceParent.php
  30. 2 7
      vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/SameNamespaceParent.php
  31. 3 2
      vendor/doctrine/common/tests/NativePhpunitTask.php
  32. 3 21
      vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php
  33. 1 0
      vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php
  34. 8 0
      vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php
  35. 13 0
      vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Connection.php
  36. 32 0
      vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php
  37. 18 1
      vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/LoggingTest.php
  38. 8 6
      vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php
  39. 16 1
      vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php
  40. 14 0
      vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php
  41. 1 1
      vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php
  42. 2 2
      vendor/doctrine/migrations/lib/Doctrine/DBAL/Migrations/Tools/Console/Command/ExecuteCommand.php
  43. 8 0
      vendor/doctrine/migrations/lib/Doctrine/DBAL/Migrations/Tools/Console/Command/MigrateCommand.php
  44. 1 1
      vendor/doctrine/orm/bin/doctrine-pear.php
  45. 21 2
      vendor/doctrine/orm/doctrine-mapping.xsd
  46. 12 0
      vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Proxy.php
  47. 9 2
      vendor/doctrine/orm/lib/Doctrine/ORM/Query/Lexer.php
  48. 19 8
      vendor/doctrine/orm/lib/Doctrine/ORM/README.markdown
  49. 42 0
      vendor/doctrine/orm/lib/Doctrine/ORM/Version.php
  50. 20 0
      vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/HydrationCacheTest.php
  51. 13 0
      vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/CompanySchemaTest.php
  52. 17 0
      vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommandTest.php
  53. 21 0
      vendor/gedmo/doctrine-extensions/LICENSE
  54. 173 0
      vendor/gedmo/doctrine-extensions/README.md
  55. 31 0
      vendor/gedmo/doctrine-extensions/bin/clear_temp.php
  56. 48 0
      vendor/gedmo/doctrine-extensions/bin/purify.php
  57. 51 0
      vendor/gedmo/doctrine-extensions/composer.json
  58. 569 0
      vendor/gedmo/doctrine-extensions/doc/annotations.md
  59. 523 0
      vendor/gedmo/doctrine-extensions/doc/blameable.md
  60. 266 0
      vendor/gedmo/doctrine-extensions/doc/loggable.md
  61. 494 0
      vendor/gedmo/doctrine-extensions/doc/mapping.md
  62. 755 0
      vendor/gedmo/doctrine-extensions/doc/sluggable.md
  63. 215 0
      vendor/gedmo/doctrine-extensions/doc/softdeleteable.md
  64. 279 0
      vendor/gedmo/doctrine-extensions/doc/sortable.md
  65. 438 0
      vendor/gedmo/doctrine-extensions/doc/symfony2.md
  66. 623 0
      vendor/gedmo/doctrine-extensions/doc/timestampable.md
  67. 898 0
      vendor/gedmo/doctrine-extensions/doc/translatable.md
  68. 1203 0
      vendor/gedmo/doctrine-extensions/doc/tree.md
  69. 450 0
      vendor/gedmo/doctrine-extensions/doc/uploadable.md
  70. 219 0
      vendor/gedmo/doctrine-extensions/example/app/Entity/Category.php
  71. 37 0
      vendor/gedmo/doctrine-extensions/example/app/Entity/CategoryTranslation.php
  72. 10 0
      vendor/gedmo/doctrine-extensions/example/app/Entity/Repository/CategoryRepository.php
  73. 6 0
      vendor/gedmo/doctrine-extensions/example/bin/console
  74. 40 0
      vendor/gedmo/doctrine-extensions/example/bin/console.php
  75. 123 0
      vendor/gedmo/doctrine-extensions/example/em.php
  76. 80 0
      vendor/gedmo/doctrine-extensions/example/run.php
  77. 48 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Blameable.php
  78. 94 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/BlameableListener.php
  79. 86 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Driver/Annotation.php
  80. 92 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Driver/Xml.php
  81. 93 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Driver/Yaml.php
  82. 20 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Event/Adapter/ODM.php
  83. 21 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Event/Adapter/ORM.php
  84. 19 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Event/BlameableAdapter.php
  85. 73 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Traits/BlameableDocument.php
  86. 73 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Traits/BlameableEntity.php
  87. 130 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/DoctrineExtensions.php
  88. 24 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception.php
  89. 19 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/BadMethodCallException.php
  90. 20 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/FeatureNotImplementedException.php
  91. 19 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/InvalidArgumentException.php
  92. 22 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/InvalidMappingException.php
  93. 19 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/RuntimeException.php
  94. 18 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/TreeLockingException.php
  95. 19 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UnexpectedValueException.php
  96. 19 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UnsupportedObjectManagerException.php
  97. 20 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UploadableCantWriteException.php
  98. 20 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UploadableCouldntGuessMimeTypeException.php
  99. 20 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UploadableDirectoryNotFoundException.php
  100. 20 0
      vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UploadableException.php

+ 9 - 15
vendor/dflydev/doctrine-orm-service-provider/.travis.yml

@@ -96,7 +96,7 @@ $container["orm.em.options"] = array(
         // (requires registering a PSR-0 Resource Locator
         // Service Provider)
         array(
-            "type" => "annotations",
+            "type" => "annotation",
             "namespace" => "Baz\Entities",
             "resources_namespace" => "Baz\Entities",
         ),
@@ -149,7 +149,7 @@ $app->register(new DoctrineOrmServiceProvider, array(
             // (requires registering a PSR-0 Resource Locator
             // Service Provider)
             array(
-                "type" => "annotations",
+                "type" => "annotation",
                 "namespace" => "Baz\Entities",
                 "resources_namespace" => "Baz\Entities",
             ),
@@ -193,10 +193,9 @@ Configuration
    Array of Entity Manager options.
 
    These options are available:
-   * **connection**:
+   * **connection** (Default: default):
      String defining which database connection to use. Used when using
      named databases via **dbs**.
-     *Default: default*
    * **mappings**:
      Array of mapping definitions.
 
@@ -213,7 +212,7 @@ Configuration
        files are located. Example: `Path\To\Foo\Resources\mappings`
 
      Each **annotation** mapping may also specify the following options:
-     * **use_simple_annotation_reader**:
+     * **use_simple_annotation_reader** (Default: true):
        If `true`, only simple notations like `@Entity` will work.
        If `false`, more advanced notations and aliasing via `use` will
        work. (Example: `use Doctrine\ORM\Mapping AS ORM`, `@ORM\Entity`)
@@ -221,15 +220,12 @@ Configuration
        need to be configured correctly so that it can load your Annotations
        classes. See this FAQ:
        [Why aren't my Annotations classes being found?](#why-arent-my-annotations-classes-being-found)
-   * **query_cache**:
+   * **query_cache** (Default: setting specified by orm.default_cache):
      String or array describing query cache implementation.
-     *Default: setting specified by orm.default_cache*
-   * **metadata_cache**:
+   * **metadata_cache** (Default: setting specified by orm.default_cache):
      String or array describing metadata cache implementation.
-     *Default: setting specified by orm.default_cache*
-   * **result_cache**:
+   * **result_cache** (Default: setting specified by orm.default_cache):
      String or array describing result cache implementation.
-     *Default: setting specified by orm.default_cache*
  * **orm.ems.options**:
    Array of Entity Manager configuration sets indexed by each Entity Manager's
    name. Each value should look like **orm.em.options**.
@@ -258,14 +254,12 @@ Configuration
    $emMysql = $app['orm.ems']['mysql'];
    $emSqlite = $app['orm.ems']['sqlite'];
    ```
- * **orm.ems.default**:
+ * **orm.ems.default** (Default: first Entity Manager processed):
    String defining the name of the default Entity Manager.
-   *Default: first Entity Manager processed*
  * **orm.proxies_dir**:
    String defining path to where Doctrine generated proxies should be located.
- * **orm.proxies_namespace**:
+ * **orm.proxies_namespace** (Default: DoctrineProxy):
    String defining namespace in which Doctrine generated proxies should reside.
-   *Default: DoctrineProxy*
  * **orm.auto_generate_proxies**:
    Boolean defining whether or not proxies should be generated automatically.
  * **orm.default_cache**:

+ 1 - 1
vendor/dflydev/doctrine-orm-service-provider/composer.json

@@ -213,7 +213,7 @@ class DoctrineOrmServiceProvider
             $memcached->addServer($cacheOptions['host'], $cacheOptions['port']);
 
             $cache = new MemcachedCache;
-            $cache->setMemcached($memcache);
+            $cache->setMemcached($memcached);
 
             return $cache;
         });

+ 4 - 1
vendor/dflydev/doctrine-orm-service-provider/src/Dflydev/Silex/Provider/DoctrineOrm/DoctrineOrmServiceProvider.php

@@ -4,7 +4,10 @@ env:
   - OPCODE_CACHE=apc
 
 php:
+  - 5.3.3
   - 5.3
   - 5.4
 
-before_script: php ./bin/travis-setup.php $OPCODE_CACHE
+before_script:
+    - composer --prefer-source --dev install
+    - php ./bin/travis-setup.php $OPCODE_CACHE

+ 3 - 1
vendor/doctrine/common/LICENSE

@@ -13,7 +13,9 @@
         {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
     ],
     "require": {
-        "php": ">=5.3.2"
+        "php": ">=5.3.2",
+        "doctrine/inflector": "1.*",
+        "doctrine/cache": "1.*"
     },
     "autoload": {
         "psr-0": { "Doctrine\\Common\\": "lib/" }

+ 139 - 0
vendor/doctrine/common/composer.lock

@@ -0,0 +1,139 @@
+{
+    "hash": "369123de393e5e6f84fc0ebfd00adaac",
+    "packages": [
+        {
+            "name": "doctrine/cache",
+            "version": "v1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/cache.git",
+                "reference": "v1.0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/doctrine/cache/archive/v1.0.zip",
+                "reference": "v1.0",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "time": "2013-01-10 22:43:46",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\Cache\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com",
+                    "homepage": "http://www.jwage.com/"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com",
+                    "homepage": "https://github.com/schmittjoh",
+                    "role": "Developer of wrapped JMSSerializerBundle"
+                }
+            ],
+            "description": "Caching library offering an object-oriented API for many cache backends",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "cache",
+                "caching"
+            ]
+        },
+        {
+            "name": "doctrine/inflector",
+            "version": "v1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/inflector.git",
+                "reference": "v1.0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/doctrine/inflector/archive/v1.0.zip",
+                "reference": "v1.0",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "time": "2013-01-10 21:49:15",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\Inflector\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com",
+                    "homepage": "http://www.jwage.com/"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com",
+                    "homepage": "http://www.instaclick.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com",
+                    "homepage": "https://github.com/schmittjoh",
+                    "role": "Developer of wrapped JMSSerializerBundle"
+                }
+            ],
+            "description": "Common String Manipulations with regard to casing and singular/plural rules.",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "string",
+                "inflection",
+                "singuarlize",
+                "pluarlize"
+            ]
+        }
+    ],
+    "packages-dev": null,
+    "aliases": [
+
+    ],
+    "minimum-stability": "stable",
+    "stability-flags": [
+
+    ]
+}

+ 5 - 1
vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation.php

@@ -234,9 +234,13 @@ class ClassLoader
             } else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass"
                 return true;
             }
+
+            if (class_exists($className, false) || interface_exists($className, false)) {
+                return true;
+            }
         }
 
-        return class_exists($className, false) || interface_exists($className, false);
+        return false;
     }
 
     /**

+ 1 - 7
vendor/doctrine/common/lib/Doctrine/Common/Collections/ArrayCollection.php

@@ -229,13 +229,7 @@ class ArrayCollection implements Collection, Selectable
      */
     public function contains($element)
     {
-        foreach ($this->_elements as $collectionElement) {
-            if ($element === $collectionElement) {
-                return true;
-            }
-        }
-
-        return false;
+        return in_array($element, $this->_elements, true);
     }
 
     /**

+ 22 - 31
vendor/doctrine/common/lib/Doctrine/Common/Collections/Collection.php

@@ -21,6 +21,7 @@ namespace Doctrine\Common\Persistence\Mapping;
 
 use ReflectionClass;
 use ReflectionProperty;
+use Doctrine\Common\Reflection\RuntimePublicReflectionProperty;
 
 /**
  * PHP Runtime Reflection Service
@@ -30,10 +31,7 @@ use ReflectionProperty;
 class RuntimeReflectionService implements ReflectionService
 {
     /**
-     * Return an array of the parent classes (not interfaces) for the given class.
-     *
-     * @param string $class
-     * @return array
+     * {@inheritDoc}
      */
     public function getParentClasses($class)
     {
@@ -41,32 +39,27 @@ class RuntimeReflectionService implements ReflectionService
     }
 
     /**
-     * Return the shortname of a class.
-     *
-     * @param string $class
-     * @return string
+     * {@inheritDoc}
      */
     public function getClassShortName($class)
     {
-        $r = new ReflectionClass($class);
-        return $r->getShortName();
+        $reflectionClass = new ReflectionClass($class);
+
+        return $reflectionClass->getShortName();
     }
 
     /**
-     * @param string $class
-     * @return string
+     * {@inheritDoc}
      */
     public function getClassNamespace($class)
     {
-        $r = new ReflectionClass($class);
-        return $r->getNamespaceName();
+        $reflectionClass = new ReflectionClass($class);
+
+        return $reflectionClass->getNamespaceName();
     }
 
     /**
-     * Return a reflection class instance or null
-     *
-     * @param string $class
-     * @return ReflectionClass|null
+     * {@inheritDoc}
      */
     public function getClass($class)
     {
@@ -74,25 +67,23 @@ class RuntimeReflectionService implements ReflectionService
     }
 
     /**
-     * Return an accessible property (setAccessible(true)) or null.
-     *
-     * @param string $class
-     * @param string $property
-     * @return ReflectionProperty|null
+     * {@inheritDoc}
      */
     public function getAccessibleProperty($class, $property)
     {
-        $property = new ReflectionProperty($class, $property);
-        $property->setAccessible(true);
-        return $property;
+        $reflectionProperty = new ReflectionProperty($class, $property);
+
+        if ($reflectionProperty->isPublic()) {
+            $reflectionProperty = new RuntimePublicReflectionProperty($class, $property);
+        }
+
+        $reflectionProperty->setAccessible(true);
+
+        return $reflectionProperty;
     }
 
     /**
-     * Check if the class have a public method with the given name.
-     *
-     * @param mixed $class
-     * @param mixed $method
-     * @return bool
+     * {@inheritDoc}
      */
     public function hasPublicMethod($class, $method)
     {

+ 1 - 1
vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/StaticReflectionService.php

@@ -38,7 +38,7 @@ interface Proxy
     /**
      * Length of the proxy marker
      *
-     * @var int
+     * @var integer
      */
     const MARKER_LENGTH = 6;
 

+ 93 - 0
vendor/doctrine/common/lib/Doctrine/Common/PropertyChangedListener.php

@@ -0,0 +1,93 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Proxy;
+
+use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
+
+/**
+ * Special Autoloader for Proxy classes, which are not PSR-0 compliant.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
+class Autoloader
+{
+    /**
+     * Resolves proxy class name to a filename based on the following pattern.
+     *
+     * 1. Remove Proxy namespace from class name
+     * 2. Remove namespace separators from remaining class name.
+     * 3. Return PHP filename from proxy-dir with the result from 2.
+     *
+     * @param  string $proxyDir
+     * @param  string $proxyNamespace
+     * @param  string $className
+     *
+     * @return string
+     *
+     * @throws InvalidArgumentException
+     */
+    public static function resolveFile($proxyDir, $proxyNamespace, $className)
+    {
+        if (0 !== strpos($className, $proxyNamespace)) {
+            throw InvalidArgumentException::notProxyClass($className, $proxyNamespace);
+        }
+
+        $className = str_replace('\\', '', substr($className, strlen($proxyNamespace) + 1));
+
+        return $proxyDir . DIRECTORY_SEPARATOR . $className . '.php';
+    }
+
+    /**
+     * Register and return autoloader callback for the given proxy dir and
+     * namespace.
+     *
+     * @param  string  $proxyDir
+     * @param  string  $proxyNamespace
+     * @param  callable $notFoundCallback Invoked when the proxy file is not found.
+     *
+     * @return \Closure
+     *
+     * @throws InvalidArgumentException
+     */
+    public static function register($proxyDir, $proxyNamespace, $notFoundCallback = null)
+    {
+        $proxyNamespace = ltrim($proxyNamespace, '\\');
+
+        if ( ! (null === $notFoundCallback || is_callable($notFoundCallback))) {
+            throw InvalidArgumentException::invalidClassNotFoundCallback($notFoundCallback);
+        }
+
+        $autoloader = function ($className) use ($proxyDir, $proxyNamespace, $notFoundCallback) {
+            if (0 === strpos($className, $proxyNamespace)) {
+                $file = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className);
+
+                if ($notFoundCallback && ! file_exists($file)) {
+                    call_user_func($notFoundCallback, $proxyDir, $proxyNamespace, $className);
+                }
+
+                require $file;
+            }
+        };
+
+        spl_autoload_register($autoloader);
+
+        return $autoloader;
+    }
+}

+ 81 - 0
vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/InvalidArgumentException.php

@@ -0,0 +1,81 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Proxy\Exception;
+
+use InvalidArgumentException as BaseInvalidArgumentException;
+
+/**
+ * Proxy Invalid Argument Exception
+ *
+ * @link        www.doctrine-project.com
+ * @since       2.4
+ * @author      Marco Pivetta <ocramius@gmail.com>
+ */
+class InvalidArgumentException extends BaseInvalidArgumentException implements ProxyException
+{
+    /**
+     * @return self
+     */
+    public static function proxyDirectoryRequired()
+    {
+        return new self('You must configure a proxy directory. See docs for details');
+    }
+
+    /**
+     * @param  string $className
+     * @param  string $proxyNamespace
+     *
+     * @return self
+     */
+    public static function notProxyClass($className, $proxyNamespace)
+    {
+        return new self(sprintf('The class "%s" is not part of the proxy namespace "%s"', $className, $proxyNamespace));
+    }
+
+    /**
+     * @param  string $name
+     *
+     * @return self
+     */
+    public static function invalidPlaceholder($name)
+    {
+        return new self(sprintf('Provided placeholder for "%s" must be either a string or a valid callable', $name));
+    }
+
+    /**
+     * @return self
+     */
+    public static function proxyNamespaceRequired()
+    {
+        return new self('You must configure a proxy namespace');
+    }
+
+    /**
+     * @param  mixed $callback
+     *
+     * @return self
+     */
+    public static function invalidClassNotFoundCallback($callback)
+    {
+        $type = is_object($callback) ? get_class($callback) : gettype($callback);
+
+        return new self(sprintf('Invalid \$notFoundCallback given: must be a callable, "%s" given', $type));
+    }
+}

+ 31 - 0
vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/ProxyException.php

@@ -0,0 +1,31 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Proxy\Exception;
+
+/**
+ * Base exception interface for proxy exceptions
+ *
+ * @link        www.doctrine-project.com
+ * @since       2.4
+ * @author      Marco Pivetta <ocramius@gmail.com>
+ */
+interface ProxyException
+{
+}

+ 61 - 0
vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/UnexpectedValueException.php

@@ -0,0 +1,61 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Proxy\Exception;
+
+use UnexpectedValueException as BaseUnexpectedValueException;
+
+/**
+ * Proxy Unexpected Value Exception
+ *
+ * @link        www.doctrine-project.com
+ * @since       2.4
+ * @author      Marco Pivetta <ocramius@gmail.com>
+ */
+class UnexpectedValueException extends BaseUnexpectedValueException implements ProxyException
+{
+    /**
+     * @return self
+     */
+    public static function proxyDirectoryNotWritable()
+    {
+        return new self('Your proxy directory must be writable');
+    }
+
+    /**
+     * @param string $className
+     * @param string $methodName
+     * @param string $parameterName
+     *
+     * @return self
+     */
+    public static function invalidParameterTypeHint($className, $methodName, $parameterName, \Exception $previous)
+    {
+        return new self(
+            sprintf(
+                'The type hint of parameter "%s" in method "%s" in class "%s" is invalid.',
+                $parameterName,
+                $methodName,
+                $className
+            ),
+            0,
+            $previous
+        );
+    }
+}

+ 83 - 0
vendor/doctrine/common/lib/Doctrine/Common/Proxy/Proxy.php

@@ -0,0 +1,83 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Proxy;
+
+use Doctrine\Common\Persistence\Proxy as BaseProxy;
+use Closure;
+
+/**
+ * Interface for proxy classes.
+ *
+ * @author Roman Borschel <roman@code-factory.org>
+ * @author Marco Pivetta  <ocramius@gmail.com>
+ * @since  2.4
+ */
+interface Proxy extends BaseProxy
+{
+    /**
+     * Marks the proxy as initialized or not.
+     *
+     * @param boolean $initialized
+     */
+    public function __setInitialized($initialized);
+
+    /**
+     * Set the initializer callback to be used when initializing the proxy. That
+     * initializer should accept 3 parameters: $proxy, $method and $params. Those
+     * are respectively the proxy object that is being initialized, the method name
+     * that triggered initialization and the parameters passed to that method
+     *
+     * @param Closure $initializer
+     */
+    public function __setInitializer(Closure $initializer = null);
+
+    /**
+     * Retrieves the initializer callback used to initialize the proxy.
+     * @see __setInitializer
+     *
+     * @return Closure|null
+     */
+    public function __getInitializer();
+
+    /**
+     * Set the callback to be used when cloning the proxy. That initializer should accept
+     * a single parameter, which is the cloned proxy instance itself
+     *
+     * @param Closure $cloner
+     */
+    public function __setCloner(Closure $cloner = null);
+
+    /**
+     * Retrieves the callback to be used when cloning the proxy.
+     * @see __setCloner
+     *
+     * @return Closure|null
+     */
+    public function __getCloner();
+
+    /**
+     * Retrieves the list of lazy loaded properties for a given proxy
+     *
+     * @return array with keys being the property names, and values being the default values
+     *               for those properties
+     */
+    public function __getLazyProperties();
+}

+ 921 - 0
vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyGenerator.php

@@ -0,0 +1,921 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Proxy;
+
+use Doctrine\Common\Persistence\Mapping\ClassMetadata;
+use Doctrine\Common\Util\ClassUtils;
+use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
+use Doctrine\Common\Proxy\Exception\UnexpectedValueException;
+
+/**
+ * This factory is used to generate proxy classes. It builds proxies from given parameters, a template and class
+ * metadata.
+ *
+ * @author Marco Pivetta <ocramius@gmail.com>
+ * @since 2.4
+ */
+class ProxyGenerator
+{
+    /**
+     * Used to match very simple id methods that don't need
+     * to be decorated since the identifier is known.
+     */
+    const PATTERN_MATCH_ID_METHOD = '((public\s)?(function\s{1,}%s\s?\(\)\s{1,})\s{0,}{\s{0,}return\s{0,}\$this->%s;\s{0,}})i';
+
+    /**
+     * @var string The namespace that contains all proxy classes.
+     */
+    private $proxyNamespace;
+
+    /**
+     * @var string The directory that contains all proxy classes.
+     */
+    private $proxyDirectory;
+
+    /**
+     * @var string[]|callable[] map of callables used to fill in placeholders set in the template
+     */
+    protected $placeholders = array();
+
+    /**
+     * @var string template used as a blueprint to generate proxies
+     */
+    protected $proxyClassTemplate = '<?php
+
+namespace <namespace>;
+
+/**
+ * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE\'S PROXY GENERATOR
+ */
+class <proxyClassName> extends \<className> implements \<baseProxyInterface>
+{
+    /**
+     * @var \Closure the callback responsible for loading properties in the proxy object. This callback is called with
+     *      three parameters, being respectively the proxy object to be initialized, the method that triggered the
+     *      initialization process and an array of ordered parameters that were passed to that method.
+     *
+     * @see \Doctrine\Common\Persistence\Proxy::__setInitializer
+     */
+    public $__initializer__;
+
+    /**
+     * @var \Closure the callback responsible of loading properties that need to be copied in the cloned object
+     *
+     * @see \Doctrine\Common\Persistence\Proxy::__setCloner
+     */
+    public $__cloner__;
+
+    /**
+     * @var boolean flag indicating if this object was already initialized
+     *
+     * @see \Doctrine\Common\Persistence\Proxy::__isInitialized
+     */
+    public $__isInitialized__ = false;
+
+    /**
+     * @var array properties to be lazy loaded, with keys being the property
+     *            names and values being their default values
+     *
+     * @see \Doctrine\Common\Persistence\Proxy::__getLazyProperties
+     */
+    public static $lazyPropertiesDefaults = array(<lazyPropertiesDefaults>);
+
+<additionalProperties>
+
+<constructorImpl>
+
+<magicGet>
+
+<magicSet>
+
+<magicIsset>
+
+<sleepImpl>
+
+<wakeupImpl>
+
+<cloneImpl>
+
+    /**
+     * Forces initialization of the proxy
+     */
+    public function __load()
+    {
+        $this->__initializer__ && $this->__initializer__->__invoke($this, \'__load\', array());
+    }
+
+    /**
+     * {@inheritDoc}
+     * @internal generated method: use only when explicitly handling proxy specific loading logic
+     */
+    public function __isInitialized()
+    {
+        return $this->__isInitialized__;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @internal generated method: use only when explicitly handling proxy specific loading logic
+     */
+    public function __setInitialized($initialized)
+    {
+        $this->__isInitialized__ = $initialized;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @internal generated method: use only when explicitly handling proxy specific loading logic
+     */
+    public function __setInitializer(\Closure $initializer = null)
+    {
+        $this->__initializer__ = $initializer;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @internal generated method: use only when explicitly handling proxy specific loading logic
+     */
+    public function __getInitializer()
+    {
+        return $this->__initializer__;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @internal generated method: use only when explicitly handling proxy specific loading logic
+     */
+    public function __setCloner(\Closure $cloner = null)
+    {
+        $this->__cloner__ = $cloner;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @internal generated method: use only when explicitly handling proxy specific cloning logic
+     */
+    public function __getCloner()
+    {
+        return $this->__cloner__;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @internal generated method: use only when explicitly handling proxy specific loading logic
+     * @static
+     */
+    public function __getLazyProperties()
+    {
+        return self::$lazyPropertiesDefaults;
+    }
+
+    <methods>
+}
+';
+
+    /**
+     * Initializes a new instance of the <tt>ProxyFactory</tt> class that is
+     * connected to the given <tt>EntityManager</tt>.
+     *
+     * @param  string $proxyDirectory The directory to use for the proxy classes. It must exist.
+     * @param  string $proxyNamespace The namespace to use for the proxy classes.
+     *
+     * @throws InvalidArgumentException
+     */
+    public function __construct($proxyDirectory, $proxyNamespace)
+    {
+        if ( ! $proxyDirectory) {
+            throw InvalidArgumentException::proxyDirectoryRequired();
+        }
+
+        if ( ! $proxyNamespace) {
+            throw InvalidArgumentException::proxyNamespaceRequired();
+        }
+
+        $this->proxyDirectory        = $proxyDirectory;
+        $this->proxyNamespace        = $proxyNamespace;
+
+        $this->setPlaceholders(array(
+            '<namespace>'                    => array($this, 'generateNamespace'),
+            '<proxyClassName>'               => array($this, 'generateProxyShortClassName'),
+            '<baseProxyInterface>'           => 'Doctrine\Common\Proxy\Proxy',
+            '<className>'                    => array($this, 'generateClassName'),
+            '<additionalProperties>'         => '',
+            '<lazyPropertiesDefaults>'       => array($this, 'generateLazyPropertiesDefaults'),
+            '<constructorImpl>'              => array($this, 'generateConstructorImpl'),
+            '<magicGet>'                     => array($this, 'generateMagicGet'),
+            '<magicSet>'                     => array($this, 'generateMagicSet'),
+            '<magicIsset>'                   => array($this, 'generateMagicIsset'),
+            '<sleepImpl>'                    => array($this, 'generateSleepImpl'),
+            '<wakeupImpl>'                   => array($this, 'generateWakeupImpl'),
+            '<cloneImpl>'                    => array($this, 'generateCloneImpl'),
+            '<methods>'                      => array($this, 'generateMethods'),
+        ));
+    }
+
+    /**
+     * Set the placeholders to be replaced in the template
+     *
+     * @param string[]|callable[] $placeholders
+     */
+    public function setPlaceholders(array $placeholders)
+    {
+        foreach ($placeholders as $name => $value) {
+            $this->setPlaceholder($name, $value);
+        }
+    }
+
+    /**
+     * Set a placeholder to be replaced in the template
+     *
+     * @param  string          $name
+     * @param  string|callable $placeholder
+     *
+     * @throws InvalidArgumentException
+     */
+    public function setPlaceholder($name, $placeholder)
+    {
+        if ( ! is_string($placeholder) && ! is_callable($placeholder)) {
+            throw InvalidArgumentException::invalidPlaceholder($name);
+        }
+
+        $this->placeholders[$name] = $placeholder;
+    }
+
+    /**
+     * Set the base template used to create proxy classes
+     *
+     * @param string $proxyClassTemplate
+     */
+    public function setProxyClassTemplate($proxyClassTemplate)
+    {
+        $this->proxyClassTemplate = (string) $proxyClassTemplate;
+    }
+
+    /**
+     * Generate the Proxy class name
+     *
+     * @param  string $originalClassName
+     *
+     * @return string the FQCN class name of the proxy. If the proxy does not exist, it is generated
+     */
+    public function getProxyClassName($originalClassName)
+    {
+        return ClassUtils::generateProxyClassName($originalClassName, $this->proxyNamespace);
+    }
+
+    /**
+     * Generates the proxy short class name to be used in the template
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateProxyShortClassName(ClassMetadata $class)
+    {
+        $proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace);
+        $parts          = explode('\\', strrev($proxyClassName), 2);
+
+        return strrev($parts[0]);
+    }
+
+    /**
+     * Generates the proxy namespace
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateNamespace(ClassMetadata $class)
+    {
+        $proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace);
+        $parts = explode('\\', strrev($proxyClassName), 2);
+
+        return strrev($parts[1]);
+    }
+
+    /**
+     * Generates the original class name
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateClassName(ClassMetadata $class)
+    {
+        return ltrim($class->getName(), '\\');
+    }
+
+    /**
+     * Generates the array representation of lazy loaded public properties and their default values
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateLazyPropertiesDefaults(ClassMetadata $class)
+    {
+        $lazyPublicProperties = $this->getLazyLoadedPublicProperties($class);
+        $values               = array();
+
+        foreach ($lazyPublicProperties as $key => $value) {
+            $values[] = var_export($key, true) . ' => ' . var_export($value, true);
+        }
+
+        return implode(', ', $values);
+    }
+
+    /**
+     * Generates the constructor code (un-setting public lazy loaded properties, setting identifier field values)
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateConstructorImpl(ClassMetadata $class)
+    {
+        $constructorImpl = <<<'EOT'
+    /**
+     * @param \Closure $initializer
+     * @param \Closure $cloner
+     */
+    public function __construct($initializer = null, $cloner = null)
+    {
+
+EOT;
+        $toUnset = array();
+
+        foreach ($this->getLazyLoadedPublicProperties($class) as $lazyPublicProperty => $unused) {
+            $toUnset[] = '$this->' . $lazyPublicProperty;
+        }
+
+        $constructorImpl .= (empty($toUnset) ? '' : '        unset(' . implode(', ', $toUnset) . ");\n")
+            . <<<'EOT'
+
+        $this->__initializer__ = $initializer;
+        $this->__cloner__      = $cloner;
+    }
+EOT;
+
+        return $constructorImpl;
+    }
+
+    /**
+     * Generates the magic getter invoked when lazy loaded public properties are requested
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateMagicGet(ClassMetadata $class)
+    {
+        $lazyPublicProperties = array_keys($this->getLazyLoadedPublicProperties($class));
+        $hasParentGet         = $class->getReflectionClass()->hasMethod('__get');
+
+        if (empty($lazyPublicProperties) && ! $hasParentGet) {
+            return '';
+        }
+
+        $inheritDoc = $hasParentGet ? '{@inheritDoc}' : '';
+        $magicGet = <<<EOT
+    /**
+     * $inheritDoc
+     * @param string \$name
+     */
+    public function __get(\$name)
+    {
+
+EOT;
+
+        if ( ! empty($lazyPublicProperties)) {
+            $magicGet .= <<<'EOT'
+        if (array_key_exists($name, $this->__getLazyProperties())) {
+            $this->__initializer__ && $this->__initializer__->__invoke($this, '__get', array($name));
+
+            return $this->$name;
+        }
+
+
+EOT;
+        }
+
+        if ($hasParentGet) {
+            $magicGet .= <<<'EOT'
+        $this->__initializer__ && $this->__initializer__->__invoke($this, '__get', array($name));
+
+        return parent::__get($name)
+
+EOT;
+        } else {
+            $magicGet .= <<<'EOT'
+        trigger_error(sprintf('Undefined property: %s::$%s', __CLASS__, $name), E_USER_NOTICE);
+
+EOT;
+        }
+
+        $magicGet .= "    }";
+
+        return $magicGet;
+    }
+
+    /**
+     * Generates the magic setter (currently unused)
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateMagicSet(ClassMetadata $class)
+    {
+        $lazyPublicProperties = $this->getLazyLoadedPublicProperties($class);
+        $hasParentSet         = $class->getReflectionClass()->hasMethod('__set');
+
+        if (empty($lazyPublicProperties) && ! $hasParentSet) {
+            return '';
+        }
+
+        $inheritDoc = $hasParentSet ? '{@inheritDoc}' : '';
+        $magicSet   = <<<EOT
+    /**
+     * $inheritDoc
+     * @param string \$name
+     * @param mixed  \$value
+     */
+    public function __set(\$name, \$value)
+    {
+
+EOT;
+
+        if ( ! empty($lazyPublicProperties)) {
+            $magicSet .= <<<'EOT'
+        if (array_key_exists($name, $this->__getLazyProperties())) {
+            $this->__initializer__ && $this->__initializer__->__invoke($this, '__set', array($name, $value));
+
+            $this->$name = $value;
+
+            return;
+        }
+
+
+EOT;
+        }
+
+        if ($hasParentSet) {
+            $magicSet .= <<<'EOT'
+        $this->__initializer__ && $this->__initializer__->__invoke($this, '__set', array($name, $value));
+
+        return parent::__set(\$name, \$value)
+EOT;
+        } else {
+            $magicSet .= "        \$this->\$name = \$value;";
+        }
+
+        $magicSet .= "\n    }";
+
+        return $magicSet;
+    }
+
+    /**
+     * Generates the magic issetter invoked when lazy loaded public properties are checked against isset()
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateMagicIsset(ClassMetadata $class)
+    {
+        $lazyPublicProperties = array_keys($this->getLazyLoadedPublicProperties($class));
+        $hasParentIsset       = $class->getReflectionClass()->hasMethod('__isset');
+
+        if (empty($lazyPublicProperties) && ! $hasParentIsset) {
+            return '';
+        }
+
+        $inheritDoc = $hasParentIsset ? '{@inheritDoc}' : '';
+        $magicIsset = <<<EOT
+    /**
+     * $inheritDoc
+     * @param  string \$name
+     * @return boolean
+     */
+    public function __isset(\$name)
+    {
+
+EOT;
+
+        if ( ! empty($lazyPublicProperties)) {
+            $magicIsset .= <<<'EOT'
+        if (array_key_exists($name, $this->__getLazyProperties())) {
+            $this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', array($name));
+
+            return isset($this->$name);
+        }
+
+
+EOT;
+        }
+
+        if ($hasParentIsset) {
+            $magicIsset .= <<<'EOT'
+        $this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', array($name));
+
+        return parent::__isset($name)
+
+EOT;
+        } else {
+            $magicIsset .= "        return false;";
+        }
+
+        return $magicIsset . "\n    }";
+    }
+
+    /**
+     * Generates implementation for the `__sleep` method of proxies.
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateSleepImpl(ClassMetadata $class)
+    {
+        $hasParentSleep = $class->getReflectionClass()->hasMethod('__sleep');
+        $inheritDoc     = $hasParentSleep ? '{@inheritDoc}' : '';
+        $sleepImpl      = <<<EOT
+    /**
+     * $inheritDoc
+     * @return array
+     */
+    public function __sleep()
+    {
+
+EOT;
+
+        if ($hasParentSleep) {
+            return $sleepImpl . <<<'EOT'
+        $properties = array_merge(array('__isInitialized__'), parent::__sleep());
+
+        if ($this->__isInitialized__) {
+            $properties = array_diff($properties, array_keys($this->__getLazyProperties()));
+        }
+
+        return $properties;
+    }
+EOT;
+        }
+
+        $allProperties = array('__isInitialized__');
+
+        /* @var $prop \ReflectionProperty */
+        foreach ($class->getReflectionClass()->getProperties() as $prop) {
+            $allProperties[] = $prop->getName();
+        }
+
+        $lazyPublicProperties = array_keys($this->getLazyLoadedPublicProperties($class));
+        $protectedProperties  = array_diff($allProperties, $lazyPublicProperties);
+
+        foreach ($allProperties as &$property) {
+            $property = var_export($property, true);
+        }
+
+        foreach ($protectedProperties as &$property) {
+            $property = var_export($property, true);
+        }
+
+        $allProperties       = implode(', ', $allProperties);
+        $protectedProperties = implode(', ', $protectedProperties);
+
+        return $sleepImpl . <<<EOT
+        if (\$this->__isInitialized__) {
+            return array($allProperties);
+        }
+
+        return array($protectedProperties);
+    }
+EOT;
+    }
+
+    /**
+     * Generates implementation for the `__wakeup` method of proxies.
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateWakeupImpl(ClassMetadata $class)
+    {
+        $unsetPublicProperties = array();
+        $hasWakeup             = $class->getReflectionClass()->hasMethod('__wakeup');
+
+        foreach (array_keys($this->getLazyLoadedPublicProperties($class)) as $lazyPublicProperty) {
+            $unsetPublicProperties[] = '$this->' . $lazyPublicProperty;
+        }
+
+        $shortName  = $this->generateProxyShortClassName($class);
+        $inheritDoc = $hasWakeup ? '{@inheritDoc}' : '';
+        $wakeupImpl = <<<EOT
+    /**
+     * $inheritDoc
+     */
+    public function __wakeup()
+    {
+        if ( ! \$this->__isInitialized__) {
+            \$this->__initializer__ = function ($shortName \$proxy) {
+                \$proxy->__setInitializer(null);
+                \$proxy->__setCloner(null);
+
+                \$existingProperties = get_object_vars(\$proxy);
+
+                foreach (\$proxy->__getLazyProperties() as \$property => \$defaultValue) {
+                    if ( ! array_key_exists(\$property, \$existingProperties)) {
+                        \$proxy->\$property = \$defaultValue;
+                    }
+                }
+            };
+
+EOT;
+
+        if ( ! empty($unsetPublicProperties)) {
+            $wakeupImpl .= "\n            unset(" . implode(', ', $unsetPublicProperties) . ");";
+        }
+
+        $wakeupImpl .= "\n        }";
+
+        if ($hasWakeup) {
+            $wakeupImpl .= "\n        parent::__wakeup();";
+        }
+
+        $wakeupImpl .= "\n    }";
+
+        return $wakeupImpl;
+    }
+
+    /**
+     * Generates implementation for the `__clone` method of proxies.
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateCloneImpl(ClassMetadata $class)
+    {
+        $hasParentClone  = $class->getReflectionClass()->hasMethod('__clone');
+        $inheritDoc      = $hasParentClone ? '{@inheritDoc}' : '';
+        $callParentClone = $hasParentClone ? "\n        parent::__clone();" : '';
+
+        return <<<EOT
+    /**
+     * $inheritDoc
+     */
+    public function __clone()
+    {
+        \$this->__cloner__ && \$this->__cloner__->__invoke(\$this, '__clone', array());
+$callParentClone    }
+EOT;
+    }
+
+    /**
+     * Generates decorated methods by picking those available in the parent class
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return string
+     */
+    public function generateMethods(ClassMetadata $class)
+    {
+        $methods           = '';
+        $methodNames       = array();
+        $reflectionMethods = $class->getReflectionClass()->getMethods(\ReflectionMethod::IS_PUBLIC);
+        $skippedMethods    = array(
+            '__sleep'   => true,
+            '__clone'   => true,
+            '__wakeup'  => true,
+            '__get'     => true,
+            '__set'     => true,
+            '__isset'   => true,
+        );
+
+        foreach ($reflectionMethods as $method) {
+            $name = $method->getName();
+
+            if (
+                $method->isConstructor() ||
+                isset($skippedMethods[strtolower($name)]) ||
+                isset($methodNames[$name]) ||
+                $method->isFinal() ||
+                $method->isStatic() ||
+                ( ! $method->isPublic())
+            ) {
+                continue;
+            }
+
+            $methodNames[$name] = true;
+            $methods .= "\n    /**\n"
+                . "     * {@inheritDoc}\n"
+                . "     */\n"
+                . '    public function ';
+
+            if ($method->returnsReference()) {
+                $methods .= '&';
+            }
+
+            $methods .= $name . '(';
+
+            $firstParam      = true;
+            $parameterString = '';
+            $argumentString  = '';
+            $parameters      = array();
+
+            foreach ($method->getParameters() as $param) {
+                if ($firstParam) {
+                    $firstParam = false;
+                } else {
+                    $parameterString .= ', ';
+                    $argumentString  .= ', ';
+                }
+
+                try {
+                    $paramClass = $param->getClass();
+                } catch (\ReflectionException $previous) {
+                    throw UnexpectedValueException::invalidParameterTypeHint(
+                        $class->getName(),
+                        $method->getName(),
+                        $param->getName(),
+                        $previous
+                    );
+                }
+
+                // We need to pick the type hint class too
+                if (null !== $paramClass) {
+                    $parameterString .= '\\' . $paramClass->getName() . ' ';
+                } elseif ($param->isArray()) {
+                    $parameterString .= 'array ';
+                }
+
+                if ($param->isPassedByReference()) {
+                    $parameterString .= '&';
+                }
+
+                $parameters[] = '$' . $param->getName();
+                $parameterString .= '$' . $param->getName();
+                $argumentString  .= '$' . $param->getName();
+
+                if ($param->isDefaultValueAvailable()) {
+                    $parameterString .= ' = ' . var_export($param->getDefaultValue(), true);
+                }
+            }
+
+            $methods .= $parameterString . ')';
+            $methods .= "\n" . '    {' . "\n";
+
+            if ($this->isShortIdentifierGetter($method, $class)) {
+                $identifier = lcfirst(substr($name, 3));
+                $fieldType  = $class->getTypeOfField($identifier);
+                $cast       = in_array($fieldType, array('integer', 'smallint')) ? '(int) ' : '';
+
+                $methods .= '        if ($this->__isInitialized__ === false) {' . "\n";
+                $methods .= '            return ' . $cast . ' parent::' . $method->getName() . "();\n";
+                $methods .= '        }' . "\n\n";
+            }
+
+            $methods .= "\n        \$this->__initializer__ "
+                . "&& \$this->__initializer__->__invoke(\$this, " . var_export($name, true)
+                . ", array(" . implode(', ', $parameters) . "));"
+                . "\n\n        return parent::" . $name . '(' . $argumentString . ');'
+                . "\n" . '    }' . "\n";
+        }
+
+        return $methods;
+    }
+
+    /**
+     * Generate the Proxy file name
+     *
+     * @param string $className
+     * @param string $baseDirectory   Optional base directory for proxy file name generation.
+     *                        If not specified, the directory configured on the Configuration of the
+     *                        EntityManager will be used by this factory.
+     *
+     * @return string
+     */
+    public function getProxyFileName($className, $baseDirectory = null)
+    {
+        $baseDirectory = $baseDirectory ?: $this->proxyDirectory;
+
+        return rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . Proxy::MARKER
+            . str_replace('\\', '', $className) . '.php';
+    }
+
+    /**
+     * Generates a proxy class file.
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata  $class    Metadata for the original class
+     * @param  string         $fileName Filename (full path) for the generated class
+     * @param  string         $file     The proxy class template data
+     *
+     * @throws UnexpectedValueException
+     */
+    public function generateProxyClass(ClassMetadata $class, $fileName = null, $file = null)
+    {
+        $placeholders = array();
+
+        foreach ($this->placeholders as $name => $placeholder) {
+            $placeholders[$name] = is_callable($placeholder) ? call_user_func($placeholder, $class) : $placeholder;
+        }
+
+        $fileName = $fileName ?: $this->getProxyFileName($class->getName());
+        $file = $file ? $file : $this->proxyClassTemplate;
+        $file = strtr($file, $placeholders);
+
+        $parentDirectory = dirname($fileName);
+
+        if ( ! is_dir($parentDirectory) && (false === @mkdir($parentDirectory, 0775, true))) {
+            throw UnexpectedValueException::proxyDirectoryNotWritable();
+        } elseif ( ! is_writable($parentDirectory)) {
+            throw UnexpectedValueException::proxyDirectoryNotWritable();
+        }
+
+        $tmpFileName = $fileName . '.' . uniqid('', true);
+        file_put_contents($tmpFileName, $file);
+        rename($tmpFileName, $fileName);
+    }
+
+    /**
+     * Check if the method is a short identifier getter.
+     *
+     * What does this mean? For proxy objects the identifier is already known,
+     * however accessing the getter for this identifier usually triggers the
+     * lazy loading, leading to a query that may not be necessary if only the
+     * ID is interesting for the userland code (for example in views that
+     * generate links to the entity, but do not display anything else).
+     *
+     * @param  \ReflectionMethod                                  $method
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return boolean
+     */
+    private function isShortIdentifierGetter($method, ClassMetadata $class)
+    {
+        $identifier = lcfirst(substr($method->getName(), 3));
+        $startLine = $method->getStartLine();
+        $endLine = $method->getEndLine();
+        $cheapCheck = (
+            $method->getNumberOfParameters() == 0
+            && substr($method->getName(), 0, 3) == 'get'
+            && in_array($identifier, $class->getIdentifier(), true)
+            && $class->hasField($identifier)
+            && (($endLine - $startLine) <= 4)
+        );
+
+        if ($cheapCheck) {
+            $code = file($method->getDeclaringClass()->getFileName());
+            $code = trim(implode(' ', array_slice($code, $startLine - 1, $endLine - $startLine + 1)));
+
+            $pattern = sprintf(self::PATTERN_MATCH_ID_METHOD, $method->getName(), $identifier);
+
+            if (preg_match($pattern, $code)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Generates the list of public properties to be lazy loaded, with their default values
+     *
+     * @param  \Doctrine\Common\Persistence\Mapping\ClassMetadata $class
+     *
+     * @return mixed[]
+     */
+    private function getLazyLoadedPublicProperties(ClassMetadata $class)
+    {
+        $defaultProperties = $class->getReflectionClass()->getDefaultProperties();
+        $properties = array();
+
+        foreach ($class->getReflectionClass()->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
+            $name = $property->getName();
+
+            if (($class->hasField($name) || $class->hasAssociation($name)) && ! $class->isIdentifier($name)) {
+                $properties[$name] = $defaultProperties[$name];
+            }
+        }
+
+        return $properties;
+    }
+}

+ 76 - 0
vendor/doctrine/common/lib/Doctrine/Common/Reflection/ClassFinderInterface.php

@@ -0,0 +1,76 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Reflection;
+
+use ReflectionProperty;
+use Doctrine\Common\Proxy\Proxy;
+
+/**
+ * PHP Runtime Reflection Public Property - special overrides for public properties
+ *
+ * @author Marco Pivetta <ocramius@gmail.com>
+ * @since  2.4
+ */
+class RuntimePublicReflectionProperty extends ReflectionProperty
+{
+    /**
+     * {@inheritDoc}
+     *
+     * Checks is the value actually exist before fetching it.
+     * This is to avoid calling `__get` on the provided $object if it
+     * is a {@see \Doctrine\Common\Proxy\Proxy}.
+     */
+    public function getValue($object = null)
+    {
+        $name = $this->getName();
+
+        if ($object instanceof Proxy && ! $object->__isInitialized()) {
+            $originalInitializer = $object->__getInitializer();
+            $object->__setInitializer(null);
+            $val = isset($object->$name) ? $object->$name : null;
+            $object->__setInitializer($originalInitializer);
+
+            return $val;
+        }
+
+        return isset($object->$name) ? parent::getValue($object) : null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Avoids triggering lazy loading via `__set` if the provided object
+     * is a {@see \Doctrine\Common\Proxy\Proxy}.
+     * @link https://bugs.php.net/bug.php?id=63463
+     */
+    public function setValue($object, $value = null)
+    {
+        if ( ! ($object instanceof Proxy && ! $object->__isInitialized())) {
+            parent::setValue($object, $value);
+
+            return;
+        }
+
+        $originalInitializer = $object->__getInitializer();
+        $object->__setInitializer(null);
+        parent::setValue($object, $value);
+        $object->__setInitializer($originalInitializer);
+    }
+}

+ 5 - 45
vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionClass.php

@@ -1,7 +1,5 @@
 <?php
 /*
- *  $Id: Inflector.php 3189 2007-11-18 20:37:44Z meus $
- *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -21,52 +19,14 @@
 
 namespace Doctrine\Common\Util;
 
+use Doctrine\Common\Inflector\Inflector as BaseInflector;
+
 /**
  * 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 <kvesteri@cc.hut.fi>
- * @author      Jonathan H. Wage <jonwage@gmail.com>
+ * Kept for backwards compatibility reasons, was moved to its
+ * own component.
  */
-class Inflector
+class Inflector extends BaseInflector
 {
-    /**
-     * 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));
-    }
 }

+ 1 - 4
vendor/doctrine/common/lib/Doctrine/Common/Version.php

@@ -2,9 +2,6 @@
 
 namespace Doctrine\Tests\Common\Annotations\Fixtures;
 
-$var = 1;
-function () use ($var) {};
-
 use Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Secure;
 use Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Route;
 use Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Template;
@@ -12,4 +9,4 @@ use Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Template;
 $var = 1;
 function () use ($var) {};
 
-class NamespaceWithClosureDeclaration {}
+class NamespaceWithClosureDeclaration {}

+ 19 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NamespacedSingleClassLOC1000.php

@@ -42,4 +42,23 @@ class ClassLoaderTest extends \Doctrine\Tests\DoctrineTestCase
         $this->assertNull(ClassLoader::getClassLoader('This\Class\Does\Not\Exist'));
         $cl->unregister();
     }
+
+    public function testClassExistsWithSilentAutoloader()
+    {
+        $test = $this;
+        $silentLoader = function ($className) use ($test) {
+            $test->assertSame('ClassLoaderTest\ClassE', $className);
+            require __DIR__ . '/ClassLoaderTest/ClassE.php';
+        };
+        $additionalLoader = function () use ($test) {
+            $test->fail('Should not call this loader, class was already loaded');
+        };
+
+        $this->assertFalse(ClassLoader::classExists('ClassLoaderTest\ClassE'));
+        spl_autoload_register($silentLoader);
+        spl_autoload_register($additionalLoader);
+        $this->assertTrue(ClassLoader::classExists('ClassLoaderTest\ClassE'));
+        spl_autoload_unregister($additionalLoader);
+        spl_autoload_unregister($silentLoader);
+    }
 }

+ 5 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest/ClassA.class.php

@@ -0,0 +1,5 @@
+<?php
+
+namespace ClassLoaderTest;
+
+class ClassE {}

+ 8 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/ClosureExpressionVisitorTest.php

@@ -26,8 +26,13 @@ use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
  */
 class RuntimeReflectionServiceTest extends \PHPUnit_Framework_TestCase
 {
+    /**
+     * @var RuntimeReflectionService
+     */
     private $reflectionService;
 
+    public $unusedPublicProperty;
+
     public function setUp()
     {
         $this->reflectionService = new RuntimeReflectionService();
@@ -65,6 +70,9 @@ class RuntimeReflectionServiceTest extends \PHPUnit_Framework_TestCase
     {
         $reflProp = $this->reflectionService->getAccessibleProperty(__CLASS__, "reflectionService");
         $this->assertInstanceOf("ReflectionProperty", $reflProp);
+
+        $reflProp = $this->reflectionService->getAccessibleProperty(__CLASS__, "unusedPublicProperty");
+        $this->assertInstanceOf("Doctrine\Common\Reflection\RuntimePublicReflectionProperty", $reflProp);
     }
 }
 

+ 72 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticPHPDriverTest.php

@@ -0,0 +1,72 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the LGPL. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Tests\Common\Proxy;
+
+use PHPUnit_Framework_TestCase;
+use Doctrine\Common\Proxy\Autoloader;
+
+/**
+ * @group DDC-1698
+ */
+class AutoloaderTest extends PHPUnit_Framework_TestCase
+{
+    public static function dataResolveFile()
+    {
+        return array(
+            array('/tmp', 'MyProxy', 'MyProxy\__CG__\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__RealClass.php'),
+            array('/tmp', 'MyProxy\Subdir', 'MyProxy\Subdir\__CG__\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__RealClass.php'),
+            array('/tmp', 'MyProxy', 'MyProxy\__CG__\Other\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__OtherRealClass.php'),
+        );
+    }
+
+    /**
+     * @dataProvider dataResolveFile
+     */
+    public function testResolveFile($proxyDir, $proxyNamespace, $className, $expectedProxyFile)
+    {
+        $actualProxyFile = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className);
+        $this->assertEquals($expectedProxyFile, $actualProxyFile);
+    }
+
+    public function testAutoload()
+    {
+        if (file_exists(sys_get_temp_dir() ."/AutoloaderTestClass.php")) {
+            unlink(sys_get_temp_dir() ."/AutoloaderTestClass.php");
+        }
+
+        $autoloader = Autoloader::register(sys_get_temp_dir(), 'ProxyAutoloaderTest', function($proxyDir, $proxyNamespace, $className) {
+            file_put_contents(sys_get_temp_dir() . "/AutoloaderTestClass.php", "<?php namespace ProxyAutoloaderTest; class AutoloaderTestClass {} ");
+        });
+
+        $this->assertTrue(class_exists('ProxyAutoloaderTest\AutoloaderTestClass', true));
+        unlink(sys_get_temp_dir() ."/AutoloaderTestClass.php");
+    }
+
+    public function testRegisterWithInvalidCallback()
+    {
+        $this->setExpectedException(
+            'Doctrine\Common\Proxy\Exception\InvalidArgumentException',
+            'Invalid \$notFoundCallback given: must be a callable, "stdClass" given'
+        );
+
+        Autoloader::register('', '', new \stdClass());
+    }
+}
+

+ 16 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/InvalidTypeHintClass.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace Doctrine\Tests\Common\Proxy;
+
+/**
+ * Test asset class
+ */
+class InvalidTypeHintClass
+{
+    /**
+     * @param InvalidHint (non existing class type hint)
+     */
+    public function invalidTypeHintMethod(InvalidHint $foo)
+    {
+    }
+}

+ 115 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/LazyLoadableObject.php

@@ -0,0 +1,115 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Tests\Common\Proxy;
+
+/**
+ * Test asset representing a lazy loadable object
+ *
+ * @author Marco Pivetta <ocramius@gmail.com>
+ * @since  2.4
+ */
+class LazyLoadableObject
+{
+    /**
+     * @var string
+     */
+    public $publicIdentifierField;
+
+    /**
+     * @var string
+     */
+    protected $protectedIdentifierField;
+
+    /**
+     * @var string
+     */
+    public $publicTransientField            = 'publicTransientFieldValue';
+
+    /**
+     * @var string
+     */
+    protected $protectedTransientField      = 'protectedTransientFieldValue';
+
+    /**
+     * @var string
+     */
+    public $publicPersistentField           = 'publicPersistentFieldValue';
+
+    /**
+     * @var string
+     */
+    protected $protectedPersistentField     = 'protectedPersistentFieldValue';
+
+    /**
+     * @var string
+     */
+    public $publicAssociation               = 'publicAssociationValue';
+
+    /**
+     * @var string
+     */
+    protected $protectedAssociation         = 'protectedAssociationValue';
+
+    /**
+     * @return string
+     */
+    public function getProtectedIdentifierField()
+    {
+        return $this->protectedIdentifierField;
+    }
+
+    /**
+     * @return string
+     */
+    public function testInitializationTriggeringMethod()
+    {
+        return 'testInitializationTriggeringMethod';
+    }
+
+    /**
+     * @return string
+     */
+    public function getProtectedAssociation()
+    {
+        return $this->protectedAssociation;
+    }
+
+    /**
+     * @param \stdClass $param
+     */
+    public function publicTypeHintedMethod(\stdClass $param)
+    {
+    }
+
+    /**
+     *
+     */
+    public function &byRefMethod()
+    {
+    }
+
+    /**
+     * @param mixed $thisIsNotByRef
+     * @param &mixed $thisIsByRef
+     */
+    public function byRefParamMethod($thisIsNotByRef, &$thisIsByRef)
+    {
+    }
+}

+ 195 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/LazyLoadableObjectClassMetadata.php

@@ -0,0 +1,195 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Tests\Common\Proxy;
+
+use ReflectionClass;
+use Doctrine\Common\Persistence\Mapping\ClassMetadata;
+
+/**
+ * Class metadata test asset for @see LazyLoadableObject
+ *
+ * @author Marco Pivetta <ocramius@gmail.com>
+ * @since  2.4
+ */
+class LazyLoadableObjectClassMetadata implements ClassMetadata
+{
+    /**
+     * @var ReflectionClass
+     */
+    protected $reflectionClass;
+
+    /**
+     * @var array
+     */
+    protected $identifier = array(
+        'publicIdentifierField'    => true,
+        'protectedIdentifierField' => true,
+    );
+
+    /**
+     * @var array
+     */
+    protected $fields = array(
+        'publicIdentifierField'    => true,
+        'protectedIdentifierField' => true,
+        'publicPersistentField'    => true,
+        'protectedPersistentField' => true,
+    );
+
+    /**
+     * @var array
+     */
+    protected $associations = array(
+        'publicAssociation'        => true,
+        'protectedAssociation'     => true,
+    );
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getName()
+    {
+        return $this->getReflectionClass()->getName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getIdentifier()
+    {
+        return array_keys($this->identifier);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getReflectionClass()
+    {
+        if (null === $this->reflectionClass) {
+            $this->reflectionClass = new \ReflectionClass(__NAMESPACE__ . '\LazyLoadableObject');
+        }
+
+        return $this->reflectionClass;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function isIdentifier($fieldName)
+    {
+        return isset($this->identifier[$fieldName]);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function hasField($fieldName)
+    {
+        return isset($this->fields[$fieldName]);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function hasAssociation($fieldName)
+    {
+        return isset($this->associations[$fieldName]);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function isSingleValuedAssociation($fieldName)
+    {
+        throw new \BadMethodCallException('not implemented');
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function isCollectionValuedAssociation($fieldName)
+    {
+        throw new \BadMethodCallException('not implemented');
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getFieldNames()
+    {
+        return array_keys($this->fields);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getIdentifierFieldNames()
+    {
+        return $this->getIdentifier();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getAssociationNames()
+    {
+        return array_keys($this->associations);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getTypeOfField($fieldName)
+    {
+        return 'string';
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getAssociationTargetClass($assocName)
+    {
+        throw new \BadMethodCallException('not implemented');
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function isAssociationInverseSide($assocName)
+    {
+        throw new \BadMethodCallException('not implemented');
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getAssociationMappedByTargetField($assocName)
+    {
+        throw new \BadMethodCallException('not implemented');
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getIdentifierValues($object)
+    {
+        throw new \BadMethodCallException('not implemented');
+    }
+}

+ 161 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/ProxyClassGeneratorTest.php

@@ -0,0 +1,161 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+
+namespace Doctrine\Tests\Common\Proxy;
+
+use Doctrine\Common\Proxy\ProxyGenerator;
+use ReflectionClass;
+use ReflectionMethod;
+use PHPUnit_Framework_TestCase;
+
+/**
+ * Test the proxy generator. Its work is generating on-the-fly subclasses of a given model, which implement the Proxy
+ * pattern.
+ *
+ * @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
+ * @author Marco Pivetta <ocramius@gmail.com>
+ */
+class ProxyClassGeneratorTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * @var string
+     */
+    protected $proxyClass = 'Doctrine\Tests\Common\ProxyProxy\__CG__\Doctrine\Tests\Common\Proxy\LazyLoadableObject';
+
+    /**
+     * @var LazyLoadableObjectClassMetadata
+     */
+    protected $metadata;
+
+    /**
+     * @var ProxyGenerator
+     */
+    protected $proxyGenerator;
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function setUp()
+    {
+        $this->metadata       = new LazyLoadableObjectClassMetadata();
+        $this->proxyGenerator = new ProxyGenerator(__DIR__ . '/generated', __NAMESPACE__ . 'Proxy', true);
+
+        if (class_exists($this->proxyClass, false)) {
+            return;
+        }
+
+        $this->proxyGenerator->generateProxyClass($this->metadata);
+        require_once $this->proxyGenerator->getProxyFileName($this->metadata->getName());
+    }
+
+    public function testReferenceProxyRespectsMethodsParametersTypeHinting()
+    {
+        $method = new ReflectionMethod($this->proxyClass, 'publicTypeHintedMethod');
+        $params = $method->getParameters();
+
+        $this->assertEquals(1, count($params));
+        $this->assertEquals('stdClass', $params[0]->getClass()->getName());
+    }
+
+    public function testProxyRespectsMethodsWhichReturnValuesByReference()
+    {
+        $method = new ReflectionMethod($this->proxyClass, 'byRefMethod');
+
+        $this->assertTrue($method->returnsReference());
+    }
+
+    public function testProxyRespectsByRefMethodParameters()
+    {
+        $method = new ReflectionMethod($this->proxyClass, 'byRefParamMethod');
+        $parameters = $method->getParameters();
+        $this->assertSame('thisIsNotByRef', $parameters[0]->getName());
+        $this->assertFalse($parameters[0]->isPassedByReference());
+        $this->assertSame('thisIsByRef', $parameters[1]->getName());
+        $this->assertTrue($parameters[1]->isPassedByReference());
+    }
+
+    public function testCreatesAssociationProxyAsSubclassOfTheOriginalOne()
+    {
+        $this->assertTrue(is_subclass_of($this->proxyClass, $this->metadata->getName()));
+    }
+
+    public function testNonNamespacedProxyGeneration()
+    {
+        $classCode = file_get_contents($this->proxyGenerator->getProxyFileName($this->metadata->getName()));
+
+        $this->assertNotContains("class LazyLoadableObject extends \\\\" . $this->metadata->getName(), $classCode);
+        $this->assertContains("class LazyLoadableObject extends \\" . $this->metadata->getName(), $classCode);
+    }
+
+    public function testClassWithSleepProxyGeneration()
+    {
+        if (!class_exists('Doctrine\Tests\Common\ProxyProxy\__CG__\SleepClass', false)) {
+            $metadata = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata');
+            $reflClass = new ReflectionClass('Doctrine\Tests\Common\Proxy\SleepClass');
+            $metadata->expects($this->any())->method('getReflectionClass')->will($this->returnValue($reflClass));
+            $metadata->expects($this->any())->method('getIdentifierFieldNames')->will($this->returnValue(array('id')));
+            $metadata->expects($this->any())->method('getName')->will($this->returnValue($reflClass->getName()));
+            $proxyGenerator = new ProxyGenerator(__DIR__ . '/generated', __NAMESPACE__ . 'Proxy', true);
+            $proxyGenerator->generateProxyClass($metadata);
+            require_once $proxyGenerator->getProxyFileName($metadata->getName());
+        }
+
+        $classCode = file_get_contents(__DIR__ . '/generated/__CG__DoctrineTestsCommonProxySleepClass.php');
+        $this->assertEquals(1, substr_count($classCode, 'function __sleep'));
+        $this->assertEquals(1, substr_count($classCode, 'parent::__sleep()'));
+    }
+
+    public function testClassWithInvalidTypeHintOnProxiedMethod()
+    {
+        $className = 'Doctrine\Tests\Common\Proxy\InvalidTypeHintClass';
+        $metadata = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata');
+        $reflClass = new ReflectionClass($className);
+        $metadata->expects($this->any())->method('getReflectionClass')->will($this->returnValue($reflClass));
+        $metadata->expects($this->any())->method('getIdentifierFieldNames')->will($this->returnValue(array()));
+        $metadata->expects($this->any())->method('getName')->will($this->returnValue($className));
+        $proxyGenerator = new ProxyGenerator(__DIR__ . '/generated', __NAMESPACE__ . 'Proxy', true);
+
+        $this->setExpectedException(
+            'Doctrine\Common\Proxy\Exception\UnexpectedValueException',
+            'The type hint of parameter "foo" in method "invalidTypeHintMethod"'
+                .' in class "' . $className . '" is invalid.'
+        );
+        $proxyGenerator->generateProxyClass($metadata);
+    }
+
+    public function testNoConfigDirThrowsException()
+    {
+        $this->setExpectedException('Doctrine\Common\Proxy\Exception\InvalidArgumentException');
+        new ProxyGenerator(null, null);
+    }
+
+    public function testNoNamespaceThrowsException()
+    {
+        $this->setExpectedException('Doctrine\Common\Proxy\Exception\InvalidArgumentException');
+        new ProxyGenerator(__DIR__ . '/generated', null);
+    }
+
+    public function testInvalidPlaceholderThrowsException()
+    {
+        $this->setExpectedException('Doctrine\Common\Proxy\Exception\InvalidArgumentException');
+        $generator = new ProxyGenerator(__DIR__ . '/generated', 'SomeNamespace');
+        $generator->setPlaceholder('<somePlaceholder>', array());
+    }
+}

+ 696 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/ProxyLogicTest.php

@@ -0,0 +1,696 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Tests\Common\Proxy;
+
+use Doctrine\Common\Proxy\ProxyGenerator;
+use Doctrine\Common\Proxy\Proxy;
+use Doctrine\Common\Proxy\Exception\UnexpectedValueException;
+use Doctrine\Common\Persistence\Mapping\ClassMetadata;
+use PHPUnit_Framework_TestCase;
+
+/**
+ * Test the generated proxies behavior. These tests make assumptions about the structure of LazyLoadableObject
+ *
+ * @author Marco Pivetta <ocramius@gmail.com>
+ */
+class ProxyLogicTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $proxyLoader;
+
+    /**
+     * @var ClassMetadata
+     */
+    protected $lazyLoadableObjectMetadata;
+
+    /**
+     * @var LazyLoadableObject|Proxy
+     */
+    protected $lazyObject;
+
+    protected $identifier = array(
+        'publicIdentifierField' => 'publicIdentifierFieldValue',
+        'protectedIdentifierField' => 'protectedIdentifierFieldValue',
+    );
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|Callable
+     */
+    protected $initializerCallbackMock;
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setUp()
+    {
+        $this->proxyLoader = $loader      = $this->getMock('stdClass', array('load'), array(), '', false);
+        $this->initializerCallbackMock    = $this->getMock('stdClass', array('__invoke'));
+        $identifier                       = $this->identifier;
+        $this->lazyLoadableObjectMetadata = $metadata = new LazyLoadableObjectClassMetadata();
+
+        // emulating what should happen in a proxy factory
+        $cloner = function (LazyLoadableObject $proxy) use ($loader, $identifier, $metadata) {
+            /* @var $proxy LazyLoadableObject|Proxy */
+            if ($proxy->__isInitialized()) {
+                return;
+            }
+
+            $proxy->__setInitialized(true);
+            $proxy->__setInitializer(null);
+            $original = $loader->load($identifier);
+
+            if (null === $original) {
+                throw new UnexpectedValueException();
+            }
+
+            foreach ($metadata->getReflectionClass()->getProperties() as $reflProperty) {
+                $propertyName = $reflProperty->getName();
+
+                if ($metadata->hasField($propertyName) || $metadata->hasAssociation($propertyName)) {
+                    $reflProperty->setAccessible(true);
+                    $reflProperty->setValue($proxy, $reflProperty->getValue($original));
+                }
+            }
+        };
+
+        $proxyClassName = 'Doctrine\Tests\Common\ProxyProxy\__CG__\Doctrine\Tests\Common\Proxy\LazyLoadableObject';
+
+        // creating the proxy class
+        if (!class_exists($proxyClassName, false)) {
+            $proxyGenerator = new ProxyGenerator(__DIR__ . '/generated', __NAMESPACE__ . 'Proxy', true);
+            $proxyGenerator->generateProxyClass($metadata);
+            require_once $proxyGenerator->getProxyFileName($metadata->getName());
+        }
+
+        $this->lazyObject = new $proxyClassName($this->getClosure($this->initializerCallbackMock), $cloner);
+
+        // setting identifiers in the proxy via reflection
+        foreach ($metadata->getIdentifierFieldNames() as $idField) {
+            $prop = $metadata->getReflectionClass()->getProperty($idField);
+            $prop->setAccessible(true);
+            $prop->setValue($this->lazyObject, $identifier[$idField]);
+        }
+
+        $this->assertFalse($this->lazyObject->__isInitialized());
+    }
+
+    public function testFetchingPublicIdentifierDoesNotCauseLazyLoading()
+    {
+        $this->configureInitializerMock(0);
+
+        $this->assertSame('publicIdentifierFieldValue', $this->lazyObject->publicIdentifierField);
+    }
+
+    public function testFetchingIdentifiersViaPublicGetterDoesNotCauseLazyLoading()
+    {
+        $this->configureInitializerMock(0);
+
+        $this->assertSame('protectedIdentifierFieldValue', $this->lazyObject->getProtectedIdentifierField());
+    }
+
+    public function testCallingMethodCausesLazyLoading()
+    {
+        $this->configureInitializerMock(
+            1,
+            array($this->lazyObject, 'testInitializationTriggeringMethod', array()),
+            function (Proxy $proxy) {
+                $proxy->__setInitializer(null);
+            }
+        );
+
+        $this->lazyObject->testInitializationTriggeringMethod();
+        $this->lazyObject->testInitializationTriggeringMethod();
+    }
+
+    public function testFetchingPublicFieldsCausesLazyLoading()
+    {
+        $test = $this;
+        $this->configureInitializerMock(
+            1,
+            array($this->lazyObject, '__get', array('publicPersistentField')),
+            function () use ($test) {
+                $test->setProxyValue('publicPersistentField', 'loadedValue');
+            }
+        );
+
+        $this->assertSame('loadedValue', $this->lazyObject->publicPersistentField);
+        $this->assertSame('loadedValue', $this->lazyObject->publicPersistentField);
+    }
+
+    public function testFetchingPublicAssociationCausesLazyLoading()
+    {
+        $test = $this;
+        $this->configureInitializerMock(
+            1,
+            array($this->lazyObject, '__get', array('publicAssociation')),
+            function () use ($test) {
+                $test->setProxyValue('publicAssociation', 'loadedAssociation');
+            }
+        );
+
+        $this->assertSame('loadedAssociation', $this->lazyObject->publicAssociation);
+        $this->assertSame('loadedAssociation', $this->lazyObject->publicAssociation);
+    }
+
+    public function testFetchingProtectedAssociationViaPublicGetterCausesLazyLoading()
+    {
+        $this->configureInitializerMock(
+            1,
+            array($this->lazyObject, 'getProtectedAssociation', array()),
+            function (Proxy $proxy) {
+                $proxy->__setInitializer(null);
+            }
+        );
+
+        $this->assertSame('protectedAssociationValue', $this->lazyObject->getProtectedAssociation());
+        $this->assertSame('protectedAssociationValue', $this->lazyObject->getProtectedAssociation());
+    }
+
+    public function testLazyLoadingTriggeredOnlyAtFirstPublicPropertyRead()
+    {
+        $test = $this;
+        $this->configureInitializerMock(
+            1,
+            array($this->lazyObject, '__get', array('publicPersistentField')),
+            function () use ($test) {
+                $test->setProxyValue('publicPersistentField', 'loadedValue');
+                $test->setProxyValue('publicAssociation', 'publicAssociationValue');
+            }
+        );
+
+        $this->assertSame('loadedValue', $this->lazyObject->publicPersistentField);
+        $this->assertSame('publicAssociationValue', $this->lazyObject->publicAssociation);
+    }
+
+    public function testNoticeWhenReadingNonExistentPublicProperties()
+    {
+        $this->configureInitializerMock(0);
+
+        $class = get_class($this->lazyObject);
+        $this->setExpectedException(
+            'PHPUnit_Framework_Error_Notice',
+            'Undefined property: ' . $class . '::$non_existing_property'
+        );
+
+        $this->lazyObject->non_existing_property;
+    }
+
+    public function testFalseWhenCheckingNonExistentProperty()
+    {
+        $this->configureInitializerMock(0);
+
+        $this->assertFalse(isset($this->lazyObject->non_existing_property));
+    }
+
+    public function testNoErrorWhenSettingNonExistentProperty()
+    {
+        $this->configureInitializerMock(0);
+
+        $this->lazyObject->non_existing_property = 'now has a value';
+        $this->assertSame('now has a value', $this->lazyObject->non_existing_property);
+    }
+
+    public function testCloningCallsClonerWithClonedObject()
+    {
+        $lazyObject = $this->lazyObject;
+        $test = $this;
+        $cb = $this->getMock('stdClass', array('cb'));
+        $cb
+            ->expects($this->once())
+            ->method('cb')
+            ->will($this->returnCallback(function (LazyLoadableObject $proxy) use ($lazyObject, $test) {
+                /* @var $proxy LazyLoadableObject|Proxy */
+                $test->assertNotSame($proxy, $lazyObject);
+                $proxy->__setInitializer(null);
+                $proxy->publicAssociation = 'clonedAssociation';
+            }));
+
+        $this->lazyObject->__setCloner($this->getClosure(array($cb, 'cb')));
+
+        $cloned = clone $this->lazyObject;
+        $this->assertSame('clonedAssociation', $cloned->publicAssociation);
+        $this->assertNotSame($cloned, $lazyObject, 'a clone of the lazy object is retrieved');
+    }
+
+    public function testFetchingTransientPropertiesWillNotTriggerLazyLoading()
+    {
+        $this->configureInitializerMock(0);
+
+        $this->assertSame(
+            'publicTransientFieldValue',
+            $this->lazyObject->publicTransientField,
+            'fetching public transient field won\'t trigger lazy loading'
+        );
+        $property = $this
+            ->lazyLoadableObjectMetadata
+            ->getReflectionClass()
+            ->getProperty('protectedTransientField');
+        $property->setAccessible(true);
+        $this->assertSame(
+            'protectedTransientFieldValue',
+            $property->getValue($this->lazyObject),
+            'fetching protected transient field via reflection won\'t trigger lazy loading'
+        );
+    }
+
+    /**
+     * Provided to guarantee backwards compatibility
+     */
+    public function testLoadProxyMethod()
+    {
+        $this->configureInitializerMock(2, array($this->lazyObject, '__load', array()));
+
+        $this->lazyObject->__load();
+        $this->lazyObject->__load();
+    }
+
+    public function testLoadingWithPersisterWillBeTriggeredOnlyOnce()
+    {
+        $this
+            ->proxyLoader
+            ->expects($this->once())
+            ->method('load')
+            ->with(
+                array(
+                    'publicIdentifierField' => 'publicIdentifierFieldValue',
+                    'protectedIdentifierField' => 'protectedIdentifierFieldValue',
+                ),
+                $this->lazyObject
+            )
+            ->will($this->returnCallback(function ($id, LazyLoadableObject $lazyObject) {
+                // setting a value to verify that the persister can actually set something in the object
+                $lazyObject->publicAssociation = $id['publicIdentifierField'] . '-test';
+                return true;
+            }));
+        $this->lazyObject->__setInitializer($this->getSuggestedInitializerImplementation());
+
+        $this->lazyObject->__load();
+        $this->lazyObject->__load();
+        $this->assertSame('publicIdentifierFieldValue-test', $this->lazyObject->publicAssociation);
+    }
+
+    public function testFailedLoadingWillThrowException()
+    {
+        $this->proxyLoader->expects($this->any())->method('load')->will($this->returnValue(null));
+        $this->setExpectedException('UnexpectedValueException');
+        $this->lazyObject->__setInitializer($this->getSuggestedInitializerImplementation());
+
+        $this->lazyObject->__load();
+    }
+
+    public function testCloningWithPersister()
+    {
+        $this->lazyObject->publicTransientField = 'should-not-change';
+        $this
+            ->proxyLoader
+            ->expects($this->exactly(2))
+            ->method('load')
+            ->with(array(
+                'publicIdentifierField'    => 'publicIdentifierFieldValue',
+                'protectedIdentifierField' => 'protectedIdentifierFieldValue',
+            ))
+            ->will($this->returnCallback(function () {
+                $blueprint = new LazyLoadableObject();
+                $blueprint->publicPersistentField = 'checked-persistent-field';
+                $blueprint->publicAssociation     = 'checked-association-field';
+                $blueprint->publicTransientField  = 'checked-transient-field';
+
+                return $blueprint;
+            }));
+
+        $firstClone = clone $this->lazyObject;
+        $this->assertSame(
+            'checked-persistent-field',
+            $firstClone->publicPersistentField,
+            'Persistent fields are cloned correctly'
+        );
+        $this->assertSame(
+            'checked-association-field',
+            $firstClone->publicAssociation,
+            'Associations are cloned correctly'
+        );
+        $this->assertSame(
+            'should-not-change',
+            $firstClone->publicTransientField,
+            'Transient fields are not overwritten'
+        );
+
+        $secondClone = clone $this->lazyObject;
+        $this->assertSame(
+            'checked-persistent-field',
+            $secondClone->publicPersistentField,
+            'Persistent fields are cloned correctly'
+        );
+        $this->assertSame(
+            'checked-association-field',
+            $secondClone->publicAssociation,
+            'Associations are cloned correctly'
+        );
+        $this->assertSame(
+            'should-not-change',
+            $secondClone->publicTransientField,
+            'Transient fields are not overwritten'
+        );
+
+        // those should not trigger lazy loading
+        $firstClone->__load();
+        $secondClone->__load();
+    }
+
+    public function testNotInitializedProxyUnserialization()
+    {
+        $this->configureInitializerMock();
+
+        $serialized = serialize($this->lazyObject);
+        /* @var $unserialized LazyLoadableObject|Proxy */
+        $unserialized = unserialize($serialized);
+        $reflClass = $this->lazyLoadableObjectMetadata->getReflectionClass();
+
+        $this->assertFalse($unserialized->__isInitialized(), 'serialization didn\'t cause intialization');
+
+        // Checking identifiers
+        $this->assertSame('publicIdentifierFieldValue', $unserialized->publicIdentifierField, 'identifiers are kept');
+        $protectedIdentifierField = $reflClass->getProperty('protectedIdentifierField');
+        $protectedIdentifierField->setAccessible(true);
+        $this->assertSame(
+            'protectedIdentifierFieldValue',
+            $protectedIdentifierField->getValue($unserialized),
+            'identifiers are kept'
+        );
+
+        // Checking transient fields
+        $this->assertSame(
+            'publicTransientFieldValue',
+            $unserialized->publicTransientField,
+            'transient fields are kept'
+        );
+        $protectedTransientField = $reflClass->getProperty('protectedTransientField');
+        $protectedTransientField->setAccessible(true);
+        $this->assertSame(
+            'protectedTransientFieldValue',
+            $protectedTransientField->getValue($unserialized),
+            'transient fields are kept'
+        );
+
+        // Checking persistent fields
+        $this->assertSame(
+            'publicPersistentFieldValue',
+            $unserialized->publicPersistentField,
+            'persistent fields are kept'
+        );
+        $protectedPersistentField = $reflClass->getProperty('protectedPersistentField');
+        $protectedPersistentField->setAccessible(true);
+        $this->assertSame(
+            'protectedPersistentFieldValue',
+            $protectedPersistentField->getValue($unserialized),
+            'persistent fields are kept'
+        );
+
+        // Checking associations
+        $this->assertSame('publicAssociationValue', $unserialized->publicAssociation, 'associations are kept');
+        $protectedAssociationField = $reflClass->getProperty('protectedAssociation');
+        $protectedAssociationField->setAccessible(true);
+        $this->assertSame(
+            'protectedAssociationValue',
+            $protectedAssociationField->getValue($unserialized),
+            'associations are kept'
+        );
+    }
+
+    public function testInitializedProxyUnserialization()
+    {
+        // persister will retrieve the lazy object itself, so that we don't have to re-define all field values
+        $this->proxyLoader->expects($this->once())->method('load')->will($this->returnValue($this->lazyObject));
+        $this->lazyObject->__setInitializer($this->getSuggestedInitializerImplementation());
+        $this->lazyObject->__load();
+
+        $serialized   = serialize($this->lazyObject);
+        $reflClass    = $this->lazyLoadableObjectMetadata->getReflectionClass();
+        /* @var $unserialized LazyLoadableObject|Proxy */
+        $unserialized = unserialize($serialized);
+
+        $this->assertTrue($unserialized->__isInitialized(), 'serialization didn\'t cause intialization');
+
+        // Checking transient fields
+        $this->assertSame(
+            'publicTransientFieldValue',
+            $unserialized->publicTransientField,
+            'transient fields are kept'
+        );
+        $protectedTransientField = $reflClass->getProperty('protectedTransientField');
+        $protectedTransientField->setAccessible(true);
+        $this->assertSame(
+            'protectedTransientFieldValue',
+            $protectedTransientField->getValue($unserialized),
+            'transient fields are kept'
+        );
+
+        // Checking persistent fields
+        $this->assertSame(
+            'publicPersistentFieldValue',
+            $unserialized->publicPersistentField,
+            'persistent fields are kept'
+        );
+        $protectedPersistentField = $reflClass->getProperty('protectedPersistentField');
+        $protectedPersistentField->setAccessible(true);
+        $this->assertSame(
+            'protectedPersistentFieldValue',
+            $protectedPersistentField->getValue($unserialized),
+            'persistent fields are kept'
+        );
+
+        // Checking identifiers
+        $this->assertSame(
+            'publicIdentifierFieldValue',
+            $unserialized->publicIdentifierField,
+            'identifiers are kept'
+        );
+        $protectedIdentifierField = $reflClass->getProperty('protectedIdentifierField');
+        $protectedIdentifierField->setAccessible(true);
+        $this->assertSame(
+            'protectedIdentifierFieldValue',
+            $protectedIdentifierField->getValue($unserialized),
+            'identifiers are kept'
+        );
+
+        // Checking associations
+        $this->assertSame('publicAssociationValue', $unserialized->publicAssociation, 'associations are kept');
+        $protectedAssociationField = $reflClass->getProperty('protectedAssociation');
+        $protectedAssociationField->setAccessible(true);
+        $this->assertSame(
+            'protectedAssociationValue',
+            $protectedAssociationField->getValue($unserialized),
+            'associations are kept'
+        );
+    }
+
+    public function testInitializationRestoresDefaultPublicLazyLoadedFieldValues()
+    {
+        // setting noop persister
+        $this->proxyLoader->expects($this->once())->method('load')->will($this->returnValue($this->lazyObject));
+        $this->lazyObject->__setInitializer($this->getSuggestedInitializerImplementation());
+
+        $this->assertSame(
+            'publicPersistentFieldValue',
+            $this->lazyObject->publicPersistentField,
+            'Persistent field is restored to default value'
+        );
+        $this->assertSame(
+            'publicAssociationValue',
+            $this->lazyObject->publicAssociation,
+            'Association is restored to default value'
+        );
+    }
+
+    public function testSettingPublicFieldsCausesLazyLoading()
+    {
+        $test = $this;
+        $this->configureInitializerMock(
+            1,
+            array($this->lazyObject, '__set', array('publicPersistentField', 'newPublicPersistentFieldValue')),
+            function () use ($test) {
+                $test->setProxyValue('publicPersistentField', 'overrideValue');
+                $test->setProxyValue('publicAssociation', 'newAssociationValue');
+            }
+        );
+
+        $this->lazyObject->publicPersistentField = 'newPublicPersistentFieldValue';
+        $this->assertSame('newPublicPersistentFieldValue', $this->lazyObject->publicPersistentField);
+        $this->assertSame('newAssociationValue', $this->lazyObject->publicAssociation);
+    }
+
+    public function testSettingPublicAssociationCausesLazyLoading()
+    {
+        $test = $this;
+        $this->configureInitializerMock(
+            1,
+            array($this->lazyObject, '__set', array('publicAssociation', 'newPublicAssociationValue')),
+            function () use ($test) {
+                $test->setProxyValue('publicPersistentField', 'newPublicPersistentFieldValue');
+                $test->setProxyValue('publicAssociation', 'overrideValue');
+            }
+        );
+
+        $this->lazyObject->publicAssociation = 'newPublicAssociationValue';
+        $this->assertSame('newPublicAssociationValue', $this->lazyObject->publicAssociation);
+        $this->assertSame('newPublicPersistentFieldValue', $this->lazyObject->publicPersistentField);
+    }
+
+    public function testCheckingPublicFieldsCausesLazyLoading()
+    {
+        $test = $this;
+        $this->configureInitializerMock(
+            1,
+            array($this->lazyObject, '__isset', array('publicPersistentField')),
+            function () use ($test) {
+                $test->setProxyValue('publicPersistentField', null);
+                $test->setProxyValue('publicAssociation', 'setPublicAssociation');
+            }
+        );
+
+        $this->assertFalse(isset($this->lazyObject->publicPersistentField));
+        $this->assertNull($this->lazyObject->publicPersistentField);
+        $this->assertTrue(isset($this->lazyObject->publicAssociation));
+        $this->assertSame('setPublicAssociation', $this->lazyObject->publicAssociation);
+    }
+
+    public function testCheckingPublicAssociationCausesLazyLoading()
+    {
+        $test = $this;
+        $this->configureInitializerMock(
+            1,
+            array($this->lazyObject, '__isset', array('publicAssociation')),
+            function () use ($test) {
+                $test->setProxyValue('publicPersistentField', 'newPersistentFieldValue');
+                $test->setProxyValue('publicAssociation', 'setPublicAssociation');
+            }
+        );
+
+        $this->assertTrue(isset($this->lazyObject->publicAssociation));
+        $this->assertSame('setPublicAssociation', $this->lazyObject->publicAssociation);
+        $this->assertTrue(isset($this->lazyObject->publicPersistentField));
+        $this->assertSame('newPersistentFieldValue', $this->lazyObject->publicPersistentField);
+    }
+
+    /**
+     * Converts a given callable into a closure
+     *
+     * @param  callable $callable
+     * @return \Closure
+     */
+    public function getClosure($callable) {
+        return function () use ($callable) {
+            call_user_func_array($callable, func_get_args());
+        };
+    }
+
+    /**
+     * Configures the current initializer callback mock with provided matcher params
+     *
+     * @param int $expectedCallCount the number of invocations to be expected. If a value< 0 is provided, `any` is used
+     * @param array $callParamsMatch an ordered array of parameters to be expected
+     * @param callable $callbackClosure a return callback closure
+     *
+     * @return \PHPUnit_Framework_MockObject_MockObject|
+     */
+    protected function configureInitializerMock(
+        $expectedCallCount = 0,
+        array $callParamsMatch = null,
+        \Closure $callbackClosure = null
+    ) {
+        if (!$expectedCallCount) {
+            $invocationCountMatcher = $this->exactly((int) $expectedCallCount);
+        } else {
+            $invocationCountMatcher = $expectedCallCount < 0 ? $this->any() : $this->exactly($expectedCallCount);
+        }
+
+        $invocationMocker = $this->initializerCallbackMock->expects($invocationCountMatcher)->method('__invoke');
+
+        if (null !== $callParamsMatch) {
+            call_user_func_array(array($invocationMocker, 'with'), $callParamsMatch);
+        }
+
+        if ($callbackClosure) {
+            $invocationMocker->will($this->returnCallback($callbackClosure));
+        }
+    }
+
+    /**
+     * Sets a value in the current proxy object without triggering lazy loading through `__set`
+     *
+     * @link https://bugs.php.net/bug.php?id=63463
+     *
+     * @param string $property
+     * @param mixed $value
+     */
+    public function setProxyValue($property, $value)
+    {
+        $reflectionProperty = new \ReflectionProperty($this->lazyObject, $property);
+        $initializer        = $this->lazyObject->__getInitializer();
+
+        // disabling initializer since setting `publicPersistentField` triggers `__set`/`__get`
+        $this->lazyObject->__setInitializer(null);
+        $reflectionProperty->setValue($this->lazyObject, $value);
+        $this->lazyObject->__setInitializer($initializer);
+    }
+
+    /**
+     * Retrieves the suggested implementation of an initializer that proxy factories in O*M
+     * are currently following, and that should be used to initialize the current proxy object
+     *
+     * @return \Closure
+     */
+    protected function getSuggestedInitializerImplementation()
+    {
+        $loader     = $this->proxyLoader;
+        $identifier = $this->identifier;
+
+        return function (LazyLoadableObject $proxy) use ($loader, $identifier) {
+            /* @var $proxy LazyLoadableObject|Proxy */
+            $proxy->__setInitializer(null);
+            $proxy->__setCloner(null);
+
+
+            if ($proxy->__isInitialized()) {
+                return;
+            }
+
+            $properties = $proxy->__getLazyProperties();
+
+            foreach ($properties as $propertyName => $property) {
+                if (!isset($proxy->$propertyName)) {
+                    $proxy->$propertyName = $properties[$propertyName];
+                }
+            }
+
+            $proxy->__setInitialized(true);
+
+            if (method_exists($proxy, '__wakeup')) {
+                $proxy->__wakeup();
+            }
+
+            if (null === $loader->load($identifier, $proxy)) {
+                throw new \UnexpectedValueException('Couldn\'t load');
+            }
+        };
+    }
+}

+ 19 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Proxy/SleepClass.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Doctrine\Tests\Common\Proxy;
+
+/**
+ * Test asset class
+ */
+class SleepClass
+{
+    public $id;
+
+    /**
+     * @return array
+     */
+    public function __sleep()
+    {
+        return array('id');
+    }
+}

+ 192 - 0
vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/DeeperNamespaceParent.php

@@ -0,0 +1,192 @@
+<?php
+
+namespace Doctrine\Tests\Common\Reflection;
+
+use PHPUnit_Framework_TestCase;
+use Doctrine\Common\Reflection\RuntimePublicReflectionProperty;
+use Doctrine\Common\Proxy\Proxy;
+
+class RuntimePublicReflectionPropertyTest extends PHPUnit_Framework_TestCase
+{
+    public function testGetValueOnProxyPublicProperty()
+    {
+        $getCheckMock = $this->getMock('stdClass', array('callGet'));
+        $getCheckMock->expects($this->never())->method('callGet');
+        $initializer = function () use ($getCheckMock) {
+            call_user_func($getCheckMock);
+        };
+
+        $mockProxy = new RuntimePublicReflectionPropertyTestProxyMock();
+        $mockProxy->__setInitializer($initializer);
+
+        $reflProperty = new RuntimePublicReflectionProperty(
+            __NAMESPACE__ . '\RuntimePublicReflectionPropertyTestProxyMock',
+            'checkedProperty'
+        );
+
+        $this->assertSame('testValue', $reflProperty->getValue($mockProxy));
+        unset($mockProxy->checkedProperty);
+        $this->assertNull($reflProperty->getValue($mockProxy));
+    }
+
+    public function testSetValueOnProxyPublicProperty()
+    {
+        $setCheckMock = $this->getMock('stdClass', array('neverCallSet'));
+        $setCheckMock->expects($this->never())->method('neverCallSet');
+        $initializer = function () use ($setCheckMock) {
+            call_user_func(array($setCheckMock, 'neverCallSet'));
+        };
+
+        $mockProxy = new RuntimePublicReflectionPropertyTestProxyMock();
+        $mockProxy->__setInitializer($initializer);
+
+        $reflProperty = new RuntimePublicReflectionProperty(
+            __NAMESPACE__ . '\RuntimePublicReflectionPropertyTestProxyMock',
+            'checkedProperty'
+        );
+
+        $reflProperty->setValue($mockProxy, 'newValue');
+        $this->assertSame('newValue', $mockProxy->checkedProperty);
+
+        unset($mockProxy->checkedProperty);
+        $reflProperty->setValue($mockProxy, 'otherNewValue');
+        $this->assertSame('otherNewValue', $mockProxy->checkedProperty);
+
+        $setCheckMock = $this->getMock('stdClass', array('callSet'));
+        $setCheckMock->expects($this->once())->method('callSet');
+        $initializer = function () use ($setCheckMock) {
+            call_user_func(array($setCheckMock, 'callSet'));
+        };
+
+        $mockProxy->__setInitializer($initializer);
+        $mockProxy->__setInitialized(true);
+
+        unset($mockProxy->checkedProperty);
+        $reflProperty->setValue($mockProxy, 'againNewValue');
+        $this->assertSame('againNewValue', $mockProxy->checkedProperty);
+    }
+}
+
+/**
+ * Mock that simulates proxy public property lazy loading
+ */
+class RuntimePublicReflectionPropertyTestProxyMock implements Proxy
+{
+    /**
+     * @var \Closure|null
+     */
+    private $initializer     = null;
+
+    /**
+     * @var \Closure|null
+     */
+    private $initialized     = false;
+
+    /**
+     * @var string
+     */
+    public  $checkedProperty = 'testValue';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function __getInitializer()
+    {
+        return $this->initializer;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function __setInitializer(\Closure $initializer = null)
+    {
+        $this->initializer = $initializer;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function __getLazyProperties()
+    {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function __load()
+    {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function __isInitialized()
+    {
+        return $this->initialized;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function __setInitialized($initialized)
+    {
+        $this->initialized = (bool) $initialized;
+    }
+
+    /**
+     * @param string $name
+     */
+    public function __get($name)
+    {
+        if ($this->initializer) {
+            $cb = $this->initializer;
+            $cb();
+        }
+
+        return $this->checkedProperty;
+    }
+
+    /**
+     * @param string $name
+     * @param mixed  $value
+     */
+    public function __set($name, $value)
+    {
+        if ($this->initializer) {
+            $cb = $this->initializer;
+            $cb();
+        }
+
+        // triggers notices if `$name` is used: see https://bugs.php.net/bug.php?id=63463
+        $this->checkedProperty = $value;
+    }
+
+    /**
+     * @param string $name
+     *
+     * @return integer
+     */
+    public function __isset($name)
+    {
+        if ($this->initializer) {
+            $cb = $this->initializer;
+            $cb();
+        }
+
+        return isset($this->checkedProperty);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function __setCloner(\Closure $cloner = null)
+    {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function __getCloner()
+    {
+    }
+}

+ 2 - 7
vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/SameNamespaceParent.php

@@ -14,18 +14,13 @@ spl_autoload_register(function($class)
         if (is_file($path) && is_readable($path)) {
             require_once $path;
 
-            return true;
-        }
-    } else if (0 === strpos($class, 'Doctrine\Common\\')) {
-        $path = __DIR__.'/../../../lib/'.($class = strtr($class, '\\', '/')).'.php';
-        if (is_file($path) && is_readable($path)) {
-            require_once $path;
-
             return true;
         }
     }
 });
 
+require_once __DIR__ . "/../../../vendor/autoload.php";
+
 \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
     'Doctrine\Tests\Common\Annotations\Fixtures', __DIR__ . '/../../'
 );

+ 3 - 2
vendor/doctrine/common/tests/NativePhpunitTask.php

@@ -577,11 +577,12 @@ class Connection implements DriverConnection
      *
      * @param string $sql The SQL query.
      * @param array $params The query parameters.
+     * @param array $types Query parameter types.
      * @return array
      */
-    public function fetchAll($sql, array $params = array())
+    public function fetchAll($sql, array $params = array(), $types = array())
     {
-        return $this->executeQuery($sql, $params)->fetchAll();
+        return $this->executeQuery($sql, $params, $types)->fetchAll();
     }
 
     /**

+ 3 - 21
vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php

@@ -1193,27 +1193,15 @@ abstract class AbstractPlatform
                 }
             }
 
-            $columnData = array();
+            $columnData = $column->toArray();
             $columnData['name'] = $column->getQuotedName($this);
-            $columnData['type'] = $column->getType();
-            $columnData['length'] = $column->getLength();
-            $columnData['notnull'] = $column->getNotNull();
-            $columnData['fixed'] = $column->getFixed();
-            $columnData['unique'] = false; // TODO: what do we do about this?
             $columnData['version'] = $column->hasPlatformOption("version") ? $column->getPlatformOption('version') : false;
+            $columnData['comment'] = $this->getColumnComment($column);
 
             if (strtolower($columnData['type']) == "string" && $columnData['length'] === null) {
                 $columnData['length'] = 255;
             }
 
-            $columnData['unsigned'] = $column->getUnsigned();
-            $columnData['precision'] = $column->getPrecision();
-            $columnData['scale'] = $column->getScale();
-            $columnData['default'] = $column->getDefault();
-            $columnData['columnDefinition'] = $column->getColumnDefinition();
-            $columnData['autoincrement'] = $column->getAutoincrement();
-            $columnData['comment'] = $this->getColumnComment($column);
-
             if (in_array($column->getName(), $options['primary'])) {
                 $columnData['primary'] = true;
             }
@@ -1905,17 +1893,11 @@ abstract class AbstractPlatform
      */
     public function getIndexDeclarationSQL($name, Index $index)
     {
-        $type = '';
-
-        if ($index->isUnique()) {
-            $type = 'UNIQUE ';
-        }
-
         if (count($index->getColumns()) === 0) {
             throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
         }
 
-        return $type . 'INDEX ' . $name . ' ('
+        return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ('
              . $this->getIndexFieldDeclarationListSQL($index->getColumns())
              . ')';
     }

+ 1 - 0
vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php

@@ -722,6 +722,7 @@ class PostgreSqlPlatform extends AbstractPlatform
             '_varchar'      => 'string',
             'char'          => 'string',
             'bpchar'        => 'string',
+            'inet'          => 'string',
             'date'          => 'date',
             'datetime'      => 'datetime',
             'timestamp'     => 'datetime',

+ 8 - 0
vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php

@@ -602,6 +602,14 @@ class SqlitePlatform extends AbstractPlatform
         return true;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public function supportsForeignKeyConstraints()
+    {
+        return false;
+    }
+
     /**
      * {@inheritDoc}
      */

+ 13 - 0
vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Connection.php

@@ -248,6 +248,19 @@ class ExpressionBuilder
     {
         return $this->comparison($x, 'LIKE', $y);
     }
+    
+    /**
+     * Creates a NOT LIKE() comparison expression with the given arguments.
+     *
+     * @param string $x Field in string format to be inspected by NOT LIKE() comparison.
+     * @param mixed $y Argument to be used in NOT LIKE() comparison.
+     *
+     * @return string
+     */
+    public function notLike($x, $y)
+    {
+        return $this->comparison($x, 'NOT LIKE', $y);
+    }
 
     /**
      * Creates a IN () comparison expression with the given arguments.

+ 32 - 0
vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php

@@ -186,6 +186,38 @@ class DataAccessTest extends \Doctrine\Tests\DbalFunctionalTestCase
         $this->assertEquals('foo', $row['test_string']);
     }
 
+    /**
+     * @group DBAL-209
+     */
+    public function testFetchAllWithTypes()
+    {
+        $datetimeString = '2010-01-01 10:10:10';
+        $datetime = new \DateTime($datetimeString);
+        $sql = "SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?";
+        $data = $this->_conn->fetchAll($sql, array(1, $datetime), array(PDO::PARAM_STR, Type::DATETIME));
+
+        $this->assertEquals(1, count($data));
+
+        $row = $data[0];
+        $this->assertEquals(2, count($row));
+
+        $row = array_change_key_case($row, \CASE_LOWER);
+        $this->assertEquals(1, $row['test_int']);
+        $this->assertEquals($datetimeString, $row['test_datetime']);        
+    }
+    
+    /**
+     * @group DBAL-209
+     * @expectedException \Doctrine\DBAL\DBALException
+     */
+    public function testFetchAllWithMissingTypes()
+    {
+        $datetimeString = '2010-01-01 10:10:10';
+        $datetime = new \DateTime($datetimeString);
+        $sql = "SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?";
+        $data = $this->_conn->fetchAll($sql, array(1, $datetime));
+    }
+
     public function testFetchBoth()
     {
         $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";

+ 18 - 1
vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/LoggingTest.php

@@ -47,4 +47,21 @@ class MySqlSchemaManagerTest extends SchemaManagerFunctionalTestCase
 
         $this->assertFalse($diff, "no changes expected.");
     }
-}
+
+    public function testFulltextIndex()
+    {
+        $table = new Table('fulltext_index');
+        $table->addColumn('text', 'text');
+        $table->addIndex(array('text'), 'f_index');
+        $table->addOption('engine', 'MyISAM');
+
+        $index = $table->getIndex('f_index');
+        $index->addFlag('fulltext');
+
+        $this->_sm->dropAndCreateTable($table);
+
+        $indexes = $this->_sm->listTableIndexes('fulltext_index');
+        $this->assertArrayHasKey('f_index', $indexes);
+        $this->assertTrue($indexes['f_index']->hasFlag('fulltext'));
+    }
+}

+ 8 - 6
vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php

@@ -433,12 +433,14 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
         // dont check for index size here, some platforms automatically add indexes for foreign keys.
         $this->assertFalse($table->hasIndex('foo_idx'));
 
-        $this->assertEquals(1, count($table->getForeignKeys()));
-        $fks = $table->getForeignKeys();
-        $foreignKey = current($fks);
-        $this->assertEquals('alter_table_foreign', strtolower($foreignKey->getForeignTableName()));
-        $this->assertEquals(array('foreign_key_test'), array_map('strtolower', $foreignKey->getColumns()));
-        $this->assertEquals(array('id'), array_map('strtolower', $foreignKey->getForeignColumns()));
+        if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
+            $fks = $table->getForeignKeys();
+            $this->assertCount(1, $fks);
+            $foreignKey = current($fks);
+            $this->assertEquals('alter_table_foreign', strtolower($foreignKey->getForeignTableName()));
+            $this->assertEquals(array('foreign_key_test'), array_map('strtolower', $foreignKey->getColumns()));
+            $this->assertEquals(array('id'), array_map('strtolower', $foreignKey->getForeignColumns()));
+        }
     }
 
     public function testCreateAndListViews()

+ 16 - 1
vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php

@@ -10,7 +10,7 @@ use Doctrine\DBAL\Schema\TableDiff;
 abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase
 {
     /**
-     * @var Doctrine\DBAL\Platforms\AbstractPlatform
+     * @var \Doctrine\DBAL\Platforms\AbstractPlatform
      */
     protected $_platform;
 
@@ -156,6 +156,21 @@ abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase
         $this->assertEquals($this->getGenerateConstraintForeignKeySql(), $sql);
     }
 
+    public function testGeneratesForeignKeySqlOnlyWhenSupportingForeignKeys()
+    {
+        $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('fk_name'), 'foreign', array('id'), 'constraint_fk');
+
+        if ($this->_platform->supportsForeignKeyConstraints()) {
+            $this->assertInternalType(
+                'string',
+                $this->_platform->getCreateForeignKeySQL($fk, 'test')
+            );
+        } else {
+            $this->setExpectedException('Doctrine\DBAL\DBALException');
+            $this->_platform->getCreateForeignKeySQL($fk, 'test');
+        }
+    }
+
     protected function getBitAndComparisonExpressionSql($value1, $value2)
     {
         return '(' . $value1 . ' & ' . $value2 . ')';

+ 14 - 0
vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php

@@ -240,4 +240,18 @@ class MySqlPlatformTest extends AbstractPlatformTestCase
             'CREATE TABLE `quoted` (`key` VARCHAR(255) NOT NULL, INDEX IDX_22660D028A90ABA9 (`key`)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'
         );
     }
+
+    public function testCreateTableWithFulltextIndex()
+    {
+        $table = new Table('fulltext_table');
+        $table->addOption('engine', 'MyISAM');
+        $table->addColumn('text', 'text');
+        $table->addIndex(array('text'), 'fulltext_text');
+
+        $index = $table->getIndex('fulltext_text');
+        $index->addFlag('fulltext');
+
+        $sql = $this->_platform->getCreateTableSQL($table);
+        $this->assertEquals(array('CREATE TABLE fulltext_table (text LONGTEXT NOT NULL, FULLTEXT INDEX fulltext_text (text)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = MyISAM'), $sql);
+    }
 }

+ 1 - 1
vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php

@@ -118,7 +118,7 @@ EOT
     {
         $currentPlatform = $configuration->getConnection()->getDatabasePlatform()->getName();
         $code = array(
-            "\$this->abortIf(\$this->connection->getDatabasePlatform()->getName() != \"$currentPlatform\");", "",
+            "\$this->abortIf(\$this->connection->getDatabasePlatform()->getName() != \"$currentPlatform\", \"Migration can only be executed safely on '$currentPlatform'.\");", "",
         );
         foreach ($sql as $query) {
             if (strpos($query, $configuration->getMigrationsTableName()) !== false) {

+ 2 - 2
vendor/doctrine/migrations/lib/Doctrine/DBAL/Migrations/Tools/Console/Command/ExecuteCommand.php

@@ -53,13 +53,13 @@ class Version<version> extends AbstractMigration
 {
     public function up(Schema $schema)
     {
-        // this up() migration is autogenerated, please modify it to your needs
+        // this up() migration is auto-generated, please modify it to your needs
 <up>
     }
 
     public function down(Schema $schema)
     {
-        // this down() migration is autogenerated, please modify it to your needs
+        // this down() migration is auto-generated, please modify it to your needs
 <down>
     }
 }

+ 8 - 0
vendor/doctrine/migrations/lib/Doctrine/DBAL/Migrations/Tools/Console/Command/MigrateCommand.php

@@ -1,3 +1,11 @@
+# Upgrade to 2.4
+
+## OnFlush and PostFlush event always called
+
+Before 2.4 the postFlush and onFlush events were only called when there were
+actually entities that changed. Now these events are called no matter if there
+are entities in the UoW or changes are found.
+
 # Upgrade to 2.3
 
 ## EntityManager#find() not calls EntityRepository#find() anymore

+ 1 - 1
vendor/doctrine/orm/bin/doctrine-pear.php

@@ -14,7 +14,7 @@
     "require": {
         "php": ">=5.3.2",
         "ext-pdo": "*",
-        "doctrine/dbal": ">=2.3-dev,<2.5-dev",
+        "doctrine/dbal": ">=2.4-dev,<2.5-dev",
         "symfony/console": "2.*"
     },
     "suggest": {

+ 21 - 2
vendor/doctrine/orm/doctrine-mapping.xsd

@@ -19,6 +19,9 @@
 
 namespace Doctrine\ORM\Proxy;
 
+use Doctrine\ORM\Configuration;
+use Closure;
+
 /**
  * Special Autoloader for Proxy classes because them not being PSR-0 compatible.
  *
@@ -61,7 +64,7 @@ class Autoloader
      *
      * @return \Closure
      */
-    static public function register($proxyDir, $proxyNamespace, \Closure $notFoundCallback = null)
+    static public function register($proxyDir, $proxyNamespace, Closure $notFoundCallback = null)
     {
         $proxyNamespace = ltrim($proxyNamespace, "\\");
         $autoloader = function($className) use ($proxyDir, $proxyNamespace, $notFoundCallback) {
@@ -75,7 +78,23 @@ class Autoloader
                 require $file;
             }
         };
-        spl_autoload_register($autoloader);
+
+        spl_autoload_register($autoloader, true, true);
+
         return $autoloader;
     }
+
+    /**
+     * Registers and returns autoloader callback from a Configuration instance
+     *
+     * @param Configuration $config
+     * @param \Closure $notFoundCallback
+     *
+     * @return \Closure
+     */
+    static public function registerFromConfiguration(Configuration $configuration, Closure $notFoundCallback)
+    {
+        return self::register($configuration->getProxyDir(), $configuration->getProxyNamespace(), $notFoundCallback);
+    }
 }
+

+ 12 - 0
vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Proxy.php

@@ -163,6 +163,18 @@ class FilterCollection
         return $this->enabledFilters[$name];
     }
 
+    /**
+     * Checks if a filter is enabled.
+     * 
+     * @param string $name Name of the filter.
+     * 
+     * @return boolean True if the filter is enabled, false otherwise.
+     */
+    public function isEnabled($name)
+    {
+        return isset($this->enabledFilters[$name]);
+    }
+    
     /**
      * @return boolean True, if the filter collection is clean.
      */

+ 9 - 2
vendor/doctrine/orm/lib/Doctrine/ORM/Query/Lexer.php

@@ -532,6 +532,13 @@ class QueryBuilder
      */
     public function add($dqlPartName, $dqlPart, $append = false)
     {
+        if ($append && ($dqlPartName === "where" || $dqlPartName === "having")) {
+            throw new \InvalidArgumentException(
+                "Using \$append = true does not have an effect with 'where' or 'having' ".
+                "parts. See QueryBuilder#andWhere() for an example for correct usage."
+            );
+        }
+
         $isMultiple = is_array($this->_dqlParts[$dqlPartName]);
 
         // This is introduced for backwards compatibility reasons.
@@ -898,7 +905,7 @@ class QueryBuilder
             $where = new Expr\Andx($args);
         }
 
-        return $this->add('where', $where, true);
+        return $this->add('where', $where);
     }
 
     /**
@@ -931,7 +938,7 @@ class QueryBuilder
             $where = new Expr\Orx($args);
         }
 
-        return $this->add('where', $where, true);
+        return $this->add('where', $where);
     }
 
     /**

+ 19 - 8
vendor/doctrine/orm/lib/Doctrine/ORM/README.markdown

@@ -287,6 +287,9 @@ class UnitOfWork implements PropertyChangedListener
                 $this->collectionUpdates ||
                 $this->collectionDeletions ||
                 $this->orphanRemovals)) {
+            $this->dispatchOnFlushEvent();
+            $this->dispatchPostFlushEvent();
+
             return; // Nothing to do.
         }
 
@@ -296,10 +299,7 @@ class UnitOfWork implements PropertyChangedListener
             }
         }
 
-        // Raise onFlush
-        if ($this->evm->hasListeners(Events::onFlush)) {
-            $this->evm->dispatchEvent(Events::onFlush, new Event\OnFlushEventArgs($this->em));
-        }
+        $this->dispatchOnFlushEvent();
 
         // Now we need a commit order to maintain referential integrity
         $commitOrder = $this->getCommitOrder();
@@ -354,10 +354,7 @@ class UnitOfWork implements PropertyChangedListener
             $coll->takeSnapshot();
         }
 
-        // Raise postFlush
-        if ($this->evm->hasListeners(Events::postFlush)) {
-            $this->evm->dispatchEvent(Events::postFlush, new Event\PostFlushEventArgs($this->em));
-        }
+        $this->dispatchPostFlushEvent();
 
         // Clear up
         $this->entityInsertions =
@@ -3153,4 +3150,18 @@ class UnitOfWork implements PropertyChangedListener
 
         return isset($this->readOnlyObjects[spl_object_hash($object)]);
     }
+
+    private function dispatchOnFlushEvent()
+    {
+        if ($this->evm->hasListeners(Events::onFlush)) {
+            $this->evm->dispatchEvent(Events::onFlush, new Event\OnFlushEventArgs($this->em));
+        }
+    }
+
+    private function dispatchPostFlushEvent()
+    {
+        if ($this->evm->hasListeners(Events::postFlush)) {
+            $this->evm->dispatchEvent(Events::postFlush, new Event\PostFlushEventArgs($this->em));
+        }
+    }
 }

+ 42 - 0
vendor/doctrine/orm/lib/Doctrine/ORM/Version.php

@@ -48,6 +48,27 @@ class FlushEventTest extends \Doctrine\Tests\OrmFunctionalTestCase
         //echo "SECOND FLUSH";
         //$this->_em->flush();
     }
+
+    /**
+     * @group DDC-2173
+     */
+    public function testPreAndOnFlushCalledAlways()
+    {
+        $listener = new OnFlushCalledListener();
+        $this->_em->getEventManager()->addEventListener(Events::onFlush, $listener);
+        $this->_em->getEventManager()->addEventListener(Events::preFlush, $listener);
+        $this->_em->getEventManager()->addEventListener(Events::postFlush, $listener);
+
+        $this->_em->flush();
+
+        $this->assertEquals(1, $listener->preFlush);
+        $this->assertEquals(1, $listener->onFlush);
+
+        $this->_em->flush();
+
+        $this->assertEquals(2, $listener->preFlush);
+        $this->assertEquals(2, $listener->onFlush);
+    }
 }
 
 class OnFlushListener
@@ -91,4 +112,25 @@ class OnFlushListener
     }
 }
 
+class OnFlushCalledListener
+{
+    public $preFlush = 0;
+    public $onFlush = 0;
+    public $postFlush = 0;
+
+    public function preFlush($args)
+    {
+        $this->preFlush++;
+    }
+
+    public function onFlush($args)
+    {
+        $this->onFlush++;
+    }
+
+    public function postFlush($args)
+    {
+        $this->postFlush++;
+    }
+}
 

+ 20 - 0
vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/HydrationCacheTest.php

@@ -172,6 +172,26 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase
         $this->assertTrue($exceptionThrown);
     }
 
+    /**
+     * @group DDC-2203
+     */
+    public function testEntityManagerIsFilterEnabled()
+    {
+        $em = $this->_getEntityManager();
+        $this->configureFilters($em);
+
+        // Check for an enabled filter
+        $em->getFilters()->enable("locale");
+        $this->assertTrue($em->getFilters()->isEnabled("locale"));
+
+        // Check for a disabled filter
+        $em->getFilters()->disable("locale");
+        $this->assertFalse($em->getFilters()->isEnabled("locale"));
+        
+        // Check a non-existing filter
+        $this->assertFalse($em->getFilters()->isEnabled("foo_filter"));        
+    }
+    
     protected function configureFilters($em)
     {
         // Add filters to the configuration of the EM

+ 13 - 0
vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/CompanySchemaTest.php

@@ -834,4 +834,17 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
 
         $this->assertEquals('SELECT DISTINCT u FROM Doctrine\Tests\Models\CMS\CmsUser u', $qb->getDQL());
     }
+
+    /**
+     * @group DDC-2192
+     */
+    public function testWhereAppend()
+    {
+        $this->setExpectedException('InvalidArgumentException', "Using \$append = true does not have an effect with 'where' or 'having' parts. See QueryBuilder#andWhere() for an example for correct usage.");
+
+        $qb = $this->_em->createQueryBuilder()
+            ->add('where', 'u.foo = ?1')
+            ->add('where', 'u.bar = ?2', true)
+        ;
+    }
 }

+ 17 - 0
vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommandTest.php

@@ -0,0 +1,17 @@
+language: php
+
+php:
+  - 5.3
+  - 5.4
+
+services: mongodb
+
+before_script:
+  - pecl install mongo
+  - composer install --dev
+
+script: phpunit --coverage-text -c tests/
+
+notifications:
+  email:
+    - gediminas.morkevicius@gmail.com

+ 21 - 0
vendor/gedmo/doctrine-extensions/LICENSE

@@ -0,0 +1,21 @@
+Copyright (c) 2011-2012 Gediminas Morkevičius
+
+The MIT license, reference http://www.opensource.org/licenses/mit-license.php
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 173 - 0
vendor/gedmo/doctrine-extensions/README.md

@@ -0,0 +1,173 @@
+# Doctrine2 behavioral extensions
+
+## I'm looking for maintainers of this project
+
+Feel free to open discusion in issue or email message if you are interested in maintaining,
+refactoring doctrine2 extensions. The repository can be moved to the maintainers account and fork
+left on mine. I do not want users to lose availability of stable extensions which they were and are
+used to, at the moment.
+
+**Version 2.3.2**
+
+[![Build Status](https://secure.travis-ci.org/l3pp4rd/DoctrineExtensions.png?branch=master)](http://travis-ci.org/l3pp4rd/DoctrineExtensions)
+
+**Note:** recently doctrine orm and odm were updated to use common doctrine mapping persistense
+layer. The support for it has been made and tagged with **2.3.1** version tag. It will be compatible
+with latest version of doctrine mapping at master branches
+
+### Latest updates
+
+**2012-12-06**
+
+- **Blameable** extension added to allow setting a username string or user object on fields, with the same options as Timestampable.
+
+
+**2012-07-05**
+
+- **Mapping** drivers were updated to support latest doctrine versions.
+
+**2012-05-01**
+
+- **Sluggable** now allows to regenerate slug if its set to empty or null. Also it allows to
+manually set the slug, in that case it would only transliterate it and ensure uniqueness.
+
+**2012-04-09**
+
+- **Translatable** now does not force lowercase letters on locale or language. If your database is case
+sensitive, take this into account and upgrade your current translations in the database. This change
+will not be backported into 2.2 or older versions of extensions and will be available in comming
+releases.
+- **Sortable** now handles and synchronizes all object sort positions which are allready in memory
+of unitOfWork. Which does not require to do **$em->clear()** after each operation anymore.
+
+**2012-03-04**
+
+- We should be very grateful for contributions of [comfortablynumb](http://github.com/comfortablynumb)
+He has contributed most to these extensions and recently - long waited [softdeleteable
+behavior](https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/softdeleteable.md) for **ORM** users. Also most important, there
+was a tree extension missing for **ODM** now everyone can enjoy [materialized path tree strategy](https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/tree.md#materialized-path) for **ORM** including.
+
+**2012-02-26**
+
+- Removed slug handlers, this functionality brought complications which could not be maintained.
+
+**2012-02-15**
+
+- Add option to force **Translatable** store translation in default locale like any other.
+See [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/translatable.md#advanced-examples)
+
+**2012-01-29**
+
+- Translatable finally has **Personal Translations** which can relate through a real **foreign key**
+constraint and be used as a standard doctrine collection. This allows to configure domain
+objects anyway you prefere and still enjoy all features **Translatable** provides.
+- There were **BC** breaks introduced in **master** branch of extensions which is
+based on **doctrine2.3.x** version. If you are not interested in upgrading you can
+safely checkout at **2.2.x** or **2.1.x** [tag](http://github.com/l3pp4rd/DoctrineExtensions/tags).
+To upgrade your source code follow the [upgrade guide](https://github.com/l3pp4rd/DoctrineExtensions/blob/master/upgrade/2-3-0.md)
+- Library now can map only **MappedSuperclass**es which would avoid generation of **ext_**
+tables which might not be used. Also it provides [convinient methods](https://github.com/l3pp4rd/DoctrineExtensions/blob/master/lib/Gedmo/DoctrineExtensions.php#L66)
+to hook extension metadata drivers into metadata driver chain.
+- [Example demo application](https://github.com/l3pp4rd/DoctrineExtensions/blob/master/example/em.php) has a detailed configuration provided, which
+explains and shows how extensions can or should be used with **Doctrine2** ORM. To install
+it follow the [steps](#example-demo).
+
+### Summary and features
+
+This package contains extensions for Doctrine2 that hook into the facilities of Doctrine and
+offer new functionality or tools to use Doctrine2 more efficently. This package contains mostly
+used behaviors which can be easily attached to your event system of Doctrine2 and handle the
+records being flushed in the behavioral way. List of extensions:
+
+- **Tree** - this extension automates the tree handling process and adds some tree specific functions on repository.
+(**closure**, **nestedset** or **materialized path**)
+- **Translatable** - gives you a very handy solution for translating records into diferent languages. Easy to setup, easier to use.
+- **Sluggable** - urlizes your specified fields into single unique slug
+- **Timestampable** - updates date fields on create, update and even property change.
+- **Blameable** - updates string or reference fields on create, update and even property change with a string or object (e.g. user).
+- **Loggable** - helps tracking changes and history of objects, also supports version managment.
+- **Sortable** - makes any document or entity sortable
+- **Translator** - explicit way to handle translations
+- **Softdeleteable** - allows to implicitly remove records
+- **Uploadable** - provides file upload handling in entity fields
+
+Currently these extensions support **Yaml**, **Annotation**  and **Xml** mapping. Additional mapping drivers
+can be easily implemented using Mapping extension to handle the additional metadata mapping.
+
+**Note:** Please note, that xml mapping needs to be in a different namespace, the declared namespace for
+Doctrine extensions is http://gediminasm.org/schemas/orm/doctrine-extensions-mapping
+So root node now looks like this:
+
+**Note:** Use 2.1.x tag in order to use extensions based on Doctrine2.1.x versions. Currently
+master branch is based on 2.2.x versions and may not work with 2.1.x
+
+```
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                 xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+...
+</doctrine-mapping>
+```
+
+XML mapping xsd schemas are also versioned and can be used by version suffix:
+
+- Latest version - **http://gediminasm.org/schemas/orm/doctrine-extensions-mapping**
+- 2.2.x version - **http://gediminasm.org/schemas/orm/doctrine-extensions-mapping-2-2**
+- 2.1.x version - **http://gediminasm.org/schemas/orm/doctrine-extensions-mapping-2-1**
+
+### ODM MongoDB support
+
+List of extensions which support ODM
+
+- Translatable
+- Sluggable
+- Timestampable
+- Blameable
+- Loggable
+- Translator
+- Tree (Materialized Path strategy for now)
+
+All these extensions can be nested together and mapped in traditional ways - annotations,
+xml or yaml
+
+You can test these extensions on [my blog](http://gediminasm.org/demo "Test doctrine behavioral extensions").
+All tutorials for basic usage examples are on [my blog](http://gediminasm.org "Tutorials for extensions") too.
+You can also fork or clone this blog from [github repository](https://github.com/l3pp4rd/gediminasm.org)
+
+### Running the tests:
+
+PHPUnit 3.6 or newer is required.
+To setup and run tests follow these steps:
+
+- go to the root directory of extensions
+- download composer: **wget https://getcomposer.org/composer.phar**
+- install dev libraries: **php composer.phar install --dev**
+- run: **phpunit -c tests**
+- optional - run mongodb service if targetting mongo tests
+
+<a name="example-demo"></a>
+
+### Running the example:
+
+To setup and run example follow these steps:
+
+- go to the root directory of extensions
+- download composer: **wget https://getcomposer.org/composer.phar**
+- install dev libraries: **php composer.phar install --dev**
+- edit **example/em.php** and configure your database on top of the file
+- run: **./example/bin/console** or **php example/bin/console** for console commands
+- run: **./example/bin/console orm:schema-tool:create** to create schema
+- run: **php example/run.php** to run example
+
+### Contributors:
+
+Thanks to [everyone participating](http://github.com/l3pp4rd/DoctrineExtensions/contributors) in
+the development of these great Doctrine2 extensions!
+
+And especialy ones who create and maintain new extensions:
+
+- Lukas Botsch [lbotsch](http://github.com/lbotsch)
+- Gustavo Adrian [comfortablynumb](http://github.com/comfortablynumb)
+- Boussekeyt Jules [gordonslondon](http://github.com/gordonslondon)
+- Kudryashov Konstantin [everzet](http://github.com/everzet)
+- David Buchmann [dbu](https://github.com/dbu)
+

+ 31 - 0
vendor/gedmo/doctrine-extensions/bin/clear_temp.php

@@ -0,0 +1,31 @@
+<?php
+
+$location = __DIR__ . '/../tests/temp';
+define('VENDOR_PATH', realpath(__DIR__ . '/../vendor'));
+
+set_include_path(implode(PATH_SEPARATOR, array(
+    VENDOR_PATH,
+    get_include_path(),
+)));
+
+$classLoaderFile = VENDOR_PATH . '/doctrine-common/lib/Doctrine/Common/ClassLoader.php';
+if (!file_exists($classLoaderFile)) {
+    die('cannot find vendor, run: php bin/vendors.php');
+}
+
+require_once $classLoaderFile;
+$classLoader = new Doctrine\Common\ClassLoader('Symfony');
+$classLoader->register();
+
+$finder = new Symfony\Component\Finder\Finder;
+$finder->files()
+    ->name('*')
+    ->in(__DIR__ . '/../tests/temp');
+
+foreach ($finder as $fileInfo) {
+    if (!$fileInfo->isWritable()) {
+        continue;
+    }
+    echo 'removing: ' . $fileInfo->getRealPath() . PHP_EOL;
+    @unlink($fileInfo->getRealPath());
+}

+ 48 - 0
vendor/gedmo/doctrine-extensions/bin/purify.php

@@ -0,0 +1,48 @@
+<?php
+
+define('VENDOR_PATH', realpath(__DIR__ . '/../vendor'));
+
+set_include_path(implode(PATH_SEPARATOR, array(
+    VENDOR_PATH,
+    get_include_path(),
+)));
+
+$classLoaderFile = VENDOR_PATH . '/doctrine-common/lib/Doctrine/Common/ClassLoader.php';
+if (!file_exists($classLoaderFile)) {
+    die('cannot find vendor, run: php bin/vendors.php');
+}
+
+require_once $classLoaderFile;
+$classLoader = new Doctrine\Common\ClassLoader('Symfony');
+$classLoader->register();
+
+$finder = new Symfony\Component\Finder\Finder;
+$finder->files()
+    ->name('*.php')
+    ->in(__DIR__ . '/../lib')
+    ->in(__DIR__ . '/../tests');
+
+foreach ($finder as $fileInfo) {
+    if (!$fileInfo->isReadable()) {
+        continue;
+    }
+    $count = 0;
+    $total = 0;
+    $needsSave = false;
+    $content = file_get_contents($fileInfo->getRealPath());
+
+    $content = str_replace("\t", '    ', $content, $count);
+    $total += $count;
+
+    $content = str_replace("\r\n", "\n", $content, $count);
+    $total += $count;
+
+    $needsSave = $total != 0;
+
+    if ($needsSave) {
+        file_put_contents($fileInfo->getRealPath(), $content);
+        echo $fileInfo->getRealPath() . PHP_EOL;
+    }
+}
+
+echo 'done';

+ 51 - 0
vendor/gedmo/doctrine-extensions/composer.json

@@ -0,0 +1,51 @@
+{
+    "name": "gedmo/doctrine-extensions",
+    "type": "library",
+    "description": "Doctrine2 behavioral extensions",
+    "keywords": [
+        "behaviors",
+        "doctrine2",
+        "extensions",
+        "gedmo",
+        "sluggable",
+        "loggable",
+        "translatable",
+        "tree",
+        "nestedset",
+        "sortable",
+        "timestampable"
+    ],
+    "homepage": "http://gediminasm.org/",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Gediminas Morkevicius",
+            "email": "gediminas.morkevicius@gmail.com"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.2",
+        "doctrine/common": ">=2.2,<2.5-dev"
+    },
+    "require-dev": {
+        "doctrine/mongodb": ">=1.0.0-BETA1",
+        "doctrine/mongodb-odm": ">=1.0.0-BETA6",
+        "doctrine/orm": ">=2.2",
+        "doctrine/dbal": ">=2.2",
+        "symfony/yaml": "2.*"
+    },
+    "suggest": {
+        "doctrine/mongodb": ">=1.0.0",
+        "doctrine/mongodb-odm": ">=1.0.0-BETA7",
+        "doctrine/orm": ">=2.2",
+        "doctrine/dbal": ">=2.2"
+    },
+    "autoload": {
+        "psr-0": { "Gedmo": "lib/" }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "2.3.x-dev"
+        }
+    }
+}

+ 569 - 0
vendor/gedmo/doctrine-extensions/doc/annotations.md

@@ -0,0 +1,569 @@
+# Annotation reference
+
+Bellow you will find all annotation descriptions used in these extensions.
+There will be introduction on usage with examples. For more detailed usage
+on extensions, refer to their specific documentation.
+
+[blog_reference]: http://gediminasm.org/article/annotation-reference-for-extensions "Doctrine2 extensions annotation reference and examples"
+
+Content:
+
+- Best [practices](#em-setup) for setting up
+- [Tree](#gedmo-tree)
+- [Translatable](#gedmo-translatable)
+- [Sluggable](#gedmo-sluggable)
+- [Timestampable](#gedmo-timestampable)
+- [Loggable](#gedmo-loggable)
+
+## Annotation mapping
+
+Starting from **doctrine2.1.x** versions you have to import all used annotations
+by an **use** statement, see example bellow:
+
+``` php
+namespace MyApp\Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo; // this will be like an alias for Gedmo extensions annotations
+use Doctrine\ORM\Mapping\Id; // includes single annotation
+use Doctrine\ORM\Mapping as ORM; // alias for doctrine ORM annotations
+
+/**
+ * @ORM\Entity
+ * @Gedmo\TranslationEntity(class="something")
+ */
+class Article
+{
+    /**
+     * @Id
+     * @Gedmo\Slug(fields={"title"}, updatable=false, separator="_")
+     * @ORM\Column(length=32, unique=true)
+     */
+    private $id;
+    
+    /**
+     * @Gedmo\Translatable
+     * @ORM\Column(length=64)
+     */
+    private $title;
+    
+    /**
+     * @Gedmo\Timestampable(on="create")
+     * @ORM\Column(type="datetime")
+     */
+    private $created;
+}
+```
+
+**Note:** this mapping applies only if you use **doctrine-common** library at version **2.1.x** or higher,
+extension library still supports old mapping styles if you manually set the mapping drivers
+
+<a name="em-setup"></a>
+
+## Best practices for setting up with annotations
+
+New annotation reader does not depend on any namespaces, for that reason you can use
+single reader instance for whole project. The example bellow shows how to setup the
+mapping and listeners:
+
+**Note:** using this repository you can test and check the [example demo configuration](https://github.com/l3pp4rd/DoctrineExtensions/blob/master/example/em.php)
+
+``` php
+<?php
+// WARNING: setup, assumes that autoloaders are set
+
+// globally used cache driver, in production use APC or memcached
+$cache = new Doctrine\Common\Cache\ArrayCache;
+// standard annotation reader
+$annotationReader = new Doctrine\Common\Annotations\AnnotationReader;
+$cachedAnnotationReader = new Doctrine\Common\Annotations\CachedReader(
+    $annotationReader, // use reader
+    $cache // and a cache driver
+);
+// create a driver chain for metadata reading
+$driverChain = new Doctrine\ORM\Mapping\Driver\DriverChain();
+// load superclass metadata mapping only, into driver chain
+// also registers Gedmo annotations.NOTE: you can personalize it
+Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM(
+    $driverChain, // our metadata driver chain, to hook into
+    $cachedAnnotationReader // our cached annotation reader
+);
+
+// now we want to register our application entities,
+// for that we need another metadata driver used for Entity namespace
+$annotationDriver = new Doctrine\ORM\Mapping\Driver\AnnotationDriver(
+    $cachedAnnotationReader, // our cached annotation reader
+    array(__DIR__.'/app/Entity') // paths to look in
+);
+// NOTE: driver for application Entity can be different, Yaml, Xml or whatever
+// register annotation driver for our application Entity namespace
+$driverChain->addDriver($annotationDriver, 'Entity');
+
+// general ORM configuration
+$config = new Doctrine\ORM\Configuration;
+$config->setProxyDir(sys_get_temp_dir());
+$config->setProxyNamespace('Proxy');
+$config->setAutoGenerateProxyClasses(false); // this can be based on production config.
+// register metadata driver
+$config->setMetadataDriverImpl($driverChain);
+// use our allready initialized cache driver
+$config->setMetadataCacheImpl($cache);
+$config->setQueryCacheImpl($cache);
+
+// create event manager and hook prefered extension listeners
+$evm = new Doctrine\Common\EventManager();
+// gedmo extension listeners, remove which are not used
+
+// sluggable
+$sluggableListener = new Gedmo\Sluggable\SluggableListener;
+// you should set the used annotation reader to listener, to avoid creating new one for mapping drivers
+$sluggableListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($sluggableListener);
+
+// tree
+$treeListener = new Gedmo\Tree\TreeListener;
+$treeListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($treeListener);
+
+// loggable, not used in example
+$loggableListener = new Gedmo\Loggable\LoggableListener;
+$loggableListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($loggableListener);
+
+// timestampable
+$timestampableListener = new Gedmo\Timestampable\TimestampableListener;
+$timestampableListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($timestampableListener);
+
+// translatable
+$translatableListener = new Gedmo\Translatable\TranslatableListener;
+// current translation locale should be set from session or hook later into the listener
+// most important, before entity manager is flushed
+$translatableListener->setTranslatableLocale('en');
+$translatableListener->setDefaultLocale('en');
+$translatableListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($translatableListener);
+
+// sortable, not used in example
+$sortableListener = new Gedmo\Sortable\SortableListener;
+$sortableListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($sortableListener);
+
+// mysql set names UTF-8 if required
+$evm->addEventSubscriber(new Doctrine\DBAL\Event\Listeners\MysqlSessionInit());
+// DBAL connection
+$connection = array(
+    'driver' => 'pdo_mysql',
+    'host' => '127.0.0.1',
+    'dbname' => 'test',
+    'user' => 'root',
+    'password' => ''
+);
+// Finally, create entity manager
+$em = Doctrine\ORM\EntityManager::create($connection, $config, $evm);
+```
+
+**Note:** that symfony2 StofDoctrineExtensionsBundle does it automatically this
+way you will maintain a single instance of annotation reader. It relates only
+to doctrine-common-2.1.x branch and newer.
+
+<a name="gedmo-tree"></a>
+
+## Tree annotations
+
+Tree can use diferent adapters. Currently **Tree** extension supports **NestedSet**
+and **Closure** strategies which has a difference for annotations used. Note, that 
+tree will automatically map indexes which are considered necessary for best performance.
+
+### @Gedmo\Mapping\Annotation\Tree (required for all tree strategies)
+
+**class** annotation
+
+Is the main identificator of tree used for domain object which should **act as Tree**.
+
+**options:**
+
+- **type** - (string) _optional_ default: **nested**
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Tree(type="nested")
+ * @Doctrine\ORM\Mapping\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
+ */
+class Category ...
+```
+
+### @Gedmo\Mapping\Annotation\TreeParent (required for all tree strategies)
+
+**property** annotation
+
+This annotation forces to specify the **parent** field, which must be a **ManyToOne**
+relation
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\TreeParent
+ * @Doctrine\ORM\Mapping\ManyToOne(targetEntity="Category")
+ * @Doctrine\ORM\Mapping\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
+ */
+private $parent;
+```
+
+### @Gedmo\Mapping\Annotation\TreeLeft (required for nested tree)
+
+**property** annotation
+
+This annotation forces to specify the **left** field, which will be used for generation
+of nestedset left values. Property must be **integer** type.
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\TreeLeft
+ * @Doctrine\ORM\Mapping\Column(type=integer)
+ */
+private $lft;
+```
+
+### @Gedmo\Mapping\Annotation\TreeRight (required for nested tree)
+
+**property** annotation
+
+This annotation forces to specify the **right** field, which will be used for generation
+of nestedset right values. Property must be **integer** type.
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\TreeRight
+ * @Doctrine\ORM\Mapping\Column(type=integer)
+ */
+private $rgt;
+```
+
+### @Gedmo\Mapping\Annotation\TreeRoot (optional for nested tree)
+
+**property** annotation
+
+This annotation will use **integer** type field to specify the root of tree. This way
+updating tree will cost less because each root will act as separate tree.
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\TreeRoot
+ * @Doctrine\ORM\Mapping\Column(type=integer, nullable=true)
+ */
+private $root;
+```
+
+### @Gedmo\Mapping\Annotation\TreeLevel (optional for nested tree)
+
+**property** annotation
+
+This annotation lets to store the **level** of each node in the tree, in other word it
+is depth. Can be used for indentation for instance. Property must be **integer** type.
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\TreeLevel
+ * @Doctrine\ORM\Mapping\Column(type=integer)
+ */
+private $lvl;
+```
+
+### @Gedmo\Mapping\Annotation\TreeClosure (required for closure tree)
+
+**class** annotation
+
+This annotation forces to specify the closure domain object, which must
+extend **AbstractClosure** in order to have personal closures.
+
+**options:**
+
+- **class** - (string) _required_
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Tree(type="closure")
+ * @Gedmo\Mapping\Annotation\TreeClosure(class="Entity\CategoryClosure")
+ * @Doctrine\ORM\Mapping\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\ClosureTreeRepository")
+ */
+class Category ...
+```
+
+<a name="gedmo-translatable"></a>
+
+## Translatable annotations
+
+Translatable additionaly can have unmapped property, which would override the
+locale used by listener.
+
+### @Gedmo\Mapping\Annotation\TranslationEntity (optional)
+
+**class** annotation
+
+This class annotation can force translatable to use **personal Entity** to store
+translations. In large tables this can be very handy.
+
+**options:**
+
+- **class** - (string) _required_
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\TranslationEntity(class="Entity\ProductTranslation")
+ * @Doctrine\ORM\Mapping\Entity
+ */
+class Product ...
+```
+
+### @Gedmo\Mapping\Annotation\Translatable (required in order to translate)
+
+**property** annotation
+
+This annotation simply marks **any type** of field to be tracked and translated into
+currently used locale. Locale can be forced through entity or set by **TranslationListener**.
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Translatable
+ * @Doctrine\ORM\Mapping\Column(type=text)
+ */
+private $content;
+```
+    
+### @Gedmo\Mapping\Annotation\Locale or @Gedmo\Mapping\Annotation\Language (optional)
+
+**unmapped property** annotation
+
+Both annotations will do exactly the same - mark property as one which can override
+the locale set by **TranslationListener**. Property must not be mapped, that means
+it cannot be stored in database.
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Locale
+ */
+private $locale;
+```
+
+<a name="gedmo-sluggable"></a>
+
+## Sluggable annotations
+
+Sluggable ensures unique slugs and correct length of the slug. It also uses utf8 to ascii
+table map to create correct ascii slugs.
+
+### @Gedmo\Mapping\Annotation\Slug (required)
+
+**property** annotation
+
+It will use this **string** property to store the generated slug.
+
+**options:**
+
+- **fields** - (array) _required_, must at least contain one field
+- **updatable** - (boolean) _optional_ default: **true**
+- **separator** - (string) _optional_ default: **-**
+- **unique** - (boolean) _optional_ default: **true**
+- **style** - (string) _optional_ default: **default** lowercase, can be **camel** also
+- **handlers** - (array) _optional_ default: empty array, refer to the documentation below, possible elements: **Gedmo\Mapping\Annotation\SlugHandler**
+
+### Slug handlers:
+
+- Gedmo\Sluggable\Handler\TreeSlugHandler - transforms a tree slug into path based, example "food/fruits/apricots/king-apricots"
+- Gedmo\Sluggable\Handler\RelativeSlugHandler - takes a raliotion slug and prefixes the slug, example "singers/michael-jackson"
+in order to synchronize updates regarding the relation changes, you will need to hood **InversedRelativeSlugHandler** to the relation mentioned.
+- Gedmo\Sluggable\Handler\InversedRelativeSlugHandler - updates prefixed slug for an inversed relation which is mapped by **RelativeSlugHandler**
+
+examples:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Slug
+ * @Doctrine\ORM\Mapping\Column(length=64, unique=true)
+ */
+private $slug;
+```
+
+with TreeSlugHandler
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Slug(handlers={
+ *      @Gedmo\Mapping\Annotation\SlugHandler(class="Gedmo\Sluggable\Handler\TreeSlugHandler", options={
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="parentRelationField", value="parent"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="separator", value="/")
+ *      })
+ * }, separator="-", updatable=true)
+ * @Doctrine\ORM\Mapping\Column(length=64, unique=true)
+ */
+private $slug;
+```
+
+with **RelativeSlugHandler**:
+
+``` php
+<?php
+/**
+ * Person domain object class
+ *
+ * @Gedmo\Mapping\Annotation\Slug(handlers={
+ *      @Gedmo\Mapping\Annotation\SlugHandler(class="Gedmo\Sluggable\Handler\RelativeSlugHandler", options={
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="relationField", value="category"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="relationSlugField", value="slug"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="separator", value="/")
+ *      })
+ * })
+ * @Doctrine\ORM\Mapping\Column(length=64, unique=true)
+ */
+private $slug;
+```
+
+if you used **RelativeSlugHandler** - relation object should use **InversedRelativeSlugHandler**:
+
+``` php
+<?php
+/**
+ * Category domain object class
+ *
+ * @Gedmo\Mapping\Annotation\Slug(handlers={
+ *      @Gedmo\Mapping\Annotation\SlugHandler(class="Gedmo\Sluggable\Handler\InversedRelativeSlugHandler", options={
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="relationClass", value="App\Entity\Person"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="mappedBy", value="category"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="inverseSlugField", value="slug")
+ *      })
+ * })
+ * @Doctrine\ORM\Mapping\Column(length=64, unique=true)
+ */
+private $slug;
+```
+
+<a name="gedmo-timestampable"></a>
+
+## Timestampable annotations
+
+Timestampable will update date fields on create, update or property change. If you set/force
+date manualy it will not update it.
+
+### @Gedmo\Mapping\Annotation\Timestampable (required)
+
+**property** annotation
+
+Marks a **date, datetime or time** field as timestampable.
+
+**options:**
+
+- **on** - (string) _optional_ default: **update**, other choise is **create** or **change**
+- **field** - (string) _conditional_ required only if it triggers on **change**, name of the **field**
+or if it is a relation **property.field**
+- **value** - (mixed) _conditional_ required only if it triggers on **change**, value of property
+which would trigger an update.
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Timestampable(on="create")
+ * @Doctrine\ORM\Mapping\Column(type="datetime")
+ */
+private $created;
+
+/**
+ * @Gedmo\Mapping\Annotation\Timestampable(on="change", field="status.title", value="Published")
+ * @Doctrine\ORM\Mapping\Column(type="date")
+ */
+private $published;
+
+/**
+ * @Doctrine\ORM\Mapping\ManyToOne(targetEntity="Status")
+ */
+private $status;
+```
+
+<a name="gedmo-loggable"></a>
+
+## Loggable annotations
+
+Loggable is used to log all actions made on annotated object class, it logs insert, update
+and remove actions for a username which currently is logged in for instance.
+Further more, it stores all **Versioned** property changes in the log which allows
+a version management implementation for this object.
+
+### @Gedmo\Mapping\Annotation\Loggable (required)
+
+**class** annotation
+
+This class annotation marks object as being loggable and logs all actions being done to
+this class records.
+
+**options:**
+
+- **logEntryClass** - (string) _optional_ personal log storage class
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Loggable(logEntryClass="Entity\ProductLogEntry")
+ * @Doctrine\ORM\Mapping\Entity
+ */
+class Product ...
+```
+
+### @Gedmo\Mapping\Annotation\Versioned (optional)
+
+**property** annotation
+
+Tracks the marked property for changes to be logged, can be set to single valued associations
+but not for collections. Using these log entries as revisions, objects can be reverted to
+a specific version.
+
+example:
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Versioned
+ * @Doctrine\ORM\Mapping\Column(type="text")
+ */
+private $content;
+
+/**
+ * @Gedmo\Mapping\Annotation\Versioned
+ * @Doctrine\ORM\Mapping\ManyToOne(targetEntity="Article", inversedBy="comments")
+ */
+private $article;
+```
+

+ 523 - 0
vendor/gedmo/doctrine-extensions/doc/blameable.md

@@ -0,0 +1,523 @@
+# Blameable behavior extension for Doctrine 2
+
+**Blameable** behavior will automate the update of username or user reference fields
+on your Entities or Documents. It works through annotations and can update
+fields on creation, update or even on specific property value change.
+
+This is very similar to Timestampable but sets a string or user object for a user association.
+
+If you map the blame onto a string field, this extension will try to assign the user name.
+If you map the blame onto a association field, this extension will try to assign the user
+object to it.
+
+Note that you need to set the user on the BlameableListener (unless you use the
+Symfony2 extension which does automatically assign the current security context
+user).
+
+
+Features:
+
+- Automatic predifined user field update on creation, update and even on record property changes
+- ORM and ODM support using same listener
+- Specific annotations for properties, and no interface required
+- Can react to specific property or relation changes to specific value
+- Can be nested with other behaviors
+- Annotation, Yaml and Xml mapping support for extensions
+
+
+**Symfony:**
+
+- **Blameable** is available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
+for **Symfony2**, together with all other extensions
+
+This article will cover the basic installation and functionality of **Blameable** behavior
+
+Content:
+
+- [Including](#including-extension) the extension
+- Entity [example](#entity-mapping)
+- Document [example](#document-mapping)
+- [Yaml](#yaml-mapping) mapping example
+- [Xml](#xml-mapping) mapping example
+- Advanced usage [examples](#advanced-examples)
+- Using [Traits](#traits)
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+<a name="entity-mapping"></a>
+
+## Blameable Entity example:
+
+### Blameable annotations:
+- **@Gedmo\Mapping\Annotation\Blameable** this annotation tells that this column is blameable
+by default it updates this column on update. If column is not a string field or an association
+it will trigger an exception.
+
+Available configuration options:
+
+- **on** - is main option and can be **create, update, change** this tells when it
+should be updated
+- **field** - only valid if **on="change"** is specified, tracks property for changes
+- **value** - only valid if **on="change"** is specified, if tracked field has this **value**
+then it updates the blame
+
+**Note:** that Blameable interface is not necessary, except in cases there
+you need to identify entity as being Blameable. The metadata is loaded only once then
+cache is activated
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class Article
+{
+    /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=128)
+     */
+    private $title;
+
+    /**
+     * @var string $createdBy
+     *
+     * @Gedmo\Blameable(on="create")
+     * @ORM\Column(type="string")
+     */
+    private $createdBy;
+
+    /**
+     * @var string $updatedBy
+     *
+     * @Gedmo\Blameable(on="update")
+     * @ORM\Column(type="string")
+     */
+    private $updatedBy;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    public function getUpdated()
+    {
+        return $this->updated;
+    }
+}
+```
+
+<a name="document-mapping"></a>
+
+## Blameable Document example:
+
+``` php
+<?php
+namespace Document;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
+
+/**
+ * @ODM\Document(collection="articles")
+ */
+class Article
+{
+    /** @ODM\Id */
+    private $id;
+
+    /**
+     * @ODM\String
+     */
+    private $title;
+
+    /**
+     * @var string $createdBy
+     *
+     * @ODM\String
+     * @Gedmo\Blameable(on="create")
+     */
+    private $createdBy;
+
+    /**
+     * @var string $updatedBy
+     *
+     * @ODM\String
+     * @Gedmo\Blameable
+     */
+    private $updatedBy;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function getCreatedBy()
+    {
+        return $this->createdBy;
+    }
+
+    public function getUpdatedBy()
+    {
+        return $this->updatedBy;
+    }
+}
+```
+
+Now on update and creation these annotated fields will be automatically updated
+
+<a name="yaml-mapping"></a>
+
+## Yaml mapping example:
+
+Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
+
+```
+---
+Entity\Article:
+  type: entity
+  table: articles
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+      length: 64
+    createdBy:
+      type: string
+      gedmo:
+        blameable:
+          on: create
+    updatedBy:
+      type: string
+      gedmo:
+        blameable:
+          on: update
+```
+
+<a name="xml-mapping"></a>
+
+## Xml mapping example
+
+``` xml
+<?xml version="1.0" encoding="UTF-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+
+    <entity name="Mapping\Fixture\Xml\Blameable" table="blameables">
+        <id name="id" type="integer" column="id">
+            <generator strategy="AUTO"/>
+        </id>
+
+        <field name="createdBy" type="string">
+            <gedmo:blameable on="create"/>
+        </field>
+        <field name="updatedBy" type="string">
+            <gedmo:blameable on="update"/>
+        </field>
+        <field name="publishedBy" type="string" nullable="true">
+            <gedmo:blameable on="change" field="status.title" value="Published"/>
+        </field>
+
+        <many-to-one field="status" target-entity="Status">
+            <join-column name="status_id" referenced-column-name="id"/>
+        </many-to-one>
+    </entity>
+
+</doctrine-mapping>
+```
+
+<a name="advanced-examples"></a>
+
+## Advanced examples:
+
+### Using dependency of property changes
+
+Add another entity which would represent Article Type:
+
+``` php
+<?php
+namespace Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class Type
+{
+    /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=128)
+     */
+    private $title;
+
+    /**
+     * @ORM\OneToMany(targetEntity="Article", mappedBy="type")
+     */
+    private $articles;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+}
+```
+
+Now update the Article Entity to reflect publishedBy on Type change:
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class Article
+{
+    /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=128)
+     */
+    private $title;
+
+    /**
+     * @var string $createdBy
+     *
+     * @Gedmo\Blameable(on="create")
+     * @ORM\Column(type="string")
+     */
+    private $createdBy;
+
+    /**
+     * @var string $updatedBy
+     *
+     * @Gedmo\Blameable(on="update")
+     * @ORM\Column(type="string")
+     */
+    private $updatedBy;
+
+    /**
+     * @ORM\ManyToOne(targetEntity="Type", inversedBy="articles")
+     */
+    private $type;
+
+    /**
+     * @var string $publishedBy
+     *
+     * @ORM\Column(type="string", nullable=true)
+     * @Gedmo\Blameable(on="change", field="type.title", value="Published")
+     */
+    private $publishedBy;
+
+    public function setType($type)
+    {
+        $this->type = $type;
+    }
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function getCreatedBy()
+    {
+        return $this->createdBy;
+    }
+
+    public function getUpdatedBy()
+    {
+        return $this->updatedBy;
+    }
+
+    public function getPublishedBy()
+    {
+        return $this->publishedBy;
+    }
+}
+```
+
+Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
+
+```
+---
+Entity\Article:
+  type: entity
+  table: articles
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+      length: 64
+    createdBy:
+      type: string
+      gedmo:
+        blameable:
+          on: create
+    updatedBy:
+      type: string
+      gedmo:
+        blameable:
+          on: update
+    publishedBy:
+      type: string
+      gedmo:
+        blameable:
+          on: change
+          field: type.title
+          value: Published
+  manyToOne:
+    type:
+      targetEntity: Entity\Type
+      inversedBy: articles
+```
+
+Now few operations to get it all done:
+
+``` php
+<?php
+$article = new Article;
+$article->setTitle('My Article');
+
+$em->persist($article);
+$em->flush();
+// article: $createdBy, $updatedBy were set
+
+$type = new Type;
+$type->setTitle('Published');
+
+$article = $em->getRepository('Entity\Article')->findByTitle('My Article');
+$article->setType($type);
+
+$em->persist($article);
+$em->persist($type);
+$em->flush();
+// article: $publishedBy, $updatedBy were set
+
+$article->getPublishedBy(); // the user that published this article
+```
+
+Easy like that, any suggestions on improvements are very welcome
+
+
+<a name="traits"></a>
+
+## Traits
+
+You can use blameable traits for quick **createdBy** **updatedBy** string definitions
+when using annotation mapping.
+
+**Note:** this feature is only available since php **5.4.0**. And you are not required
+to use the Traits provided by extensions.
+
+``` php
+<?php
+namespace Blameable\Fixture;
+
+use Gedmo\Blameable\Traits\BlameableEntity;
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class UsingTrait
+{
+    /**
+     * Hook blameable behavior
+     * updates createdBy, updatedBy fields
+     */
+    use BlameableEntity;
+
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(length=128)
+     */
+    private $title;
+}
+```
+
+**Note:** you must import **Gedmo\Mapping\Annotation as Gedmo** and **Doctrine\ORM\Mapping as ORM**
+annotations. If you use mongodb ODM import **Doctrine\ODM\MongoDB\Mapping\Annotations as ODM** and
+**BlameableDocument** instead.
+
+Traits are very simple and if you use different field names I recomment to simply create your
+own ones based per project. These ones are standing as an example.
+

+ 266 - 0
vendor/gedmo/doctrine-extensions/doc/loggable.md

@@ -0,0 +1,266 @@
+# Loggable behavioral extension for Doctrine2
+
+**Loggable** behavior tracks your record changes and is able to
+manage versions.
+    
+Features:
+
+- Automatic storage of log entries in database
+- ORM and ODM support using same listener
+- Can be nested with other behaviors
+- Objects can be reverted to previous versions
+- Annotation, Yaml and Xml mapping support for extensions
+
+[blog_reference]: http://gediminasm.org/article/loggable-behavioral-extension-for-doctrine2 "Loggable extension for Doctrine2 tracks record changes and version management"
+[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
+
+Update **2011-04-04**
+
+- Made single listener, one instance can be used for any object manager
+and any number of them
+
+
+**Note:**
+
+- You can [test live][blog_test] on this blog
+- Public [Loggable repository](http://github.com/l3pp4rd/DoctrineExtensions "Loggable extension on Github") is available on github
+- Last update date: **2012-01-02**
+
+**Portability:**
+
+- **Loggable** is now available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
+ported to **Symfony2** by **Christophe Coevoet**, together with all other extensions
+
+This article will cover the basic installation and functionality of **Loggable**
+behavior
+
+Content:
+    
+- [Including](#including-extension) the extension
+- Entity [example](#entity-mapping)
+- Document [example](#document-mapping)
+- [Yaml](#yaml-mapping) mapping example
+- [Xml](#xml-mapping) mapping example
+- Basic usage [examples](#basic-examples)
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+### Loggable annotations:
+
+- **@Gedmo\Mapping\Annotation\Loggable(logEntryClass="my\class")** this class annotation 
+will use store logs to optionaly specified **logEntryClass**
+- **@Gedmo\Mapping\Annotation\Versioned** tracks annotated property for changes
+
+<a name="entity-mapping"></a>
+
+## Loggable Entity example:
+
+**Note:** that Loggable interface is not necessary, except in cases there
+you need to identify entity as being Loggable. The metadata is loaded only once when
+cache is active
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @Entity
+ * @Gedmo\Loggable
+ */
+class Article
+{
+    /**
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue(strategy="IDENTITY")
+     */
+    private $id;
+
+    /**
+     * @Gedmo\Versioned
+     * @ORM\Column(name="title", type="string", length=8)
+     */
+    private $title;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+}
+```
+
+<a name="document-mapping"></a>
+
+## Loggable Document example:
+
+``` php
+<?php
+namespace Document;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
+
+/**
+ * @ODM\Document(collection="articles")
+ * @Gedmo\Loggable
+ */
+class Article
+{
+    /** @ODM\Id */
+    private $id;
+
+    /**
+     * @ODM\String
+     * @Gedmo\Versioned
+     */
+    private $title;
+
+    public function __toString()
+    {
+        return $this->title;
+    }
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+}
+```
+
+<a name="yaml-mapping"></a>
+
+## Yaml mapping example
+
+Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
+
+```
+---
+Entity\Article:
+  type: entity
+  table: articles
+  gedmo:
+    loggable:
+# using specific personal LogEntryClass class:
+      logEntryClass: My\LogEntry
+# without specifying the LogEntryClass class:
+#   loggable: true
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+      length: 64
+      gedmo:
+        - versioned
+    content:
+      type: text
+```
+
+<a name="xml-mapping"></a>
+
+## Xml mapping example
+
+``` xml
+<?xml version="1.0" encoding="UTF-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+
+    <entity name="Mapping\Fixture\Xml\Loggable" table="loggables">
+
+        <id name="id" type="integer" column="id">
+            <generator strategy="AUTO"/>
+        </id>
+
+        <field name="title" type="string" length="128">
+            <gedmo:versioned/>
+        </field>
+        <many-to-one field="status" target-entity="Status">
+            <join-column name="status_id" referenced-column-name="id"/>
+            <gedmo:versioned/>
+        </many-to-one>
+
+        <gedmo:loggable log-entry-class="Gedmo\Loggable\Entity\LogEntry"/>
+
+    </entity>
+</doctrine-mapping>
+```
+
+<a name="basic-examples"></a>
+
+## Basic usage examples:
+
+``` php
+<?php
+$article = new Entity\Article;
+$article->setTitle('my title');
+$em->persist($article);
+$em->flush();
+```
+
+This inserted an article and inserted the logEntry for it, which contains
+all new changeset. In case if there is **OneToOne or ManyToOne** relation,
+it will store only identifier of that object to avoid storing proxies
+
+Now lets update our article:
+
+``` php
+<?php
+// first load the article
+$article = $em->find('Entity\Article', 1 /*article id*/);
+$article->setTitle('my new title');
+$em->persist($article);
+$em->flush();
+```
+
+This updated an article and inserted the logEntry for update action with new changeset
+Now lets revert it to previous version:
+
+``` php
+<?php
+// first check our log entries
+$repo = $em->getRepository('Gedmo\Loggable\Entity\LogEntry'); // we use default log entry class
+$article = $em->find('Entity\Article', 1 /*article id*/);
+$logs = $repo->getLogEntries($article);
+/* $logs contains 2 logEntries */
+// lets revert to first version
+$repo->revert($article, 1/*version*/);
+// notice article is not persisted yet, you need to persist and flush it
+echo $article->getTitle(); // prints "my title"
+$em->persist($article);
+$em->flush();
+// if article had changed relation, it would be reverted also.
+```
+
+Easy like that, any suggestions on improvements are very welcome

+ 494 - 0
vendor/gedmo/doctrine-extensions/doc/mapping.md

@@ -0,0 +1,494 @@
+# Mapping extension for Doctrine2
+
+**Mapping** extension makes it easy to map additional metadata for event listeners.
+It supports **Yaml**, **Xml** and **Annotation** drivers which will be chosen depending on
+currently used mapping driver for your domain objects. **Mapping** extension also
+provides abstraction layer of **EventArgs** to make it possible to use single listener
+for different object managers like **ODM** and **ORM**.
+
+Features:
+
+- Mapping drivers for annotation and yaml
+- Conventional extension points for metadata extraction and object manager abstraction
+
+[blog_reference]: http://gediminasm.org/article/mapping-extension-for-doctrine2 "Mapping extension for Doctrine2 makes it easy to create extensions based on annotation, xml, yaml mapping drivers"
+[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
+
+- Public [Mapping repository](http://github.com/l3pp4rd/DoctrineExtensions "Mapping extension on Github") is available on github
+- Last update date: **2012-01-02**
+
+This article will cover the basic installation and usage of **Mapping** extension
+
+Content:
+    
+- [Including](#including-extension) the extension
+- [Creating](#create-extension) an extension
+- Defining [annotations](#annotations)
+- Creating [listener](#create-listener)
+- Attaching our [listener](#attach-listener) to the event manager
+- [Entity](#entity-mapping) with some fields to encode
+- Addapting listener to support [different](#different-managers) object managers
+- [Customizing](#event-adapter-customize) event adapter for specific functions
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+<a name="create-extension"></a>
+
+## Tutorial on creation of mapped extension
+
+First, lets asume we will use **Extension** namespace for our additional
+extension library. You should create an **Extension** directory in your library
+or vendor directory. After some changes your project might look like:
+
+```
+project
+    ...
+    bootstrap.php
+    vendor
+        Extension
+        ...
+...
+```
+
+Now you can use any namespace autoloader class and register this namespace. We
+will use Doctrine\Common\ClassLoader for instance:
+
+``` php
+<?php
+// path is related to boostrap.php location for example
+$classLoader = new \Doctrine\Common\ClassLoader('Extension', "vendor");
+$classLoader->register();
+```
+
+Now lets create some files which are necessary for our extension:
+
+```
+project
+    ...
+    bootstrap.php
+    vendor
+        Extension
+            Encoder
+                Mapping
+                    Driver
+                        Annotation.php
+                    Annotations.php
+                EncoderListener.php
+...
+```
+
+**Note:** that extension will look for mapping in **ExtensionNamespace/Mapping**
+directory. And **Driver** directory should be named as Driver. These are the conventions
+of **Mapping** extension.
+
+That is all we will need for now. As you may noticed we will create an encoding
+listener which could encode your fields by specified annotations. In real life it
+may not be useful since object will not know how to match the value.
+
+<a name="annotations"></a>
+
+## Now lets define available annotations and setup drivers
+
+Edit **Annotations.php** file:
+
+``` php
+<?php
+// file: vendor/Extension/Encoder/Mapping/Annotations.php
+
+namespace Extension\Encoder\Mapping;
+
+use Doctrine\Common\Annotations\Annotation;
+
+final class Encode extends Annotation
+{
+    public $type = 'md5';
+    public $secret;
+}
+```
+
+Edit **Annotation.php** driver file:
+
+``` php
+<?php
+// file: vendor/Extension/Encoder/Mapping/Driver/Annotation.php
+
+namespace Extension\Encoder\Mapping\Driver;
+
+use Gedmo\Mapping\Driver;
+use Doctrine\Common\Annotations\AnnotationReader;
+
+class Annotation implements Driver
+{
+    public function readExtendedMetadata($meta, array &$config) {
+        // load our available annotations
+        require_once __DIR__ . '/../Annotations.php';
+        $reader = new AnnotationReader();
+
+        $class = $meta->getReflectionClass();
+        // check only property annotations
+        foreach ($class->getProperties() as $property) {
+            // skip inherited properties
+            if ($meta->isMappedSuperclass && !$property->isPrivate() ||
+                $meta->isInheritedField($property->name) ||
+                isset($meta->associationMappings[$property->name]['inherited'])
+            ) {
+                continue;
+            }
+            // now lets check if property has our annotation
+            if ($encode = $reader->getPropertyAnnotation($property, 'Extension\Encoder\Mapping\Encode')) {
+                $field = $property->getName();
+                // check if field is mapped
+                if (!$meta->hasField($field)) {
+                    throw new \Exception("Field is not mapped as object property");
+                }
+                // allow encoding only strings
+                if (!in_array($encode->type, array('sha1', 'md5'))) {
+                    throw new \Exception("Invalid encoding type supplied");
+                }
+                // validate encoding type
+                $mapping = $meta->getFieldMapping($field);
+                if ($mapping['type'] != 'string') {
+                    throw new \Exception("Only strings can be encoded");
+                }
+                // store the metadata
+                $config['encode'][$field] = array(
+                    'type' => $encode->type,
+                    'secret' => $encode->secret
+                );
+            }
+        }
+    }
+}
+```
+
+<a name="create-listener"></a>
+
+## Finally, lets create the listener
+
+**Note:** this version of listener will support only ORM Entities
+
+``` php
+<?php
+// file: vendor/Extension/Encoder/EncoderListener.php
+
+namespace Extension\Encoder;
+
+use Doctrine\Common\EventArgs;
+use Gedmo\Mapping\MappedEventSubscriber;
+
+class EncoderListener extends MappedEventSubscriber
+{
+    public function getSubscribedEvents()
+    {
+        return array(
+            'onFlush',
+            'loadClassMetadata'
+        );
+    }
+
+    public function loadClassMetadata(EventArgs $args)
+    {
+        // this will check for our metadata
+        $this->loadMetadataForObjectClass(
+            $args->getEntityManager(),
+            $args->getClassMetadata()
+        );
+    }
+
+    public function onFlush(EventArgs $args)
+    {
+        $em = $args->getEntityManager();
+        $uow = $em->getUnitOfWork();
+
+        // check all pending updates
+        foreach ($uow->getScheduledEntityUpdates() as $object) {
+            $meta = $em->getClassMetadata(get_class($object));
+            // if it has our metadata lets encode the properties
+            if ($config = $this->getConfiguration($em, $meta->name)) {
+                $this->encode($em, $object, $config);
+            }
+        }
+        // check all pending insertions
+        foreach ($uow->getScheduledEntityInsertions() as $object) {
+            $meta = $em->getClassMetadata(get_class($object));
+            // if it has our metadata lets encode the properties
+            if ($config = $this->getConfiguration($em, $meta->name)) {
+                $this->encode($em, $object, $config);
+            }
+            // recalculate changeset
+            $em->getUnitOfWork()->recomputeSingleEntityChangeSet($meta, $object);
+        }
+    }
+
+    protected function getNamespace()
+    {
+        // mapper must know the namespace of extension
+        return __NAMESPACE__;
+    }
+
+    private function encode($em, $object, $config)
+    {
+        $meta = $em->getClassMetadata(get_class($object));
+        foreach ($config['encode'] as $field => $options) {
+            $value = $meta->getReflectionProperty($field)->getValue($object);
+            $method = $options['type'];
+            $encoded = $method($options['secret'].$value);
+            $meta->getReflectionProperty($field)->setValue($object, $encoded);
+        }
+        // recalculate changeset
+        $em->getUnitOfWork()->recomputeSingleEntityChangeSet($meta, $object);
+    }
+}
+```
+
+Our **Encoder** extension is ready, now if we want to test it, we need
+to attach our **EncoderListener** to the EventManager and create an entity
+with some fields to encode.
+
+<a name="attach-listener"></a>
+
+### Attaching the EncoderListener
+
+``` php
+<?php
+$evm = new \Doctrine\Common\EventManager();
+$encoderListener = new \Extension\Encoder\EncoderListener;
+$evm->addEventSubscriber($encoderListener);
+// now this event manager should be passed to entity manager constructor
+```
+
+<a name="entity-mapping"></a>
+
+### Create an entity with some fields to encode
+
+``` php
+<?php
+namespace YourNamespace\Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+use Extension\Encoder\Mapping as EXT;
+
+/**
+ * @ORM\Table(name="test_users")
+ * @ORM\Entity
+ */
+class User
+{
+    /**
+     * @ORM\Column(type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     */
+    private $id;
+
+    /**
+     * @EXT\Encode(type="sha1", secret="xxx")
+     * @ORM\Column(length=64)
+     */
+    private $name;
+
+    /**
+     * @EXT\Encode(type="md5")
+     * @ORM\Column(length=32)
+     */
+    private $password;
+
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function setPassword($password)
+    {
+        $this->password = $password;
+    }
+
+    public function getPassword()
+    {
+        return $this->password;
+    }
+}
+```
+
+If you will try to create a new **User** you will get encoded fields in database.
+
+<a name="different-managers"></a>
+
+## Adapting listener to support other object managers
+
+Now the event adapter comes into play, lets slightly modify our listener:
+
+``` php
+<?php
+// file: vendor/Extension/Encoder/EncoderListener.php
+
+use Doctrine\Common\EventArgs;
+use Gedmo\Mapping\MappedEventSubscriber;
+use Gedmo\Mapping\Event\AdapterInterface as EventAdapterInterface;
+
+class EncoderListener extends MappedEventSubscriber
+{
+    public function getSubscribedEvents()
+    {
+        return array(
+            'onFlush',
+            'loadClassMetadata'
+        );
+    }
+
+    public function loadClassMetadata(EventArgs $args)
+    {
+        $ea = $this->getEventAdapter($args);
+        // this will check for our metadata
+        $this->loadMetadataForObjectClass(
+            $ea->getObjectManager(),
+            $args->getClassMetadata()
+        );
+    }
+
+    public function onFlush(EventArgs $args)
+    {
+        $ea = $this->getEventAdapter($args);
+        $om = $ea->getObjectManager();
+        $uow = $om->getUnitOfWork();
+
+        // check all pending updates
+        foreach ($ea->getScheduledObjectUpdates($uow) as $object) {
+            $meta = $om->getClassMetadata(get_class($object));
+            // if it has our metadata lets encode the properties
+            if ($config = $this->getConfiguration($om, $meta->name)) {
+                $this->encode($ea, $object, $config);
+            }
+        }
+        // check all pending insertions
+        foreach ($ea->getScheduledObjectInsertions($uow) as $object) {
+            $meta = $om->getClassMetadata(get_class($object));
+            // if it has our metadata lets encode the properties
+            if ($config = $this->getConfiguration($om, $meta->name)) {
+                $this->encode($ea, $object, $config);
+            }
+            // recalculate changeset
+            $ea->recomputeSingleObjectChangeSet($uow, $meta, $object);
+        }
+    }
+
+    protected function getNamespace()
+    {
+        // mapper must know the namespace of extension
+        return __NAMESPACE__;
+    }
+
+    private function encode(EventAdapterInterface $ea, $object, $config)
+    {
+        $om = $ea->getObjectManager();
+        $meta = $om->getClassMetadata(get_class($object));
+        $uow = $om->getUnitOfWork();
+        foreach ($config['encode'] as $field => $options) {
+            $value = $meta->getReflectionProperty($field)->getValue($object);
+            $method = $options['type'];
+            $encoded = $method($options['secret'].$value);
+            $meta->getReflectionProperty($field)->setValue($object, $encoded);
+        }
+        // recalculate changeset
+        $ea->recomputeSingleObjectChangeSet($uow, $meta, $object);
+    }
+}
+```
+
+**Note:** event adapter uses **EventArgs** to recognize with which manager
+we are dealing with. It also uses event arguments to retrieve manager and transforms
+the method call in its way. You can extend the event adapter in order to add some
+specific methods for each manager.
+
+Thats it, now it will work on ORM and ODM object managers.
+
+<a name="event-adapter-customize"></a>
+
+## Customizing event adapter for specific functions
+
+In most cases event listener will need specific functionality which will differ
+for every object manager. For instance, a query to load users will differ. The
+example bellow will illustrate how to handle such situations. You will need to
+extend default ORM and ODM event adapters to implement specific functions which
+will be available through the event adapter. First we will need to follow the
+mapping convention to use those extension points.
+
+### Extending default event adapters
+
+Update your directory structure:
+
+```
+project
+    ...
+    bootstrap.php
+    vendor
+        Extension
+            Encoder
+                Mapping
+                    Driver
+                        Annotation.php
+                    Event
+                        Adapter
+                            ORM.php
+                            ODM.php
+                    Annotations.php
+                EncoderListener.php
+...
+```
+
+Now **Mapping** extension will automatically create event adapter instances
+from the extended ones.
+
+Create extended ORM event adapter:
+
+``` php
+<?php
+// file: vendor/Extension/Encoder/Mapping/Event/Adapter/ORM.php
+
+namespace Extension\Encoder\Mapping\Event\Adapter;
+
+use Gedmo\Mapping\Event\Adapter\ORM as BaseAdapterORM;
+
+class ORM extends BaseAdapterORM
+{
+    public function someSpecificMethod()
+    {
+
+    }
+}
+```
+
+Create extended ODM event adapter:
+
+``` php
+<?php
+// file: vendor/Extension/Encoder/Mapping/Event/Adapter/ODM.php
+
+namespace Extension\Encoder\Mapping\Event\Adapter;
+
+use Gedmo\Mapping\Event\Adapter\ODM as BaseAdapterODM;
+
+class ODM extends BaseAdapterODM
+{
+    public function someSpecificMethod()
+    {
+ 
+    }
+}
+```
+
+It would be useful to make a common interface for those extended adapters.
+Now every possible requirement is fullfilled and this may be useful.
+
+Any suggestions on improvements are very welcome

+ 755 - 0
vendor/gedmo/doctrine-extensions/doc/sluggable.md

@@ -0,0 +1,755 @@
+# Sluggable behavior extension for Doctrine 2
+
+**Sluggable** behavior will build the slug of predefined fields on a given field
+which should store the slug
+
+Features:
+
+- Automatic predifined field transformation into slug
+- ORM and ODM support using same listener
+- Slugs can be unique and styled
+- Can be nested with other behaviors
+- Annotation, Yaml and Xml mapping support for extensions
+- Multiple slugs, diferent slugs can link to same fields
+
+[blog_reference]: http://gediminasm.org/article/sluggable-behavior-extension-for-doctrine-2 "Sluggable extension for Doctrine 2 makes automatic record field transformations into url friendly names"
+[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
+
+Update **2012-11-30**
+
+- Recreated slug handlers, as they are used by many people
+
+Update **2012-02-26**
+
+- Remove slug handlers were removed because of complications it brought together
+
+
+Update **2011-09-11**
+
+- Refactored sluggable for doctrine2.2 by specifieng slug fields directly in slug annotation
+- Slug handler functionality, possibility to create custom ones or use built-in
+tree path handler or linked slug through single valued association
+- Updated documentation mapping examples for 2.1.x version or higher
+
+Update **2011-04-04**
+
+- Made single listener, one instance can be used for any object manager and any number of them
+
+Update **2010-12-23**
+
+- Full support for unique index on slug field,
+no more exceptions during concurrent flushes.
+
+**Note:**
+
+- There is a reported [issue](https://github.com/l3pp4rd/DoctrineExtensions/issues/254) that sluggable transliterator
+does not work on OSX 10.6 its ok starting again from 10.7 version. To overcome the problem
+you can use your [custom transliterator](#transliterator)
+- You can [test live][blog_test] on this blog
+- Public [Sluggable repository](http://github.com/l3pp4rd/DoctrineExtensions "Sluggable extension on Github") is available on github
+- Last update date: **2012-02-26**
+
+**Portability:**
+
+- **Sluggable** is now available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
+ported to **Symfony2** by **Christophe Coevoet**, together with all other extensions
+
+This article will cover the basic installation and functionality of **Sluggable**
+behavior
+
+Content:
+    
+- [Including](#including-extension) the extension
+- Entity [example](#entity-mapping)
+- Document [example](#document-mapping)
+- [Yaml](#yaml-mapping) mapping example
+- [Xml](#xml-mapping) mapping example
+- Basic usage [examples](#basic-examples)
+- Custom [transliterator](#transliterator)
+- Advanced usage [examples](#advanced-examples)
+- Using [slug handlers](#slug-handlers)
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+<a name="entity-mapping"></a>
+
+## Sluggable Entity example:
+
+### Sluggable annotations:
+
+- **@Gedmo\Mapping\Annotation\Slug** it will use this column to store **slug** generated
+**fields** option must be specified, an array of field names to slug
+
+**Note:** that Sluggable interface is not necessary, except in cases there
+you need to identify entity as being Sluggable. The metadata is loaded only once then
+cache is activated
+
+**Note:** 2.0.x version of extensions used @Gedmo\Mapping\Annotation\Sluggable to identify
+the field for slug
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Table(name="articles")
+ * @ORM\Entity
+ */
+class Article
+{
+    /** 
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(length=64)
+     */
+    private $title;
+
+    /**
+     * @ORM\Column(length=16)
+     */
+    private $code;
+
+    /**
+     * @Gedmo\Slug(fields={"title", "code"})
+     * @ORM\Column(length=128, unique=true)
+     */
+    private $slug;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setCode($code)
+    {
+        $this->code = $code;
+    }
+
+    public function getCode()
+    {
+        return $this->code;
+    }
+
+    public function getSlug()
+    {
+        return $this->slug;
+    }
+}
+```
+
+<a name="document-mapping"></a>
+
+## Sluggable Document example:
+
+``` php
+<?php
+namespace Document;
+
+use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
+use Gedmo\Mapping\Annotation as Gedmo;
+
+/**
+ * @ODM\Document(collection="articles")
+ */
+class Article
+{
+    /** 
+     * @ODM\Id
+     */
+    private $id;
+
+    /**
+     * @ODM\String
+     */
+    private $title;
+
+    /**
+     * @ODM\String
+     */
+    private $code;
+
+    /**
+     * @Gedmo\Slug(fields={"title", "code"})
+     * @ODM\String
+     */
+    private $slug;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setCode($code)
+    {
+        $this->code = $code;
+    }
+
+    public function getCode()
+    {
+        return $this->code;
+    }
+
+    public function getSlug()
+    {
+        return $this->slug;
+    }
+}
+```
+
+<a name="yaml-mapping"></a>
+
+## Yaml mapping example
+
+Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
+
+```
+---
+Entity\Article:
+  type: entity
+  table: articles
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+      length: 64
+    code:
+      type: string
+      length: 16
+    slug:
+      type: string
+      length: 128
+      gedmo:
+        slug:
+          separator: _
+          style: camel
+          fields:
+            - title
+            - code
+  indexes:
+    search_idx:
+      columns: slug
+```
+
+<a name="xml-mapping"></a>
+
+## Xml mapping example
+
+**Note:** xml driver is not yet adapted for single slug mapping
+
+``` xml
+<?xml version="1.0" encoding="UTF-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+    <entity name="Entity\Article" table="sluggables">
+        <id name="id" type="integer" column="id">
+            <generator strategy="AUTO"/>
+        </id>
+
+        <field name="title" type="string" length="128"/>
+        <field name="code" type="string" length="16"/>
+        <field name="ean" type="string" length="13"/>
+        <field name="slug" type="string" length="156" unique="true">
+            <gedmo:slug unique="true" style="camel" updatable="false" separator="_" fields="title,code,ean" />
+        </field>
+    </entity>
+</doctrine-mapping>
+```
+
+<a name="basic-examples"></a>
+
+## Basic usage examples:
+
+### To save **Article** and generate slug simply use:
+
+``` php
+<?php
+$article = new Article();
+$article->setTitle('the title');
+$article->setCode('my code');
+$this->em->persist($article);
+$this->em->flush();
+
+echo $article->getSlug();
+// prints: the-title-my-code
+```
+
+### Some other configuration options for **slug** annotation:
+
+- **fields** (required, default=[]) - list of fields for slug
+- **updatable** (optional, default=true) - **true** to update the slug on sluggable field changes, **false** - otherwise
+- **unique** (optional, default=true) - **true** if slug should be unique and if identical it will be prefixed, **false** - otherwise
+- **separator** (optional, default="-") - separator which will separate words in slug
+- **style** (optional, default="default") - **"default"** all letters will be lowercase, **"camel"** - first word letter will be uppercase
+- **handlers** (optional, default=[]) - list of slug handlers, like tree path slug, or customized, for example see bellow
+
+**Note**: handlers are totally optional
+
+**TreeSlugHandler**
+
+``` php
+<?php
+/**
+ * @Gedmo\Mapping\Annotation\Slug(handlers={
+ *      @Gedmo\Mapping\Annotation\SlugHandler(class="Gedmo\Sluggable\Handler\TreeSlugHandler", options={
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="parentRelationField", value="parent"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="separator", value="/")
+ *      })
+ * }, fields={"title", "code"})
+ * @Doctrine\ORM\Mapping\Column(length=64, unique=true)
+ */
+private $slug;
+```
+
+**RelativeSlugHandler**:
+
+``` php
+<?php
+/**
+ * Person domain object class
+ *
+ * @Gedmo\Mapping\Annotation\Slug(handlers={
+ *      @Gedmo\Mapping\Annotation\SlugHandler(class="Gedmo\Sluggable\Handler\RelativeSlugHandler", options={
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="relationField", value="category"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="relationSlugField", value="slug"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="separator", value="/")
+ *      })
+ * }, fields={"title", "code"})
+ * @Doctrine\ORM\Mapping\Column(length=64, unique=true)
+ */
+private $slug;
+```
+
+**Note:** if you used **RelativeSlugHandler** - relation object should use in order to sync changes:
+
+**InversedRelativeSlugHandler**
+
+``` php
+<?php
+/**
+ * Category domain object class
+ *
+ * @Gedmo\Mapping\Annotation\Slug(handlers={
+ *      @Gedmo\Mapping\Annotation\SlugHandler(class="Gedmo\Sluggable\Handler\InversedRelativeSlugHandler", options={
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="relationClass", value="App\Entity\Person"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="mappedBy", value="category"),
+ *          @Gedmo\Mapping\Annotation\SlugHandlerOption(name="inverseSlugField", value="slug")
+ *      })
+ * }, fields={"title"})
+ * @Doctrine\ORM\Mapping\Column(length=64, unique=true)
+ */
+private $slug;
+```
+
+### Example
+
+``` php
+<?php
+class Article
+{
+    // ...
+    /**
+     * @Gedmo\Slug(fields={"title"}, style="camel", separator="_", updatable=false, unique=false)
+     * @Doctrine\ORM\Mapping\Column(length=128, unique=true)
+     */
+    private $slug;
+    // ...
+
+    // ...
+    /**
+     * @Doctrine\ORM\Mapping\Column(length=128)
+     */
+    private $title;
+    // ...
+}
+```
+
+And now test the result:
+
+``` php
+<?php
+$article = new Article();
+$article->setTitle('the title');
+$article->setCode('my code');
+$this->em->persist($article);
+$this->em->flush();
+
+echo $article->getSlug();
+// prints: The_Title_My_Code
+```
+
+<a name="transliterator"></a>
+
+## Custom transliterator
+
+To set your own custom transliterator, which would be used to generate the slug, use:
+
+``` php
+<?php
+
+$callable = array('My\Class', 'transliterationMethod');
+$sluggableListener->setTransliterator($callable);
+
+// or use a closure
+
+$callable = function($text, $separatorUsed, $objectBeingSlugged) {
+    // ...
+    return $transliteratedText;
+};
+$sluggableListener->setTransliterator($callable);
+```
+
+<a name="advanced-examples"></a>
+
+## Advanced examples:
+
+### Regenerating slug
+
+In case if you want the slug to regenerate itself based on sluggable fields.
+Set the slug to **null** or empty string.
+
+``` php
+<?php
+$entity = $em->find('Entity\Something', $id);
+$entity->setSlug('');
+
+$em->persist($entity);
+$em->flush();
+```
+
+### Setting the slug manually
+
+Sometimes you might need to set it manually, etc if generated one does not look satisfying enough.
+Sluggable will ensure uniqueness of the slug.
+
+``` php
+<?php
+$entity = new SomeEntity;
+$entity->setSluggableField('won't be taken into account');
+$entity->setSlug('the required slug, set manually');
+
+$em->persist($entity);
+$em->flush();
+
+echo $entity->getSlug(); // outputs: "the-required-slug-set-manually"
+```
+
+### Using TranslationListener to translate our slug
+
+If you want to attach **TranslationListener** also add it to EventManager after
+the **SluggableListener**. It is important because slug must be generated first
+before the creation of it`s translation.
+
+``` php
+<?php
+$evm = new \Doctrine\Common\EventManager();
+$sluggableListener = new \Gedmo\Sluggable\SluggableListener();
+$evm->addEventSubscriber($sluggableListener);
+$translatableListener = new \Gedmo\Translatable\TranslationListener();
+$translatableListener->setTranslatableLocale('en_us');
+$evm->addEventSubscriber($translatableListener);
+// now this event manager should be passed to entity manager constructor
+```
+
+And the Entity should look like:
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Table(name="articles")
+ * @ORM\Entity
+ */
+class Article
+{
+    /** 
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @Gedmo\Translatable
+     * @ORM\Column(length=64)
+     */
+    private $title;
+
+    /**
+     * @Gedmo\Translatable
+     * @ORM\Column(length=16)
+     */
+    private $code;
+    
+    /**
+     * @Gedmo\Translatable
+     * @Gedmo\Slug(fields={"title", "code"})
+     * @ORM\Column(length=128, unique=true)
+     */
+    private $slug;
+    
+    /**
+     * @ORM\Column(type="string", length=64)
+     */
+    private $uniqueTitle;
+    
+    /**
+     * @Gedmo\Slug(fields={"uniqueTitle"})
+     * @ORM\Column(type="string", length=128, unique=true)
+     */
+    private $uniqueSlug;
+
+    
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setCode($code)
+    {
+        $this->code = $code;
+    }
+
+    public function getCode()
+    {
+        return $this->code;
+    }
+
+    public function getSlug()
+    {
+        return $this->slug;
+    }
+    
+    public function getUniqueSlug()
+    {
+        return $this->uniqueSlug;
+    }
+}
+```
+
+Now the generated slug will be translated by Translatable behavior
+
+<a name="slug-handlers"></a>
+
+## Using slug handlers:
+
+There are built-in slug handlers like described in configuration options of slug, but there
+can be also customized slug handlers depending on use cases. Usually the most logic use case
+is for related slug. For instance if user has a **ManyToOne relation to a **Company** we
+would like to have a url like **http://example.com/knplabs/gedi where **KnpLabs**
+is a company and user name is **Gedi**. In this case relation has a path separator **/**
+
+User entity example:
+
+``` php
+<?php
+namespace Sluggable\Fixture\Handler;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class User
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(length=64)
+     */
+    private $username;
+
+    /**
+     * @Gedmo\Slug(handlers={
+     *      @Gedmo\SlugHandler(class="Gedmo\Sluggable\Handler\RelativeSlugHandler", options={
+     *          @Gedmo\SlugHandlerOption(name="relationField", value="company"),
+     *          @Gedmo\SlugHandlerOption(name="relationSlugField", value="alias"),
+     *          @Gedmo\SlugHandlerOption(name="separator", value="/")
+     *      })
+     * }, separator="-", updatable=true, fields={"username"})
+     * @ORM\Column(length=64, unique=true)
+     */
+    private $slug;
+
+    /**
+     * @ORM\ManyToOne(targetEntity="Company")
+     */
+    private $company;
+
+    public function setCompany(Company $company = null)
+    {
+        $this->company = $company;
+    }
+
+    public function getCompany()
+    {
+        return $this->company;
+    }
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function getSlug()
+    {
+        return $this->slug;
+    }
+}
+```
+
+Company entity example:
+
+``` php
+<?php
+namespace Sluggable\Fixture\Handler;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class Company
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(length=64)
+     */
+    private $title;
+
+    /**
+     * @Gedmo\Slug(handlers={
+     *      @Gedmo\SlugHandler(class="Gedmo\Sluggable\Handler\InversedRelativeSlugHandler", options={
+     *          @Gedmo\SlugHandlerOption(name="relationClass", value="Sluggable\Fixture\Handler\User"),
+     *          @Gedmo\SlugHandlerOption(name="mappedBy", value="company"),
+     *          @Gedmo\SlugHandlerOption(name="inverseSlugField", value="slug")
+     *      })
+     * }, fields={"title"})
+     * @ORM\Column(length=64, unique=true)
+     */
+    private $alias;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function getAlias()
+    {
+        return $this->alias;
+    }
+}
+```
+
+And the example usage:
+
+``` php
+<?php
+$company = new Company;
+$company->setTitle('KnpLabs');
+$em->persist($company);
+
+$gedi = new User;
+$gedi->setUsername('Gedi');
+$gedi->setCompany($company);
+$em->persist($gedi);
+
+$em->flush();
+
+echo $gedi->getSlug(); // outputs "knplabs/gedi"
+
+$company->setTitle('KnpLabs Nantes');
+$em->persist($company);
+$em->flush();
+
+echo $gedi->getSlug(); // outputs "knplabs-nantes/gedi"
+```
+
+**Note:** tree slug handler, takes a parent relation to build slug recursively.
+
+Any suggestions on improvements are very welcome

+ 215 - 0
vendor/gedmo/doctrine-extensions/doc/softdeleteable.md

@@ -0,0 +1,215 @@
+# SoftDeleteable behavior extension for Doctrine 2
+
+**SoftDeleteable** behavior allows to "soft delete" objects, filtering them
+at SELECT time by marking them as with a timestamp, but not explicitly removing them from the database.
+
+Features:
+
+- Works with DQL DELETE queries (using a Query Hint).
+- All SELECT queries will be filtered, not matter from where they are executed (Repositories, DQL SELECT queries, etc).
+- For now, it works only with the ORM
+- Can be nested with other behaviors
+- Annotation, Yaml and Xml mapping support for extensions
+
+[blog_reference]: http://gediminasm.org/article/tree-nestedset-behavior-extension-for-doctrine-2 "Softdeleteable - does not explicitly remove record entries from the database, instead it marks those as deleted and skips in selection queries"
+[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
+
+Content:
+
+- [Including](#including-extension) the extension
+- Entity [example](#entity-mapping)
+- [Yaml](#yaml-mapping) mapping example
+- [Xml](#xml-mapping) mapping example
+- Usage [examples](#usage)
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+With SoftDeleteable there's one more step you need to do. You need to add the filter to your configuration:
+
+``` php
+
+$config = new Doctrine\ORM\Configuration;
+
+// Your configs..
+
+$config->addFilter('soft-deleteable', 'Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter');
+```
+
+And then you can access the filter from your EntityManager to enable or disable it with the following code:
+
+``` php
+// This will enable the SoftDeleteable filter, so entities which were "soft-deleted" will not appear
+// in results
+$em->getFilters()->enable('soft-deleteable');
+
+// This will disable the SoftDeleteable filter, so entities which were "soft-deleted" will appear in results
+$em->getFilters()->disable('soft-deleteable');
+```
+
+<a name="entity-mapping"></a>
+
+## SoftDeleteable Entity example:
+
+### SoftDeleteable annotations:
+- **@Gedmo\Mapping\Annotation\SoftDeleteable** this class annotation tells if a class is SoftDeleteable. It has a
+mandatory parameter "fieldName", which is the name of the field to be used to hold the known "deletedAt" field. It
+must be of any of the date types.
+
+Available configuration options:
+- **fieldName** - The name of the field that will be used to determine if the object is removed or not (NULL means
+it's not removed. A date value means it was removed). NOTE: The field MUST be nullable.
+
+**Note:** that SoftDeleteable interface is not necessary, except in cases there
+you need to identify entity as being SoftDeleteable. The metadata is loaded only once then
+cache is activated
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ * @Gedmo\SoftDeleteable(fieldName="deletedAt")
+ */
+class Article
+{
+    /**
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue(strategy="IDENTITY")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(name="title", type="string")
+     */
+    private $title;
+
+    /**
+     * @ORM\Column(name="deletedAt", type="datetime", nullable=true)
+     */
+    private $deletedAt;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function getDeletedAt()
+    {
+        return $this->deletedAt;
+    }
+
+    public function setDeletedAt($deletedAt)
+    {
+        $this->deletedAt = $deletedAt;
+    }
+}
+```
+
+<a name="yaml-mapping"></a>
+
+## Yaml mapping example:
+
+Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
+
+```
+---
+Entity\Article:
+  type: entity
+  table: articles
+  gedmo:
+    soft_deleteable:
+      field_name: deletedAt
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+    deletedAt:
+      type: date
+      nullable: true
+```
+
+<a name="xml-mapping"></a>
+
+## Xml mapping example
+
+``` xml
+<?xml version="1.0" encoding="UTF-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+
+    <entity name="Mapping\Fixture\Xml\Timestampable" table="timestampables">
+        <id name="id" type="integer" column="id">
+            <generator strategy="AUTO"/>
+        </id>
+
+        <field name="title" type="string" />
+
+        <field name="deletedAt" type="datetime" nullable="true" />
+
+        <gedmo:soft-deleteable field-name="deletedAt" />
+    </entity>
+
+</doctrine-mapping>
+```
+
+<a name="usage"></a>
+
+## Usage:
+
+``` php
+<?php
+$article = new Article;
+$article->setTitle('My Article');
+
+$em->persist($article);
+$em->flush();
+
+// Now if we remove it, it will set the deletedAt field to the actual date
+$em->remove($article);
+$em->flush();
+
+$repo = $em->getRepository('Article');
+$art = $repo->findOneBy(array('title' => 'My Article'));
+
+// It should NOT return the article now
+$this->assertNull($art);
+
+// But if we disable the filter, the article should appear now
+$em->getFilters()->disable('soft-deleteable');
+
+$art = $repo->findOneBy(array('title' => 'My Article'));
+
+$this->assertTrue(is_object($art));
+
+// Enable / Disable filter filter, for specified entity (default is enabled for all)
+$filter = $em->getFilters()->enable('soft-deleteable');
+$filter->disableForEntity('Entity\Article');
+$filter->enableForEntity('Entity\Article');
+```
+
+Easy like that, any suggestions on improvements are very welcome.

+ 279 - 0
vendor/gedmo/doctrine-extensions/doc/sortable.md

@@ -0,0 +1,279 @@
+# Sortable behavior extension for Doctrine2
+
+**Sortable** behavior will maintain a position field for ordering
+entities.
+
+Features:
+
+- Automatic handling of position index
+- Group entity ordering by one or more fields
+- Can be nested with other behaviors
+- Annotation, Yaml and Xml mapping support for extensions
+
+[blog_reference]: http://gediminasm.org/article/sortable-behavior-extension-for-doctrine2 "Sortable extension will enable ordering on any entity or its relation"
+[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
+
+**Note:**
+
+- Public [Sortable repository](http://github.com/l3pp4rd/DoctrineExtensions "Sortable extension on Github") is available on github
+- Last update date: **2012-01-02**
+
+**Portability:**
+
+- **Sortable** is now available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
+ported to **Symfony2** by **Christophe Coevoet**, together with all other extensions
+
+This article will cover the basic installation and functionality of **Sortable**
+behavior
+
+Content:
+
+- [Including](#including-extension) the extension
+- Entity [example](#entity-mapping)
+- [Yaml](#yaml-mapping) mapping example
+- [Xml](#xml-mapping) mapping example
+- Basic usage [examples](#basic-examples)
+
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+<a name="entity-mapping"></a>
+
+## Sortable Entity example:
+
+### Sortable annotations:
+
+- **@Gedmo\Mapping\Annotation\SortableGroup** it will use this field for **grouping**
+- **@Gedmo\Mapping\Annotation\SortablePosition** it will use this column to store **position** index
+
+**Note:** that Sortable interface is not necessary, except in cases there
+you need to identify entity as being Sortable. The metadata is loaded only once then
+cache is activated
+
+**Note:** that you should register SortableRepository (or a subclass) as the repository in the Entity
+annotation to benefit from its query methods.
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Table(name="items")
+ * @ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
+ */
+class Item
+{
+    /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
+    private $id;
+
+    /**
+     * @ORM\Column(name="name", type="string", length=64)
+     */
+    private $name;
+
+    /**
+     * @Gedmo\SortablePosition
+     * @ORM\Column(name="position", type="integer")
+     */
+    private $position;
+
+    /**
+     * @Gedmo\SortableGroup
+     * @ORM\Column(name="category", type="string", length=128)
+     */
+    private $category;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function setPosition($position)
+    {
+        $this->position = $position;
+    }
+
+    public function getPosition()
+    {
+        return $this->position;
+    }
+    
+    public function setCategory($category)
+    {
+        $this->category = $category;
+    }
+    
+    public function getCategory()
+    {
+        return $this->category;
+    }
+}
+```
+
+<a name="yaml-mapping"></a>
+
+## Yaml mapping example
+
+Yaml mapped Item: **/mapping/yaml/Entity.Item.dcm.yml**
+
+```
+---
+Entity\Item:
+  type: entity
+  table: items
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    name:
+      type: string
+      length: 64
+    position:
+      type: integer
+      gedmo:
+        - sortablePosition
+    category:
+      type: string
+      length: 128
+      gedmo:
+        - sortableGroup
+```
+
+<a name="xml-mapping"></a>
+
+## Xml mapping example
+
+``` xml
+<?xml version="1.0" encoding="UTF-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+    <entity name="Entity\Item" table="items">
+        <id name="id" type="integer" column="id">
+            <generator strategy="AUTO"/>
+        </id>
+
+        <field name="name" type="string" length="128">
+        </field>
+
+        <field name="position" type="integer">
+            <gedmo:sortable-position/>
+        </field>
+        <field name="category" type="string" length="128">
+            <gedmo:sortable-group />
+        </field>
+    </entity>
+</doctrine-mapping>
+```
+
+<a name="basic-examples"></a>
+
+## Basic usage examples:
+
+### To save **Items** at the end of the sorting list simply do:
+
+``` php
+<?php
+// By default, items are appended to the sorting list
+$item1 = new Item();
+$item1->setName('item 1');
+$item1->setCategory('category 1');
+$this->em->persist($item1);
+
+$item2 = new Item();
+$item2->setName('item 2');
+$item2->setCategory('category 1');
+$this->em->persist($item2);
+
+$this->em->flush();
+
+echo $item1->getPosition();
+// prints: 0
+echo $item2->getPosition();
+// prints: 1
+```
+
+### Save **Item** at a given position:
+
+``` php
+<?php
+$item1 = new Item();
+$item1->setName('item 1');
+$item1->setCategory('category 1');
+$this->em->persist($item1);
+
+$item2 = new Item();
+$item2->setName('item 2');
+$item2->setCategory('category 1');
+$this->em->persist($item2);
+
+$item0 = new Item();
+$item0->setName('item 0');
+$item0->setCategory('category 1');
+$item0->setPosition(0);
+$this->em->persist($item0);
+
+$this->em->flush();
+
+$repo = $this->em->getRepository('Entity\\Item');
+$items = $repo->getBySortableGroupsQuery(array('category' => 'category 1'))->getResult();
+foreach ($items as $item) {
+    echo "{$item->getPosition()}: {$item->getName()}\n";
+}
+// prints:
+// 0: item 0
+// 1: item 1
+// 2: item 2
+```
+
+### Reordering the sorted list:
+
+``` php
+<?php
+$item1 = new Item();
+$item1->setName('item 1');
+$item1->setCategory('category 1');
+$this->em->persist($item1);
+
+$item2 = new Item();
+$item2->setName('item 2');
+$item2->setCategory('category 1');
+$this->em->persist($item2);
+
+$this->em->flush();
+
+// Update the position of item2
+$item2->setPosition(0);
+$this->em->persist($item2);
+
+$this->em->flush();
+
+$repo = $this->em->getRepository('Entity\\Item');
+$items = $repo->getBySortableGroupsQuery(array('category' => 'category 1'))->getResult();
+foreach ($items as $item) {
+    echo "{$item->getPosition()}: {$item->getName()}\n";
+}
+// prints:
+// 0: item 2
+// 1: item 1
+```

+ 438 - 0
vendor/gedmo/doctrine-extensions/doc/symfony2.md

@@ -0,0 +1,438 @@
+# Install Gedmo Doctrine2 extensions in Symfony2
+
+Configure full featured [Doctrine2 extensions](http://github.com/l3pp4rd/DoctrineExtensions) for your symfony2 project.
+This post will show you - how to create a simple configuration file to manage extensions with
+ability to use all features it provides.
+Interested? then bear with me! and don't be afraid, we're not diving into security component :)
+
+[blog_reference]: http://gediminasm.org/article/mapping-extension-for-doctrine2 "Mapping extension for Doctrine2 makes it easy to create extensions based on annotation, xml, yaml mapping drivers"
+[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
+
+This post will put some light over the shed of extension installation and mapping configuration
+of Doctrine2. It does not require any additional dependencies and gives you full power
+over management of extensions.
+
+Content:
+    
+- [Symfony2](#sf2-app) application
+- Extensions metadata [mapping](#ext-mapping)
+- Extension [listeners](#ext-listeners)
+- Usage [example](#ext-example)
+- Some [tips](#more-tips)
+- [Alternative](#alternative) over configuration
+
+<a name="sf2-app"></a>
+
+## Symfony2 application
+
+First of all, we will need a symfony2 startup application, lets say [symfony-standard edition
+with composer](http://github.com/KnpLabs/symfony-with-composer). Follow the standard setup:
+
+- `git clone git://github.com/KnpLabs/symfony-with-composer.git example`
+- `cd example && rm -rf .git && php bin/vendors install`
+- ensure your application loads and meet requirements, by following the url: **http://your_virtual_host/app_dev.php**
+
+Now lets add the **gedmo/doctrine-extensions** into **composer.json**
+
+    {
+        "require": {
+            "php":              ">=5.3.2",
+            "symfony/symfony":  ">=2.0.9,<2.1.0-dev",
+            "doctrine/orm":     ">=2.1.0,<2.2.0-dev",
+            "twig/extensions":  "*",
+    
+            "symfony/assetic-bundle":         "*",
+            "sensio/generator-bundle":        "2.0.*",
+            "sensio/framework-extra-bundle":  "2.0.*",
+            "sensio/distribution-bundle":     "2.0.*",
+            "jms/security-extra-bundle":      "1.0.*",
+            "gedmo/doctrine-extensions":      "dev-master"
+        },
+    
+        "autoload": {
+            "psr-0": {
+                "Acme": "src/"
+            }
+        }
+    }
+
+Update vendors, run: **php bin/vendors update**
+Initially in this package you have **doctrine2 orm** included, so we will base our setup
+and configuration for this specific connection. Do not forget to configure your database
+connection parameters, edit **app/config/parameters.ini**
+
+<a name="ext-mapping"></a>
+
+## Mapping
+
+Lets start from the mapping, in case if you use **translatable**, **tree** or **loggable**
+extension you will need to map those abstract mappedsuperclasses for you ORM to be aware of.
+To do so, add some mapping info to your **doctrine.orm** configuration, edit **app/config.yml**:
+
+    doctrine:
+        dbal:
+    # your dbal config here
+    
+        orm:
+            auto_generate_proxy_classes: %kernel.debug%
+            auto_mapping: true
+    # only these lines are added additionally 
+            mappings:
+                translatable:
+                    type: annotation
+                    alias: Gedmo
+                    prefix: Gedmo\Translatable\Entity
+                    # make sure vendor library location is correct
+                    dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
+
+After that, running **php app/console doctrine:mapping:info** you should see the output:
+
+    Found 3 entities mapped in entity manager default:
+    [OK]   Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation
+    [OK]   Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation
+    [OK]   Gedmo\Translatable\Entity\Translation
+
+Well we mapped only **translatable** for now, it really depends on your needs, which extensions
+your application uses.
+
+**Note:** there is **Gedmo\Translatable\Entity\Translation** which is not a super class, in that case
+if you create doctrine schema, it will add **ext_translations** table, which might not be useful
+to you also. To skip mapping of these entities, you can map **only superclasses**
+
+    mappings:
+        translatable:
+            type: annotation
+            alias: Gedmo
+            prefix: Gedmo\Translatable\Entity
+            # make sure vendor library location is correct
+            dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity/MappedSuperclass"
+
+The configuration above, adds a **/MappedSuperclass** into directory depth, after running
+**php app/console doctrine:mapping:info** you should only see now:
+
+    Found 2 entities mapped in entity manager default:
+    [OK]   Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation
+    [OK]   Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation
+
+This is very useful for advanced requirements and quite simple to understand. So lets map now
+everything extensions provide:
+
+    # only orm config branch of doctrine
+    orm:
+        auto_generate_proxy_classes: %kernel.debug%
+        auto_mapping: true
+    # only these lines are added additionally 
+        mappings:
+            translatable:
+                type: annotation
+                alias: Gedmo
+                prefix: Gedmo\Translatable\Entity
+                # make sure vendor library location is correct
+                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
+            loggable:
+                type: annotation
+                alias: Gedmo
+                prefix: Gedmo\Loggable\Entity
+                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Loggable/Entity"
+            tree:
+                type: annotation
+                alias: Gedmo
+                prefix: Gedmo\Tree\Entity
+                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Tree/Entity"
+
+<a name="ext-listeners"></a>
+
+## Doctrine extension listener services
+
+Next, the heart of extensions are behavioral listeners which pours all the sugar. We will
+create a **yml** service file in our config directory. The setup can be different and located
+in the bundle, it depends what you prefer, edit **app/config/doctrine_extensions.yml**
+
+    # services to handle doctrine extensions
+    # import it in config.yml
+    services:
+        # KernelRequest listener
+        extension.listener:
+            class: Acme\DemoBundle\Listener\DoctrineExtensionListener
+            calls:
+                - [ setContainer, [ @service_container ] ]
+            tags:
+                # translatable sets locale after router processing
+                - { name: kernel.event_listener, event: kernel.request, method: onLateKernelRequest, priority: -10 }
+                # loggable hooks user username if one is in security context
+                - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
+    
+    
+        # Doctrine Extension listeners to handle behaviors
+        gedmo.listener.tree:
+            class: Gedmo\Tree\TreeListener
+            tags:
+                - { name: doctrine.event_subscriber, connection: default }
+            calls:
+                - [ setAnnotationReader, [ @annotation_reader ] ]
+                
+        gedmo.listener.translatable:
+            class: Gedmo\Translatable\TranslatableListener
+            tags:
+                - { name: doctrine.event_subscriber, connection: default }
+            calls:
+                - [ setAnnotationReader, [ @annotation_reader ] ]
+                - [ setDefaultLocale, [ %locale% ] ]
+                - [ setTranslationFallback, [ false ] ]
+        
+        gedmo.listener.timestampable:
+            class: Gedmo\Timestampable\TimestampableListener
+            tags:
+                - { name: doctrine.event_subscriber, connection: default }
+            calls:
+                - [ setAnnotationReader, [ @annotation_reader ] ]
+        
+        gedmo.listener.sluggable:
+            class: Gedmo\Sluggable\SluggableListener
+            tags:
+                - { name: doctrine.event_subscriber, connection: default }
+            calls:
+                - [ setAnnotationReader, [ @annotation_reader ] ]
+        
+        gedmo.listener.sortable:
+            class: Gedmo\Sortable\SortableListener
+            tags:
+                - { name: doctrine.event_subscriber, connection: default }
+            calls:
+                - [ setAnnotationReader, [ @annotation_reader ] ]
+        
+        gedmo.listener.loggable:
+            class: Gedmo\Loggable\LoggableListener
+            tags:
+                - { name: doctrine.event_subscriber, connection: default }
+            calls:
+                - [ setAnnotationReader, [ @annotation_reader ] ]
+
+So what it includes in general? Well it creates services for all extension listeners.
+You can remove some which you do not use or change at will. **Translatable** for instance,
+sets default locale to `%locale%` parameter, you can configure it differently.
+
+**Note:** if you noticed, theres **Acme\DemoBundle\Listener\DoctrineExtensionListener**
+you will need to create this listener class if you use **loggable** or **translatable**
+behaviors. This listener will set the **locale used** from request and **username** to
+loggable. So, to finish the setup create **Acme\DemoBundle\Listener\DoctrineExtensionListener**
+
+    <?php
+    
+    // file: src/Acme/DemoBundle/Listener/DoctrineExtensionListener.php
+    
+    namespace Acme\DemoBundle\Listener;
+    
+    use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+    use Symfony\Component\DependencyInjection\ContainerAwareInterface;
+    use Symfony\Component\DependencyInjection\ContainerInterface;
+    
+    class DoctrineExtensionListener implements ContainerAwareInterface
+    {
+        /**
+         * @var ContainerInterface
+         */
+        protected $container;
+    
+        public function setContainer(ContainerInterface $container = null)
+        {
+            $this->container = $container;
+        }
+    
+        public function onLateKernelRequest(GetResponseEvent $event)
+        {
+            $translatable = $this->container->get('gedmo.listener.translatable');
+            $translatable->setTranslatableLocale($event->getRequest()->getLocale());
+        }
+    
+        public function onKernelRequest(GetResponseEvent $event)
+        {
+            $securityContext = $this->container->get('security.context', ContainerInterface::NULL_ON_INVALID_REFERENCE);
+            if (null !== $securityContext && null !== $securityContext->getToken() && $securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
+                $loggable = $this->container->get('gedmo.listener.loggable');
+                $loggable->setUsername($securityContext->getToken()->getUsername());
+            }
+        }
+    }
+
+Do not forget to import **doctrine_extensions.yml** in your **app/config/config.yml** etc.:
+
+    # file: app/config/config.yml
+    imports:
+        - { resource: parameters.ini }
+        - { resource: security.yml }
+        - { resource: doctrine_extensions.yml }
+    
+    # ... configuration follows
+
+<a name="ext-example"></a>
+
+## Example
+
+Well after that, you have your extensions setup and ready to be used! Too easy right? Well
+if you do not believe me, lets create a simple entity in our **Acme** project:
+
+    <?php
+    
+    // file: src/Acme/DemoBundle/Entity/BlogPost.php
+    
+    namespace Acme\DemoBundle\Entity;
+    
+    use Gedmo\Mapping\Annotation as Gedmo; // gedmo annotations
+    use Doctrine\ORM\Mapping as ORM; // doctrine orm annotations
+    
+    /**
+     * @ORM\Entity
+     */
+    class BlogPost
+    {
+        /**
+         * @Gedmo\Slug(fields={"title"}, updatable=false, separator="_")
+         * @ORM\Id
+         * @ORM\Column(length=32, unique=true)
+         */
+        private $id;
+    
+        /**
+         * @Gedmo\Translatable
+         * @ORM\Column(length=64)
+         */
+        private $title;
+    
+        /**
+         * @Gedmo\Timestampable(on="create")
+         * @ORM\Column(name="created", type="datetime")
+         */
+        private $created;
+    
+        /**
+         * @ORM\Column(name="updated", type="datetime")
+         * @Gedmo\Timestampable(on="update")
+         */
+        private $updated;
+    
+        public function getId()
+        {
+            return $this->id;
+        }
+    
+        public function setTitle($title)
+        {
+            $this->title = $title;
+        }
+    
+        public function getTitle()
+        {
+            return $this->title;
+        }
+    
+        public function getCreated()
+        {
+            return $this->created;
+        }
+    
+        public function getUpdated()
+        {
+            return $this->updated;
+        }
+    }
+
+Now, lets have some fun:
+
+- if you have not created database yet, run `php app/console doctrine:database:create`
+- create the schema `php app/console doctrine:schema:create`
+
+Well, everything will work just fine, you can modify the **Acme\DemoBundle\Controller\DemoController**
+and add an action to test how it works:
+
+    // file: src/Acme/DemoBundle/Controller/DemoController.php
+    // include this code portion
+    
+    /**
+     * @Route("/posts", name="_demo_posts")
+     */
+    public function postsAction()
+    {
+        $em = $this->getDoctrine()->getEntityManager();
+        $repository = $em->getRepository('AcmeDemoBundle:BlogPost');
+        // create some posts in case if there aren't any
+        if (!$repository->findOneById('hello_world')) {
+            $post = new \Acme\DemoBundle\Entity\BlogPost();
+            $post->setTitle('Hello world');
+
+            $next = new \Acme\DemoBundle\Entity\BlogPost();
+            $next->setTitle('Doctrine extensions');
+
+            $em->persist($post);
+            $em->persist($next);
+            $em->flush();
+        }
+        $posts = $em
+            ->createQuery('SELECT p FROM AcmeDemoBundle:BlogPost p')
+            ->getArrayResult()
+        ;
+        die(var_dump($posts));
+    }
+
+Now if you follow the url: **http://your_virtual_host/app_dev.php/demo/posts** you
+should see a print of posts, this is only an extension demo, we will not create template.
+
+<a name="more-tips"></a>
+
+## More tips
+
+Regarding, the setup, I do not think its too complicated to use, in general it is simple
+enough, and lets you understand at least small parts on how you can hook mapping into doctrine,
+how easily extension services are added. This configuration does not hide anything behind
+curtains and allows you to modify the configuration as you require.
+
+### Multiple entity managers
+
+If you use more than one entity manager, you can simply tag the listener
+with other manager name:
+
+    services:
+        # tree behavior
+        gedmo.listener.tree:
+            class: Gedmo\Tree\TreeListener
+            tags:
+                - { name: doctrine.event_subscriber, connection: default }
+                # additional ORM subscriber
+                - { name: doctrine.event_subscriber, connection: other_connection }
+                # ODM MongoDb subscriber, where **default** is manager name
+                - { name: doctrine_mongodb.odm.event_subscriber }
+            calls:
+                - [ setAnnotationReader, [ @annotation_reader ] ]
+
+Well regarding, mapping of ODM mongodb, its basically the same:
+
+    doctrine_mongodb:
+        default_database: 'my_database'
+        default_connection: 'default'
+        default_document_manager: 'default'
+        connections:
+            default: ~
+        document_managers:
+            default:
+                connection: 'default'
+                auto_mapping: true
+                mappings:
+                    translatable:
+                        type: annotation
+                        alias: GedmoDocument
+                        prefix: Gedmo\Translatable\Document
+                        # make sure vendor library location is correct
+                        dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Document"
+
+This also shows, how to make mappings based on single manager. All what differs is **Document**
+instead of **Entity** used. Haven't tested it with mongo though.
+
+**Note:** [extension repository](http://github.com/l3pp4rd/DoctrineExtensions) contains all
+[documentation](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/doc) you may need
+to understand how you can use it in your projects.
+
+<a name="alternative"></a>
+
+## Alternative over configuration
+
+You can use [StofDoctrineExtensionsBundle](http://github.com/stof/StofDoctrineExtensionsBundle) which is a wrapper of these extensions

+ 623 - 0
vendor/gedmo/doctrine-extensions/doc/timestampable.md

@@ -0,0 +1,623 @@
+# Timestampable behavior extension for Doctrine 2
+
+**Timestampable** behavior will automate the update of date fields
+on your Entities or Documents. It works through annotations and can update 
+fields on creation, update or even on specific property value change.
+
+Features:
+
+- Automatic predifined date field update on creation, update and even on record property changes
+- ORM and ODM support using same listener
+- Specific annotations for properties, and no interface required
+- Can react to specific property or relation changes to specific value 
+- Can be nested with other behaviors 
+- Annotation, Yaml and Xml mapping support for extensions
+
+[blog_reference]: http://gediminasm.org/article/timestampable-behavior-extension-for-doctrine-2 "Timestampable extension for Doctrine 2 helps automate update of dates"
+[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
+
+Update **2012-03-10**
+
+- Add [Timestampable traits](#traits)
+
+Update **2011-04-04**
+ 
+- Made single listener, one instance can be used for any object manager
+and any number of them
+
+**Note:**
+
+- You can [test live][blog_test] on this blog
+- Public [Timestampable repository](http://github.com/l3pp4rd/DoctrineExtensions "Timestampable extension on Github") is available on github
+- Last update date: **2012-01-02**
+
+**Portability:**
+
+- **Timestampable** is now available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
+ported to **Symfony2** by **Christophe Coevoet**, together with all other extensions
+
+This article will cover the basic installation and functionality of **Timestampable** behavior
+
+Content:
+
+- [Including](#including-extension) the extension
+- Entity [example](#entity-mapping)
+- Document [example](#document-mapping)
+- [Yaml](#yaml-mapping) mapping example
+- [Xml](#xml-mapping) mapping example
+- Advanced usage [examples](#advanced-examples)
+- Using [Traits](#traits)
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+<a name="entity-mapping"></a>
+
+## Timestampable Entity example:
+
+### Timestampable annotations:
+- **@Gedmo\Mapping\Annotation\Timestampable** this annotation tells that this column is timestampable
+by default it updates this column on update. If column is not date, datetime or time
+type it will trigger an exception.
+
+Available configuration options:
+
+- **on** - is main option and can be **create, update, change** this tells when it 
+should be updated
+- **field** - only valid if **on="change"** is specified, tracks property for changes
+- **value** - only valid if **on="change"** is specified, if tracked field has this **value** 
+then it updates timestamp
+
+**Note:** that Timestampable interface is not necessary, except in cases there
+you need to identify entity as being Timestampable. The metadata is loaded only once then
+cache is activated
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class Article
+{
+    /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=128)
+     */
+    private $title;
+
+    /**
+     * @var datetime $created
+     *
+     * @Gedmo\Timestampable(on="create")
+     * @ORM\Column(type="datetime")
+     */
+    private $created;
+
+    /**
+     * @var datetime $updated
+     *
+     * @Gedmo\Timestampable(on="update")
+     * @ORM\Column(type="datetime")
+     */
+    private $updated;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    public function getUpdated()
+    {
+        return $this->updated;
+    }
+}
+```
+
+<a name="document-mapping"></a>
+
+## Timestampable Document example:
+
+``` php
+<?php
+namespace Document;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
+
+/**
+ * @ODM\Document(collection="articles")
+ */
+class Article
+{
+    /** @ODM\Id */
+    private $id;
+
+    /**
+     * @ODM\String
+     */
+    private $title;
+
+    /**
+     * @var date $created
+     *
+     * @ODM\Date
+     * @Gedmo\Timestampable(on="create")
+     */
+    private $created;
+
+    /**
+     * @var date $updated
+     *
+     * @ODM\Date
+     * @Gedmo\Timestampable
+     */
+    private $updated;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    public function getUpdated()
+    {
+        return $this->updated;
+    }
+}
+```
+
+Now on update and creation these annotated fields will be automatically updated
+
+<a name="yaml-mapping"></a>
+
+## Yaml mapping example:
+
+Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
+
+```
+---
+Entity\Article:
+  type: entity
+  table: articles
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+      length: 64
+    created:
+      type: date
+      gedmo:
+        timestampable:
+          on: create
+    updated:
+      type: datetime
+      gedmo:
+        timestampable:
+          on: update
+```
+
+<a name="xml-mapping"></a>
+
+## Xml mapping example
+
+``` xml
+<?xml version="1.0" encoding="UTF-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+
+    <entity name="Mapping\Fixture\Xml\Timestampable" table="timestampables">
+        <id name="id" type="integer" column="id">
+            <generator strategy="AUTO"/>
+        </id>
+
+        <field name="created" type="datetime">
+            <gedmo:timestampable on="create"/>
+        </field>
+        <field name="updated" type="datetime">
+            <gedmo:timestampable on="update"/>
+        </field>
+        <field name="published" type="datetime" nullable="true">
+            <gedmo:timestampable on="change" field="status.title" value="Published"/>
+        </field>
+
+        <many-to-one field="status" target-entity="Status">
+            <join-column name="status_id" referenced-column-name="id"/>
+        </many-to-one>
+    </entity>
+
+</doctrine-mapping>
+```
+
+<a name="advanced-examples"></a>
+
+## Advanced examples:
+
+### Using dependency of property changes
+
+Add another entity which would represent Article Type:
+
+``` php
+<?php
+namespace Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class Type
+{
+    /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=128)
+     */
+    private $title;
+
+    /**
+     * @ORM\OneToMany(targetEntity="Article", mappedBy="type")
+     */
+    private $articles;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+}
+```
+
+Now update the Article Entity to reflect published date on Type change:
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class Article
+{
+    /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
+    private $id;
+
+    /**
+     * @ORM\Column(type="string", length=128)
+     */
+    private $title;
+
+    /**
+     * @var datetime $created
+     *
+     * @Gedmo\Timestampable(on="create")
+     * @ORM\Column(type="datetime")
+     */
+    private $created;
+
+    /**
+     * @var datetime $updated
+     *
+     * @Gedmo\Timestampable(on="update")
+     * @ORM\Column(type="datetime")
+     */
+    private $updated;
+
+    /**
+     * @ORM\ManyToOne(targetEntity="Type", inversedBy="articles")
+     */
+    private $type;
+
+    /**
+     * @var datetime $published
+     *
+     * @ORM\Column(type="datetime", nullable=true)
+     * @Gedmo\Timestampable(on="change", field="type.title", value="Published")
+     */
+    private $published;
+
+    public function setType($type)
+    {
+        $this->type = $type;
+    }
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    public function getUpdated()
+    {
+        return $this->updated;
+    }
+
+    public function getPublished()
+    {
+        return $this->published;
+    }
+}
+```
+
+Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
+
+```
+---
+Entity\Article:
+  type: entity
+  table: articles
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+      length: 64
+    created:
+      type: date
+      gedmo:
+        timestampable:
+          on: create
+    updated:
+      type: datetime
+      gedmo:
+        timestampable:
+          on: update
+    published:
+      type: datetime
+      gedmo:
+        timestampable:
+          on: change
+          field: type.title
+          value: Published
+  manyToOne:
+    type:
+      targetEntity: Entity\Type
+      inversedBy: articles
+```
+
+Now few operations to get it all done:
+
+``` php
+<?php
+$article = new Article;
+$article->setTitle('My Article');
+
+$em->persist($article);
+$em->flush();
+// article: $created, $updated were set
+
+$type = new Type;
+$type->setTitle('Published');
+
+$article = $em->getRepository('Entity\Article')->findByTitle('My Article');
+$article->setType($type);
+
+$em->persist($article);
+$em->persist($type);
+$em->flush();
+// article: $published, $updated were set
+
+$article->getPublished()->format('Y-m-d'); // the date article type changed to published
+```
+
+Easy like that, any suggestions on improvements are very welcome
+
+### Creating a UTC DateTime type that stores your datetimes in UTC
+
+First, we define our custom data type (note the type name is datetime and the type extends DateTimeType which simply overrides the default Doctrine type):
+
+``` php
+<?php
+
+namespace Acme\DoctrineExtensions\DBAL\Types;
+
+use Doctrine\DBAL\Types\DateTimeType;
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use Doctrine\DBAL\Types\ConversionException;
+
+class UTCDateTimeType extends DateTimeType
+{
+    static private $utc = null;
+
+    public function convertToDatabaseValue($value, AbstractPlatform $platform)
+    {
+        if ($value === null) {
+            return null;
+        }
+
+        if (is_null(self::$utc)) {
+            self::$utc = new \DateTimeZone('UTC');
+        }
+
+        $value->setTimeZone(self::$utc);
+
+        return $value->format($platform->getDateTimeFormatString());
+    }
+
+    public function convertToPHPValue($value, AbstractPlatform $platform)
+    {
+        if ($value === null) {
+            return null;
+        }
+
+        if (is_null(self::$utc)) {
+            self::$utc = new \DateTimeZone('UTC');
+        }
+
+        $val = \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value, self::$utc);
+
+        if (!$val) {
+            throw ConversionException::conversionFailed($value, $this->getName());
+        }
+
+        return $val;
+    }
+}
+```
+
+Now in Symfony2, we register and override the **datetime** type. **WARNING:** this will override the **datetime** type for all your entities and for all entities in external bundles or extensions, so if you have some entities that require the standard **datetime** type from Doctrine, you must modify the above type and use a different name (such as **utcdatetime**). Additionally, you'll need to modify **Timestampable** so that it includes **utcdatetime** as a valid type.
+
+```
+doctrine:
+    dbal:
+        types: 
+            datetime: Acme\DoctrineExtensions\DBAL\Types\UTCDateTimeType
+```
+
+And our Entity properties look as expected:
+
+``` php
+<?php
+/**
+ * @var datetime $dateCreated
+ *
+ * @ORM\Column(name="date_created", type="datetime")
+ * @Gedmo\Timestampable(on="create")
+ */
+private $dateCreated;
+
+/**
+ * @var datetime $dateLastModified
+ *
+ * @Gedmo\Timestampable(on="update")
+ * @ORM\Column(name="date_last_modified", type="datetime")
+ */
+private $dateLastModified;
+```
+
+Now, in our view (suppose we are using Symfony2 and Twig), we can display the datetime (which is persisted in UTC format) in our user's time zone:
+
+``` html
+{{ myEntity.dateCreated | date("d/m/Y g:i a", app.user.timezone) }}
+```
+
+Or if the user does not have a timezone, we could expand that to use a system/app/PHP default timezone.
+
+[doctrine_custom_datetime_type]: http://www.doctrine-project.org/docs/orm/2.0/en/cookbook/working-with-datetime.html#handling-different-timezones-with-the-datetime-type "Handling different Timezones with the DateTime Type"
+
+This example is based off [Handling different Timezones with the DateTime Type][doctrine_custom_datetime_type] - however that example may be outdated because it contains some obvioulsy invalid PHP from the TimeZone class.
+
+<a name="traits"></a>
+
+## Traits
+
+You can use timestampable traits for quick **createdAt** **updatedAt** timestamp definitions
+when using annotation mapping.
+
+**Note:** this feature is only available since php **5.4.0**. And you are not required
+to use the Traits provided by extensions.
+
+``` php
+<?php
+namespace Timestampable\Fixture;
+
+use Gedmo\Timestampable\Traits\TimestampableEntity;
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class UsingTrait
+{
+    /**
+     * Hook timestampable behavior
+     * updates createdAt, updatedAt fields
+     */
+    use TimestampableEntity;
+
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(length=128)
+     */
+    private $title;
+}
+```
+
+**Note:** you must import **Gedmo\Mapping\Annotation as Gedmo** and **Doctrine\ORM\Mapping as ORM**
+annotations. If you use mongodb ODM import **Doctrine\ODM\MongoDB\Mapping\Annotations as ODM** and
+**TimestampableDocument** instead.
+
+Traits are very simple and if you use different field names I recomment to simply create your
+own ones based per project. These ones are standing as an example.
+

+ 898 - 0
vendor/gedmo/doctrine-extensions/doc/translatable.md

@@ -0,0 +1,898 @@
+# Translatable behavior extension for Doctrine 2
+
+**Translatable** behavior offers a very handy solution for translating specific record fields
+in diferent languages. Further more, it loads the translations automatically for a locale
+currently used, which can be set to **Translatable Listener** on it`s initialization or later
+for other cases through the **Entity** itself
+
+Features:
+
+- Automatic storage of translations in database
+- ORM and ODM support using same listener
+- Automatic translation of Entity or Document fields then loaded
+- ORM query can use **hint** to translate all records without issuing additional queries
+- Can be nested with other behaviors
+- Annotation, Yaml and Xml mapping support for extensions
+
+[blog_reference]: http://gediminasm.org/article/translatable-behavior-extension-for-doctrine-2 "Translatable extension for Doctrine 2 makes automatic record field translations and their loading depending on language used"
+[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
+
+**2012-01-28**
+
+- Created personal translation which maps through real foreign key
+constraint. This dramatically improves the management of translations
+
+**2012-01-04**
+
+- Refactored translatable to be able to persist, update many translations
+using repository, [issue #224](https://github.com/l3pp4rd/DoctrineExtensions/issues/224)
+
+**2011-12-11**
+
+- Added more useful translation query hints: Override translatable locale, inner join
+translations instead left join, override translation fallback
+
+**2011-11-08**
+
+- Thanks to [@acasademont](https://github.com/acasademont) Translatable now does not store translations for default locale. It is always left as original record value.
+So be sure you do not change your default locale per project or per data migration. This way
+it is more rational and unnecessary to store it additionaly in translation table.
+
+Update **2011-04-21**
+
+- Implemented multiple translation persistense through repository
+
+Update **2011-04-16**
+
+- Made an ORM query **hint** to hook into any select type query, which will join the translations
+and let you **filter, order or search** by translated fields directly. It also will translate
+all selected **collections or simple components** without issuing additional queries. It also
+supports translation fallbacks
+- For performance reasons, translation fallbacks are disabled by default
+
+Update **2011-04-04**
+
+- Made single listener, one instance can be used for any object manager
+and any number of them
+
+**Note list:**
+
+- You can [test live][blog_test] on this blog 
+- Public [Translatable repository](http://github.com/l3pp4rd/DoctrineExtensions "Translatable extension on Github") is available on github
+- Using other extensions on the same Entity fields may result in unexpected way
+- May inpact your application performace since it does an additional query for translation if loaded without query hint
+- Last update date: **2012-02-15**
+
+**Portability:**
+
+- **Translatable** is now available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
+ported to **Symfony2** by **Christophe Coevoet**, together with all other extensions
+
+This article will cover the basic installation and functionality of **Translatable** behavior
+
+Content:
+
+- [Including](#including-extension) the extension
+- Entity [example](#entity-domain-object)
+- Document [example](#document-domain-object)
+- [Yaml](#yaml-mapping) mapping example
+- [Xml](#xml-mapping) mapping example
+- Basic usage [examples](#basic-examples)
+- [Persisting](#multi-translations) multiple translations
+- Using ORM query [hint](#orm-query-hint)
+- Advanced usage [examples](#advanced-examples)
+- Personal [translations](#personal-translations)
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+### Translatable annotations:
+- **@Gedmo\Mapping\Annotation\Translatable** it will **translate** this field
+- **@Gedmo\Mapping\Annotation\TranslationEntity(class="my\class")** it will use this class to store **translations** generated
+- **@Gedmo\Mapping\Annotation\Locale or @Gedmo\Mapping\Annotation\Language** this will identify this column as **locale** or **language**
+used to override the global locale
+
+<a name="entity-domain-object"></a>
+
+## Translatable Entity example:
+
+**Note:** that Translatable interface is not necessary, except in cases there
+you need to identify entity as being Translatable. The metadata is loaded only once then
+cache is activated
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+use Gedmo\Translatable\Translatable;
+
+/**
+ * @ORM\Table(name="articles")
+ * @ORM\Entity
+ */
+class Article implements Translatable
+{
+    /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
+    private $id;
+
+    /**
+     * @Gedmo\Translatable
+     * @ORM\Column(name="title", type="string", length=128)
+     */
+    private $title;
+
+    /**
+     * @Gedmo\Translatable
+     * @ORM\Column(name="content", type="text")
+     */
+    private $content;
+
+    /**
+     * @Gedmo\Locale
+     * Used locale to override Translation listener`s locale
+     * this is not a mapped field of entity metadata, just a simple property
+     */
+    private $locale;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setContent($content)
+    {
+        $this->content = $content;
+    }
+
+    public function getContent()
+    {
+        return $this->content;
+    }
+
+    public function setTranslatableLocale($locale)
+    {
+        $this->locale = $locale;
+    }
+}
+```
+
+<a name="document-domain-object"></a>
+
+## Translatable Document example:
+
+``` php
+<?php
+namespace Document;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
+use Gedmo\Translatable\Translatable;
+
+/**
+ * @ODM\Document(collection="articles")
+ */
+class Article implements Translatable
+{
+    /** @ODM\Id */
+    private $id;
+
+    /**
+     * @Gedmo\Translatable
+     * @ODM\String
+     */
+    private $title;
+
+    /**
+     * @Gedmo\Translatable
+     * @ODM\String
+     */
+    private $content;
+
+    /**
+     * @Gedmo\Locale
+     * Used locale to override Translation listener`s locale
+     * this is not a mapped field of entity metadata, just a simple property
+     */
+    private $locale;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setContent($content)
+    {
+        $this->content = $content;
+    }
+
+    public function getContent()
+    {
+        return $this->content;
+    }
+
+    public function setTranslatableLocale($locale)
+    {
+        $this->locale = $locale;
+    }
+}
+```
+
+<a name="yaml-mapping"></a>
+
+## Yaml mapping example
+
+Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
+
+```
+---
+Entity\Article:
+  type: entity
+  table: articles
+  gedmo:
+    translation:
+      locale: localeField
+# using specific personal translation class:
+#     entity: Translatable\Fixture\CategoryTranslation
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+      length: 64
+      gedmo:
+        - translatable
+    content:
+      type: text
+      gedmo:
+        - translatable
+```
+
+<a name="xml-mapping"></a>
+
+## Xml mapping example
+
+``` xml
+<?xml version="1.0" encoding="UTF-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+
+    <entity name="Mapping\Fixture\Xml\Translatable" table="translatables">
+
+        <id name="id" type="integer" column="id">
+            <generator strategy="AUTO"/>
+        </id>
+
+        <field name="title" type="string" length="128">
+            <gedmo:translatable/>
+        </field>
+        <field name="content" type="text">
+            <gedmo:translatable/>
+        </field>
+
+        <gedmo:translation entity="Gedmo\Translatable\Entity\Translation" locale="locale"/>
+
+    </entity>
+
+</doctrine-mapping>
+```
+
+<a name="basic-examples"></a>
+
+## Basic usage examples: {#basic-examples}
+
+Currently a global locale used for translations is "en_us" which was
+set in **TranslationListener** globaly. To save article with its translations:
+
+``` php
+<?php
+$article = new Entity\Article;
+$article->setTitle('my title in en');
+$article->setContent('my content in en');
+$em->persist($article);
+$em->flush();
+```
+
+This inserted an article and inserted the translations for it in "en_us" locale
+only if **en_us** is not the [default locale](#advanced-examples) in case if default locale
+matches current locale - it uses original record value as translation
+
+Now lets update our article in diferent locale:
+
+``` php
+<?php
+// first load the article
+$article = $em->find('Entity\Article', 1 /*article id*/);
+$article->setTitle('my title in de');
+$article->setContent('my content in de');
+$article->setTranslatableLocale('de_de'); // change locale
+$em->persist($article);
+$em->flush();
+```
+
+This updated an article and inserted the translations for it in "de_de" locale
+To see and load all translations of **Translatable** Entity:
+
+``` php
+<?php
+// reload in different language
+$article = $em->find('Entity\Article', 1 /*article id*/);
+$article->setLocale('ru_ru');
+$em->refresh($article);
+
+$article = $em->find('Entity\Article', 1 /*article id*/);
+$repository = $em->getRepository('Gedmo\Translatable\Entity\Translation');
+$translations = $repository->findTranslations($article);
+/* $translations contains:
+Array (
+    [de_de] => Array
+        (
+            [title] => my title in de
+            [content] => my content in de
+        )
+
+    [en_us] => Array
+        (
+            [title] => my title in en
+            [content] => my content in en
+        )
+)*/
+```
+
+As far as our global locale is now "en_us" and updated article has "de_de" values.
+Lets try to load it and it should be translated in English
+
+``` php
+<?php
+$article = $em->getRepository('Entity\Article')->find(1/* id of article */);
+echo $article->getTitle();
+// prints: "my title in en"
+echo $article->getContent();
+// prints: "my content in en"
+```
+
+<a name="multi-translations"></a>
+
+## Persisting multiple translations
+
+Usually it is more convinient to persist more translations when creating
+or updating a record. **Translatable** allows to do that through translation repository.
+All additional translations will be tracked by listener and when the flush will be executed,
+it will update or persist all additional translations.
+
+**Note:** these translations will not be processed as ordinary fields of your object,
+in case if you translate a **slug** additional translation will not know how to generate
+the slug, so the value as an additional translation should be processed when creating it.
+
+### Example of multiple translations:
+
+``` php
+<?php
+// persisting multiple translations, assume default locale is EN
+$repository = $em->getRepository('Gedmo\\Translatable\\Entity\\Translation');
+// it works for ODM also
+$article = new Article;
+$article->setTitle('My article en');
+$article->setContent('content en');
+
+$repository->translate($article, 'title', 'de', 'my article de')
+    ->translate($article, 'content', 'de', 'content de')
+    ->translate($article, 'title', 'ru', 'my article ru')
+    ->translate($article, 'content', 'ru', 'content ru')
+;
+
+$em->persist($article);
+$em->flush();
+
+// updating same article also having one new translation
+
+$repo
+    ->translate($article, 'title', 'lt', 'title lt')
+    ->translate($article, 'content', 'lt', 'content lt')
+    ->translate($article, 'title', 'ru', 'title ru change')
+    ->translate($article, 'content', 'ru', 'content ru change')
+    ->translate($article, 'title', 'en', 'title en (default locale) update')
+    ->translate($article, 'content', 'en', 'content en (default locale) update')
+;
+$em->flush();
+```
+
+<a name="orm-query-hint"></a>
+
+## Using ORM query hint
+
+By default, behind the scenes, when you load a record - translatable hooks into **postLoad**
+event and issues additional query to translate all fields. Imagine that, when you load a collection,
+it may issue a lot of queries just to translate those fields. Including array hydration, 
+it is not possible to hook any **postLoad** event since it is not an
+entity being hydrated. These are the main reasons why **TranslationWalker** was created.
+
+**TranslationWalker** uses a query **hint** to hook into any **select type query**,
+and when you execute the query, no matter which hydration method you use, it automatically
+joins the translations for all fields, so you could use ordering filtering or whatever you
+want on **translated fields** instead of original record fields.
+
+And in result there is only one query for all this happyness.
+
+If you use translation [fallbacks](#advanced-examples) it will be also in the same single
+query and during the hydration process it will replace the empty fields in case if they
+do not have a translation in currently used locale.
+
+Now enough talking, here is an example:
+
+``` php
+<?php
+$dql = <<<___SQL
+  SELECT a, c, u
+  FROM Article a
+  LEFT JOIN a.comments c
+  JOIN c.author u
+  WHERE a.title LIKE '%translated_title%'
+  ORDER BY a.title
+___SQL;
+
+$query = $em->createQuery($dql);
+// set the translation query hint
+$query->setHint(
+    \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
+    'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
+);
+
+$articles = $query->getResult(); // object hydration
+$articles = $query->getArrayResult(); // array hydration
+```
+
+And even a subselect:
+
+``` php
+<?php
+$dql = <<<___SQL
+  SELECT a, c, u
+  FROM Article a
+  LEFT JOIN a.comments c
+  JOIN c.author u
+  WHERE a.id IN (
+    SELECT a2.id
+    FROM Article a2
+    WHERE a2.title LIKE '%something_translated%'
+      AND a2.status = 1
+  )
+  ORDER BY a.title
+___SQL;
+
+$query = $em->createQuery($dql);
+$query->setHint(
+    \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
+    'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
+);
+```
+
+**NOTE:** if you use memcache or apc. You should set locale and other options like fallbacks
+to query through hints. Otherwise the query will be cached with a first used locale
+
+``` php
+<?php
+// locale
+$query->setHint(
+    \Gedmo\Translatable\TranslatableListener::HINT_TRANSLATABLE_LOCALE,
+    'en', // take locale from session or request etc.
+);
+// fallback
+$query->setHint(
+    \Gedmo\Translatable\TranslatableListener::HINT_FALLBACK,
+    1, // fallback to default values in case if record is not translated
+);
+
+$articles = $query->getResult(); // object hydration
+```
+
+Theres no need for any words anymore.. right?
+I recommend you to use it extensively since it is a way better performance, even in
+cases where you need to load single translated entity.
+
+**Note**: Even in **COUNT** select statements translations are joined to leave a
+possibility to filter by translated field, if you do not need it, just do not set
+the **hint**. Also take into account that it is not possibble to translate components
+in **JOIN WITH** statement, example
+
+```
+JOIN a.comments c WITH c.message LIKE '%will_not_be_translated%'`
+```
+
+**Note**: any **find** related method calls cannot hook this hint automagically, we
+will use a different approach when **persister overriding feature** will be
+available in **Doctrine** 
+
+In case if **translation query walker** is used, you can additionally override:
+
+### Overriding translation fallback
+
+``` php
+<?php
+$query->setHint(Gedmo\TranslationListener::HINT_FALLBACK, 1);
+```
+
+will fallback to default locale translations instead of empty values if used.
+And will override the translation listener setting for fallback.
+
+``` php
+<?php
+$query->setHint(Gedmo\TranslationListener::HINT_FALLBACK, 0);
+```
+
+will do the opposite.
+
+### Using inner join strategy
+
+``` php
+<?php
+$query->setHint(Gedmo\TranslationListener::HINT_INNER_JOIN, true);
+```
+
+will use **INNER** joins
+for translations instead of **LEFT** joins, so that in case if you do not want untranslated
+records in your result set for instance.
+
+### Overriding translatable locale
+
+``` php
+<?php
+$query->setHint(Gedmo\TranslationListener::HINT_TRANSLATABLE_LOCALE, 'en');
+```
+
+would override the translation locale used to translate the resultset.
+
+**Note:** all these query hints lasts only for the specific query.
+
+<a name="advanced-examples"></a>
+
+## Advanced examples:
+
+### Default locale
+
+In some cases we need a default translation as a fallback if record does not have
+a translation on globaly used locale. In that case Translation Listener takes the
+current value of Entity. So if **default locale** is specified and it matches the
+locale in which record is being translated - it will not create extra translation
+but use original values instead. If translation fallback is set to **false** it
+will fill untranslated values as blanks
+
+To set the default locale:
+
+``` php
+<?php
+$translatableListener->setDefaultLocale('en_us');
+```
+
+To set translation fallback:
+
+``` php
+<?php
+$translatableListener->setTranslationFallback(true); // default is false
+```
+
+**Note**: Default locale should be set on the **TranslatableListener** initialization
+once, since it can impact your current records if it will be changed. As it
+will not store extra record in translation table by default.
+
+If you need to store translation in default locale, set:
+
+``` php
+<?php
+$translatableListener->setPersistDefaultLocaleTranslation(true); // default is false
+```
+
+This would always store translations in all locales, also keeping original record
+translated field values in default locale set.
+
+### Translation Entity
+
+In some cases if there are thousands of records or even more.. we would like to
+have a single table for translations of this Entity in order to increase the performance
+on translation loading speed. This example will show how to specify a different Entity for
+your translations by extending the mapped superclass.
+
+ArticleTranslation Entity:
+
+``` php
+<?php
+namespace Entity\Translation;
+
+use Doctrine\ORM\Mapping as ORM;
+use Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation;
+
+/**
+ * @ORM\Table(name="article_translations", indexes={
+ *      @ORM\index(name="article_translation_idx", columns={"locale", "object_class", "field", "foreign_key"})
+ * })
+ * @ORM\Entity(repositoryClass="Gedmo\Translatable\Entity\Repository\TranslationRepository")
+ */
+class ArticleTranslation extends AbstractTranslation
+{
+    /**
+     * All required columns are mapped through inherited superclass
+     */
+}
+```
+
+**Note:** We specified the repository class to be used from extension.
+It is handy for specific methods common to the Translation Entity
+
+**Note:** This Entity will be used instead of default Translation Entity
+only if we specify a class annotation @Gedmo\TranslationEntity(class="my\translation\entity"):
+
+``` php
+<?php
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Table(name="articles")
+ * @ORM\Entity
+ * @Gedmo\TranslationEntity(class="Entity\Translation\ArticleTranslation")
+ */
+class Article
+{
+    // ...
+}
+```
+
+Now all translations of Article will be stored and queried from specific table
+
+<a name="personal-translations"></a>
+
+## Personal translations
+
+Translatable has **AbstractPersonalTranslation** mapped superclass, which must
+be extended and mapped based on your **entity** which you want to translate.
+Note: translations are not automapped because of user preference based on cascades
+or other possible choices, which user can make.
+Personal translations uses foreign key constraint which is fully managed by ORM and
+allows to have a collection of related translations. User can use it anyway he likes, etc.:
+implementing array access on entity, using left join to fill collection and so on.
+ 
+Note: that [query hint](#orm-query-hint) will work on personal translations the same way.
+You can always use a left join like for standard doctrine collections.
+
+Usage example:
+
+``` php
+<?php
+namespace Entity;
+
+use Doctrine\Common\Collections\ArrayCollection;
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ * @Gedmo\TranslationEntity(class="Entity\CategoryTranslation")
+ */
+class Category
+{
+    /**
+     * @ORM\Column(type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     */
+    private $id;
+
+    /**
+     * @Gedmo\Translatable
+     * @ORM\Column(length=64)
+     */
+    private $title;
+
+    /**
+     * @Gedmo\Translatable
+     * @ORM\Column(type="text", nullable=true)
+     */
+    private $description;
+
+    /**
+     * @ORM\OneToMany(
+     *   targetEntity="CategoryTranslation",
+     *   mappedBy="object",
+     *   cascade={"persist", "remove"}
+     * )
+     */
+    private $translations;
+
+    public function __construct()
+    {
+        $this->translations = new ArrayCollection();
+    }
+
+    public function getTranslations()
+    {
+        return $this->translations;
+    }
+
+    public function addTranslation(CategoryTranslation $t)
+    {
+        if (!$this->translations->contains($t)) {
+            $this->translations[] = $t;
+            $t->setObject($this);
+        }
+    }
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setDescription($description)
+    {
+        $this->description = $description;
+    }
+
+    public function getDescription()
+    {
+        return $this->description;
+    }
+
+    public function __toString()
+    {
+        return $this->getTitle();
+    }
+}
+```
+
+Now the translation entity for the Category:
+
+``` php
+<?php
+namespace Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+use Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation;
+
+/**
+ * @ORM\Entity
+ * @ORM\Table(name="category_translations",
+ *     uniqueConstraints={@ORM\UniqueConstraint(name="lookup_unique_idx", columns={
+ *         "locale", "object_id", "field"
+ *     })}
+ * )
+ */
+class CategoryTranslation extends AbstractPersonalTranslation
+{
+    /**
+     * Convinient constructor
+     *
+     * @param string $locale
+     * @param string $field
+     * @param string $value
+     */
+    public function __construct($locale, $field, $value)
+    {
+        $this->setLocale($locale);
+        $this->setField($field);
+        $this->setContent($value);
+    }
+
+    /**
+     * @ORM\ManyToOne(targetEntity="Category", inversedBy="translations")
+     * @ORM\JoinColumn(name="object_id", referencedColumnName="id", onDelete="CASCADE")
+     */
+    protected $object;
+}
+```
+
+Some example code to persist with translations:
+
+``` php
+<?php
+// assumes default locale is "en"
+$food = new Entity\Category;
+$food->setTitle('Food');
+$food->addTranslation(new Entity\CategoryTranslation('lt', 'title', 'Maistas'));
+
+$fruits = new Entity\Category;
+$fruits->setParent($food);
+$fruits->setTitle('Fruits');
+$fruits->addTranslation(new Entity\CategoryTranslation('lt', 'title', 'Vaisiai'));
+$fruits->addTranslation(new Entity\CategoryTranslation('ru', 'title', 'rus trans'));
+
+$em->persist($food);
+$em->persist($fruits);
+$em->flush();
+```
+
+This would create translations for english and lithuanian, and for fruits, **ru** additionally.
+
+Easy like that, any suggestions on improvements are very welcome
+
+
+### Example code to use Personal Translations with (Symfony2 Sonata) i18n Forms:
+
+Suppose you have a Sonata Backend with a simple form like:
+
+``` php
+<?php
+protected function configureFormFields(FormMapper $formMapper)    {
+    $formMapper
+        ->with('General')
+        ->add('title', 'text')
+        ->end()
+    ;
+}
+```
+
+Then you can turn it into an 118n Form by providing the following changes.
+
+``` php
+<?php
+protected function configureFormFields(FormMapper $formMapper)
+{
+    $formMapper
+        ->with('General')
+            ->add('title', 'translatable_field', array(
+                'field'                => 'title',
+                'personal_translation' => 'ExampleBundle\Entity\Translation\ProductTranslation',
+                'property_path'        => 'translations',
+            ))
+        ->end()
+    ;
+}
+
+```
+
+To accomplish this you can add the following code in your bundle:
+
+https://gist.github.com/2437078
+
+<Bundle>/Form/TranslatedFieldType.php
+<Bundle>/Form/EventListener/addTranslatedFieldSubscriber.php
+<Bundle>/Resources/services.yml
+
+Then you can change to your needs:
+
+``` php
+    'field'                => 'title', //you need to provide which field you wish to translate
+    'personal_translation' => 'ExampleBundle\Entity\Translation\ProductTranslation', //the personal translation entity
+
+```
+
+
+### Translations field type using Personal Translations with Symfony2:
+
+You can use [A2lixTranslationFormBundle](https://github.com/a2lix/TranslationFormBundle) to facilitate your translations.

+ 1203 - 0
vendor/gedmo/doctrine-extensions/doc/tree.md

@@ -0,0 +1,1203 @@
+# Tree - Nestedset behavior extension for Doctrine 2
+
+**Tree** nested behavior will implement the standard Nested-Set behavior
+on your Entity. Tree supports different strategies. Currently it supports
+**nested-set**, **closure-table** and **materialized-path**. Also this behavior can be nested
+with other extensions to translate or generated slugs of your tree nodes.
+
+Features:
+
+- Materialized Path strategy for ORM and ODM (MongoDB)
+- Closure tree strategy, may be faster in some cases where ordering does not matter
+- Support for multiple roots in nested-set
+- No need for other managers, implementation is through event listener
+- Synchronization of left, right values is automatic
+- Can support concurrent flush with many objects being persisted and updated
+- Can be nested with other extensions
+- Annotation, Yaml and Xml mapping support for extensions
+
+[blog_reference]: http://gediminasm.org/article/tree-nestedset-behavior-extension-for-doctrine-2 "Tree - Nestedset or Closure extension for Doctrine 2 makes tree implementation on entities"
+[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
+
+Thanks for contributions to:
+
+- **[comfortablynumb](http://github.com/comfortablynumb) Gustavo Falco** for Closure and Materialized Path strategy
+- **[everzet](http://github.com/everzet) Kudryashov Konstantin** for TreeLevel implementation
+- **[stof](http://github.com/stof) Christophe Coevoet** for getTreeLeafs function
+
+Update **2012-06-28**
+
+- Added "buildTree" functionality support for Closure and Materialized Path strategies
+
+Update **2012-02-23**
+
+- Added a new strategy to support the "Materialized Path" tree model. It works with ODM (MongoDB) and ORM.
+
+Update **2011-05-07**
+
+- Tree is now able to act as **closure** tree, this strategy was refactored
+and now fully functional. It is much faster for file-folder trees for instance
+where you do not care about tree ordering.
+
+Update **2011-04-11**
+
+- Made in memory node synchronization, this change does not require clearing the cached nodes after any updates
+to nodes, except **recover, verify and removeFromTree** operations.
+
+Update **2011-02-08**
+
+- Refactored to support multiple roots
+- Changed the repository name, relevant to strategy used
+- New [annotations](#annotations) were added
+
+
+Update **2011-02-02**
+
+- Refactored the Tree to the ability on supporting diferent tree models
+- Changed the repository location in order to support future updates
+
+**Note:**
+
+- You can [test live][blog_test] on this blog
+- After using a NestedTreeRepository functions: **verify, recover, removeFromTree** it is recommended to clear EntityManager cache
+because nodes may have changed values in database but not in memory. Flushing dirty nodes can lead to unexpected behaviour.
+- Closure tree implementation is experimental and not fully functional, so far not documented either
+- Public [Tree repository](http://github.com/l3pp4rd/DoctrineExtensions "Tree extension on Github") is available on github
+- Last update date: **2012-02-23**
+
+**Portability:**
+
+- **Tree** is now available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
+ported to **Symfony2** by **Christophe Coevoet**, together with all other extensions
+
+This article will cover the basic installation and functionality of **Tree** behavior
+
+Content:
+    
+- [Including](#including-extension) the extension
+- Tree [annotations](#annotations)
+- Entity [example](#entity-mapping)
+- [Yaml](#yaml-mapping) mapping example
+- [Xml](#xml-mapping) mapping example
+- Basic usage [examples](#basic-examples)
+- Build [html tree](#html-tree)
+- Advanced usage [examples](#advanced-examples)
+- [Materialized Path](#materialized-path)
+- [Closure Table](#closure-table)
+- [Repository methods (all strategies)](#repository-methods)
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+<a name="entity-mapping"></a>
+
+## Tree Entity example:
+
+**Note:** that Node interface is not necessary, except in cases there
+you need to identify entity as being Tree Node. The metadata is loaded only once then
+cache is activated
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @Gedmo\Tree(type="nested")
+ * @ORM\Table(name="categories")
+ * use repository for handy tree functions
+ * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
+ */
+class Category
+{
+    /**
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(name="title", type="string", length=64)
+     */
+    private $title;
+
+    /**
+     * @Gedmo\TreeLeft
+     * @ORM\Column(name="lft", type="integer")
+     */
+    private $lft;
+    
+    /**
+     * @Gedmo\TreeLevel
+     * @ORM\Column(name="lvl", type="integer")
+     */
+    private $lvl;
+    
+    /**
+     * @Gedmo\TreeRight
+     * @ORM\Column(name="rgt", type="integer")
+     */
+    private $rgt;
+    
+    /**
+     * @Gedmo\TreeRoot
+     * @ORM\Column(name="root", type="integer", nullable=true)
+     */
+    private $root;
+    
+    /**
+     * @Gedmo\TreeParent
+     * @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
+     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
+     */
+    private $parent;
+    
+    /**
+     * @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
+     * @ORM\OrderBy({"lft" = "ASC"})
+     */
+    private $children;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+    
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+    
+    public function setParent(Category $parent = null)
+    {
+        $this->parent = $parent;    
+    }
+    
+    public function getParent()
+    {
+        return $this->parent;   
+    }
+}
+```
+
+<a name="annotations"></a>
+
+### Tree annotations:
+
+- **@Gedmo\Mapping\Annotation\Tree(type="strategy")** this **class annotation** is used to set the tree strategy by **type** parameter.
+Currently **nested**, **closure** or **materializedPath** strategies are supported. An additional "activateLocking" parameter
+is available if you use the "Materialized Path" strategy with MongoDB. It's used to activate the locking mechanism (more on that
+in the corresponding section).
+- **@Gedmo\Mapping\Annotation\TreeLeft** it will use this field to store tree **left** value
+- **@Gedmo\Mapping\Annotation\TreeRight** it will use this field to store tree **right** value
+- **@Gedmo\Mapping\Annotation\TreeParent** this will identify this column as the relation to **parent node**
+- **@Gedmo\Mapping\Annotation\TreeLevel** it will use this field to store tree**level**
+- **@Gedmo\Mapping\Annotation\TreeRoot** it will use this field to store tree**root** id value
+- **@Gedmo\Mapping\Annotation\TreePath** (Materialized Path only) it will use this field to store the "path". It has an
+optional parameter "separator" to define the separator used in the path
+- **@Gedmo\Mapping\Annotation\TreePathSource** (Materialized Path only) it will use this field as the source to
+ construct the "path"
+- **@Gedmo\Mapping\Annotation\TreeLockTime** (Materialized Path - ODM MongoDB only) this field is used if you need to
+use the locking mechanism with MongoDB. It persists the lock time if a root node is locked (more on that in the corresponding
+section).
+
+<a name="yaml-mapping"></a>
+
+## Yaml mapping example
+
+Yaml mapped Category: **/mapping/yaml/Entity.Category.dcm.yml**
+
+```
+---
+Entity\Category:
+  type: entity
+  repositoryClass: Gedmo\Tree\Entity\Repository\NestedTreeRepository
+  table: categories
+  gedmo:
+    tree:
+      type: nested
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+      length: 64
+    lft:
+      type: integer
+      gedmo:
+        - treeLeft
+    rgt:
+      type: integer
+      gedmo:
+        - treeRight
+    root:
+      type: integer
+      nullable: true
+      gedmo:
+        - treeRoot
+    lvl:
+      type: integer
+      gedmo:
+        - treeLevel
+  manyToOne:
+    parent:
+      targetEntity: Entity\Category
+      inversedBy: children
+      joinColumn:
+        name: parent_id
+        referencedColumnName: id
+        onDelete: SET NULL
+      gedmo:
+        - treeParent
+  oneToMany:
+    children:
+      targetEntity: Entity\Category
+      mappedBy: parent
+      orderBy:
+        lft: ASC
+```
+
+<a name="xml-mapping"></a>
+
+## Xml mapping example
+
+``` xml
+<?xml version="1.0" encoding="UTF-8"?>
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+
+    <entity name="Mapping\Fixture\Xml\NestedTree" table="nested_trees">
+
+        <indexes>
+            <index name="name_idx" columns="name"/>
+        </indexes>
+
+        <id name="id" type="integer" column="id">
+            <generator strategy="AUTO"/>
+        </id>
+
+        <field name="name" type="string" length="128"/>
+        <field name="left" column="lft" type="integer">
+            <gedmo:tree-left/>
+        </field>
+        <field name="right" column="rgt" type="integer">
+            <gedmo:tree-right/>
+        </field>
+        <field name="root" type="integer">
+            <gedmo:tree-root/>
+        </field>
+        <field name="level" column="lvl" type="integer">
+            <gedmo:tree-level/>
+        </field>
+
+        <many-to-one field="parent" target-entity="NestedTree">
+            <join-column name="parent_id" referenced-column-name="id" on-delete="SET_NULL"/>
+            <gedmo:tree-parent/>
+        </many-to-one>
+
+        <gedmo:tree type="nested"/>
+
+    </entity>
+
+</doctrine-mapping>
+```
+
+<a name="basic-examples"></a>
+
+## Basic usage examples:
+
+### To save some **Categories** and generate tree:
+
+``` php
+<?php
+$food = new Category();
+$food->setTitle('Food');
+
+$fruits = new Category();
+$fruits->setTitle('Fruits');
+$fruits->setParent($food);
+
+$vegetables = new Category();
+$vegetables->setTitle('Vegetables');
+$vegetables->setParent($food);
+
+$carrots = new Category();
+$carrots->setTitle('Carrots');
+$carrots->setParent($vegetables);
+
+$this->em->persist($food);
+$this->em->persist($fruits);
+$this->em->persist($vegetables);
+$this->em->persist($carrots);
+$this->em->flush();
+```
+
+The result after flush will generate the food tree:
+
+```
+/food (1-8)
+    /fruits (2-3)
+    /vegetables (4-7)
+        /carrots (5-6)
+```
+
+### Using repository functions
+
+``` php
+<?php
+$repo = $em->getRepository('Entity\Category');
+
+$food = $repo->findOneByTitle('Food');
+echo $repo->childCount($food);
+// prints: 3
+echo $repo->childCount($food, true/*direct*/);
+// prints: 2
+$children = $repo->children($food);
+// $children contains:
+// 3 nodes
+$children = $repo->children($food, false, 'title');
+// will sort the children by title
+$carrots = $repo->findOneByTitle('Carrots');
+$path = $repo->getPath($carrots);
+/* $path contains:
+   0 => Food
+   1 => Vegetables
+   2 => Carrots
+*/
+
+// verification and recovery of tree
+$repo->verify();
+// can return TRUE if tree is valid, or array of errors found on tree
+$repo->recover();
+$em->clear(); // clear cached nodes
+// if tree has errors it will try to fix all tree nodes
+
+UNSAFE: be sure to backup before runing this method when necessary, if you can use $em->remove($node);
+// which would cascade to children
+// single node removal
+$vegies = $repo->findOneByTitle('Vegitables');
+$repo->removeFromTree($vegies);
+$em->clear(); // clear cached nodes
+// it will remove this node from tree and reparent all children
+
+// reordering the tree
+$food = $repo->findOneByTitle('Food');
+$repo->reorder($food, 'title');
+// it will reorder all "Food" tree node left-right values by the title
+```
+
+### Inserting node in different positions
+
+``` php
+<?php
+$food = new Category();
+$food->setTitle('Food');
+
+$fruits = new Category();
+$fruits->setTitle('Fruits');
+
+$vegetables = new Category();
+$vegetables->setTitle('Vegetables');
+
+$carrots = new Category();
+$carrots->setTitle('Carrots');
+
+$treeRepository
+    ->persistAsFirstChild($food)
+    ->persistAsFirstChildOf($fruits, $food)
+    ->persistAsLastChildOf($vegitables, $food)
+    ->persistAsNextSiblingOf($carrots, $fruits);
+
+$em->flush();
+```
+
+For more details you can check the **NestedTreeRepository** __call function
+
+Moving up and down the nodes in same level:
+
+Tree example:
+
+```
+/Food
+    /Vegitables
+        /Onions
+        /Carrots
+        /Cabbages
+        /Potatoes
+    /Fruits
+```
+
+Now move **carrots** up by one position
+
+``` php
+<?php
+$repo = $em->getRepository('Entity\Category');
+$carrots = $repo->findOneByTitle('Carrots');
+// move it up by one position
+$repo->moveUp($carrots, 1);
+```
+
+Tree after moving the Carrots up:
+
+```
+/Food
+    /Vegitables
+        /Carrots <- moved up
+        /Onions
+        /Cabbages
+        /Potatoes
+    /Fruits
+```
+
+Moving **carrots** down to the last position
+
+``` php
+<?php
+$repo = $em->getRepository('Entity\Category');
+$carrots = $repo->findOneByTitle('Carrots');
+// move it down to the end
+$repo->moveDown($carrots, true);
+```
+
+Tree after moving the Carrots down as last child:
+
+```
+/Food
+    /Vegitables
+        /Onions
+        /Cabbages
+        /Potatoes
+        /Carrots <- moved down to the end
+    /Fruits
+```
+
+**Note:** tree repository functions: **verify, recover, removeFromTree**. 
+Will require to clear the cache of Entity Manager because left-right values will differ.
+So after that use **$em->clear();** if you will continue using the nodes after these operations.
+
+### If you need a repository for your TreeNode Entity simply extend it
+
+``` php
+<?php
+namespace Entity\Repository;
+
+use Gedmo\Tree\Entity\Repository\NestedTreeRepository;
+    
+class CategoryRepository extends NestedTreeRepository
+{
+    // your code here
+}
+
+// and then on your entity link to this repository
+
+/**
+ * @Gedmo\Tree(type="nested")
+ * @Entity(repositoryClass="Entity\Repository\CategoryRepository")
+ */
+class Category implements Node
+{
+    //...
+}
+```
+
+<a name="html-tree"></a>
+
+## Create html tree:
+
+### Retrieving whole tree as array
+
+If you would like to load whole tree as node array hierarchy use:
+
+``` php
+<?php
+$repo = $em->getRepository('Entity\Category');
+$arrayTree = $repo->childrenHierarchy();
+```
+
+All node children will stored under **__children** key for each node.
+
+### Retrieving as html tree
+
+To load a tree as **ul - li** html tree use:
+
+``` php
+<?php
+$repo = $em->getRepository('Entity\Category');
+$htmlTree = $repo->childrenHierarchy(
+    null, /* starting from root nodes */
+    false, /* load all children, not only direct */
+    array(
+        'decorate' => true,
+        'representationField' => 'slug',
+        'html' => true
+    )
+);
+```
+
+### Customize html tree output
+
+``` php
+<?php
+$repo = $em->getRepository('Entity\Category');
+$options = array(
+    'decorate' => true,
+    'rootOpen' => '<ul>',
+    'rootClose' => '</ul>',
+    'childOpen' => '<li>',
+    'childClose' => '</li>',
+    'nodeDecorator' => function($node) {
+        return '<a href="/page/'.$node['slug'].'">'.$node[$field].'</a>';
+    }
+);
+$htmlTree = $repo->childrenHierarchy(
+    null, /* starting from root nodes */
+    false, /* load all children, not only direct */
+    $options
+);
+
+```
+
+### Generate own node list
+
+``` php
+<?php
+$repo = $em->getRepository('Entity\Category');
+$query = $entityManager
+    ->createQueryBuilder()
+    ->select('node')
+    ->from('Entity\Category', 'node')
+    ->orderBy('node.root, node.lft', 'ASC')
+    ->where('node.root = 1')
+    ->getQuery()
+;
+$options = array('decorate' => true);
+$tree = $repo->buildTree($query->getArrayResult(), $options);
+```
+
+### Using routes in decorator, show only selected items, return unlimited levels items as 2 levels
+
+```
+$controller = $this;
+        $tree = $root->childrenHierarchy(null,false,array('decorate' => true,
+            'rootOpen' => function($tree) {
+                if(count($tree) && ($tree[0]['lvl'] == 0)){
+                        return '<div class="catalog-list">';
+                }
+            },
+            'rootClose' => function($child) {
+                if(count($child) && ($child[0]['lvl'] == 0)){
+                                return '</div>';
+                }
+             },
+            'childOpen' => '',
+            'childClose' => '',
+            'nodeDecorator' => function($node) use (&$controller) {
+                if($node['lvl'] == 1) {
+                    return '<h1>'.$node['title'].'</h1>';
+                }elseif($node["isVisibleOnHome"]) {
+                    return '<a href="'.$controller->generateUrl("wareTree",array("id"=>$node['id'])).'">'.$node['title'].'</a>&nbsp;';
+                }
+            }
+        ));
+```
+
+<a name="advanced-examples"></a>
+
+## Advanced examples:
+
+### Nesting Translatatable and Sluggable extensions
+
+If you want to attach **TranslationListener** also add it to EventManager after
+the **SluggableListener** and **TreeListener**. It is important because slug must be generated first
+before the creation of it`s translation.
+
+``` php
+<?php
+$evm = new \Doctrine\Common\EventManager();
+$treeListener = new \Gedmo\Tree\TreeListener();
+$evm->addEventSubscriber($treeListener);
+$sluggableListener = new \Gedmo\Sluggable\SluggableListener();
+$evm->addEventSubscriber($sluggableListener);
+$translatableListener = new \Gedmo\Translatable\TranslationListener();
+$translatableListener->setTranslatableLocale('en_us');
+$evm->addEventSubscriber($translatableListener);
+// now this event manager should be passed to entity manager constructor
+```
+
+And the Entity should look like:
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @Gedmo\Tree(type="nested")
+ * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
+ */
+class Category
+{
+    /**
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     */
+    private $id;
+
+    /**
+     * @Gedmo\Translatable
+     * @Gedmo\Sluggable
+     * @ORM\Column(name="title", type="string", length=64)
+     */
+    private $title;
+
+    /**
+     * @Gedmo\TreeLeft
+     * @ORM\Column(name="lft", type="integer")
+     */
+    private $lft;
+    
+    /**
+     * @Gedmo\TreeRight
+     * @ORM\Column(name="rgt", type="integer")
+     */
+    private $rgt;
+    
+    /**
+     * @Gedmo\TreeLevel
+     * @ORM\Column(name="lvl", type="integer")
+     */
+    private $lvl;
+    
+    /**
+     * @Gedmo\TreeParent
+     * @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
+     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
+     */
+    private $parent;
+    
+    /**
+     * @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
+     */
+    private $children;
+    
+    /**
+     * @Gedmo\Translatable
+     * @Gedmo\Slug
+     * @ORM\Column(name="slug", type="string", length=128)
+     */
+    private $slug;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+    
+    public function getSlug()
+    {
+        return $this->slug;
+    }
+    
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+    
+    public function setParent(Category $parent)
+    {
+        $this->parent = $parent;    
+    }
+    
+    public function getParent()
+    {
+        return $this->parent;   
+    }
+}
+```
+
+Yaml mapped Category: **/mapping/yaml/Entity.Category.dcm.yml**
+
+```
+---
+Entity\Category:
+  type: entity
+  repositoryClass: Gedmo\Tree\Entity\Repository\NestedTreeRepository
+  table: categories
+  gedmo:
+    tree:
+      type: nested
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    title:
+      type: string
+      length: 64
+      gedmo:
+        - translatable
+        - sluggable
+    lft:
+      type: integer
+      gedmo:
+        - treeLeft
+    rgt:
+      type: integer
+      gedmo:
+        - treeRight
+    lvl:
+      type: integer
+      gedmo:
+        - treeLevel
+    slug:
+      type: string
+      length: 128
+      gedmo:
+        - translatable
+        - slug
+  manyToOne:
+    parent:
+      targetEntity: Entity\Category
+      inversedBy: children
+      joinColumn:
+        name: parent_id
+        referencedColumnName: id
+        onDelete: SET NULL
+      gedmo:
+        - treeParent
+  oneToMany:
+    children:
+      targetEntity: Entity\Category
+      mappedBy: parent
+```
+
+**Note:** that using dql without object hydration, the nodes will not be
+translated. Because the postLoad event never will be triggered
+
+Now the generated treenode slug will be translated by Translatable behavior
+
+Easy like that, any suggestions on improvements are very welcome
+
+<a name="materialized-path"></a>
+
+## Materialized Path
+
+### Important notes before defining the schema
+
+- If you use MongoDB you should activate the locking mechanism provided to avoid inconsistencies in cases where concurrent
+modifications on the tree could occur. Look at the MongoDB example of schema definition to see how it must be configured.
+- If your **TreePathSource** field is of type "string", then the primary key will be concatenated in the form: "value-id".
+ This is to allow you to use non-unique values as the path source. For example, this could be very useful if you need to
+ use the date as the path source (maybe to create a tree of comments and order them by date).
+- **TreePath** field can only be of types: string, text
+- **TreePathSource** field can only be of types: id, integer, smallint, bigint, string, int, float (I include here all the
+variations of the field types, including the ORM and ODM for MongoDB ones).
+- **TreeLockTime** must be of type "date" (used only in MongoDB for now).
+
+### ORM Entity example (Annotations)
+
+``` php
+<?php
+
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\MaterializedPathRepository")
+ * @Gedmo\Tree(type="materializedPath")
+ */
+class Category
+{
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     */
+    private $id;
+
+    /**
+     * @Gedmo\TreePath
+     * @ORM\Column(name="path", type="string", length=3000, nullable=true)
+     */
+    private $path;
+
+    /**
+     * @Gedmo\TreePathSource
+     * @ORM\Column(name="title", type="string", length=64)
+     */
+    private $title;
+
+    /**
+     * @Gedmo\TreeParent
+     * @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
+     * @ORM\JoinColumns({
+     *   @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
+     * })
+     */
+    private $parent;
+
+    /**
+     * @Gedmo\TreeLevel
+     * @ORM\Column(name="lvl", type="integer", nullable=true)
+     */
+    private $level;
+
+    /**
+     * @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
+     */
+    private $children;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setParent(Category $parent = null)
+    {
+        $this->parent = $parent;
+    }
+
+    public function getParent()
+    {
+        return $this->parent;
+    }
+
+    public function setPath($path)
+    {
+        $this->path = $path;
+    }
+
+    public function getPath()
+    {
+        return $this->path;
+    }
+
+    public function getLevel()
+    {
+        return $this->level;
+    }
+}
+
+```
+
+### MongoDB example (Annotations)
+
+``` php
+<?php
+
+namespace Document;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ODM\MongoDB\Mapping\Annotations as MONGO;
+
+/**
+ * @MONGO\Document(repositoryClass="Gedmo\Tree\Document\MongoDB\Repository\MaterializedPathRepository")
+ * @Gedmo\Tree(type="materializedPath", activateLocking=true)
+ */
+class Category
+{
+    /**
+     * @MONGO\Id
+     */
+    private $id;
+
+    /**
+     * @MONGO\Field(type="string")
+     * @Gedmo\TreePathSource
+     */
+    private $title;
+
+    /**
+     * @MONGO\Field(type="string")
+     * @Gedmo\TreePath(separator="|")
+     */
+    private $path;
+
+    /**
+     * @Gedmo\TreeParent
+     * @MONGO\ReferenceOne(targetDocument="Category")
+     */
+    private $parent;
+
+    /**
+     * @Gedmo\TreeLevel
+     * @MONGO\Field(type="int")
+     */
+    private $level;
+
+    /**
+     * @Gedmo\TreeLockTime
+     * @MONGO\Field(type="date")
+     */
+    private $lockTime;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setParent(Category $parent = null)
+    {
+        $this->parent = $parent;
+    }
+
+    public function getParent()
+    {
+        return $this->parent;
+    }
+
+    public function getLevel()
+    {
+        return $this->level;
+    }
+
+    public function getPath()
+    {
+        return $this->path;
+    }
+
+    public function getLockTime()
+    {
+        return $this->lockTime;
+    }
+}
+
+```
+
+### Path generation
+
+When an entity is inserted, a path is generated using the value of the field configured as the TreePathSource.
+If For example:
+
+``` php
+$food = new Category();
+$food->setTitle('Food');
+
+$em->persist($food);
+$em->flush();
+
+// This would print "Food-1" assuming the id is 1.
+echo $food->getPath();
+
+$fruits = new Category();
+$fruits->setTitle('Fruits');
+$fruits->setParent($food);
+
+$em->persist($fruits);
+$em->flush();
+
+// This would print "Food-1,Fruits-2" assuming that $food id is 1,
+// $fruits id is 2 and separator = "," (the default value)
+echo $fruits->getPath();
+
+```
+
+### Locking mechanism for MongoDB
+
+Why you need a locking mechanism for MongoDB? Sadly, MongoDB lacks of full transactional support, so if two or more
+users try to modify the same tree concurrently, it could lead to an inconsistent tree. So we've implemented a simple
+locking mechanism to avoid this type of problems. It works like this: As soon as a user tries to modify a node of a tree,
+it first check if the root node is locked (or if the current lock has expired).
+
+If it is locked, then it throws an exception of type "Gedmo\Exception\TreeLockingException". If it's not locked,
+it locks the tree and proceed with the modification. After all the modifications are done, the lock is freed.
+
+If, for some reason, the lock couldn't get freed, there's a lock timeout configured with a default time of 3 seconds.
+You can change this value using the **lockingTimeout** parameter under the Tree annotation (or equivalent in XML and YML).
+You must pass a value in seconds to this parameter.
+
+
+<a name="closure-table"></a>
+
+## Closure Table
+
+To be able to use this strategy, you'll need an additional entity which represents the closures. We already provide you an abstract
+entity, so you'd only need to extend it.
+
+### Closure Entity
+
+``` php
+<?php
+
+namespace YourNamespace\Entity;
+
+use Gedmo\Tree\Entity\MappedSuperclass\AbstractClosure;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class CategoryClosure extends AbstractClosure
+{
+}
+```
+
+Next step, define your entity.
+
+### ORM Entity example (Annotations)
+
+``` php
+<?php
+
+namespace YourNamespace\Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @Gedmo\Tree(type="closure")
+ * @Gedmo\TreeClosure(class="YourNamespace\Entity\CategoryClosure")
+ * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\ClosureTreeRepository")
+ */
+class Category
+{
+    /**
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(name="title", type="string", length=64)
+     */
+    private $title;
+
+    /**
+     * This parameter is optional for the closure strategy
+     *
+     * @ORM\Column(name="level", type="integer", nullable=true)
+     * @Gedmo\TreeLevel
+     */
+    private $level;
+
+    /**
+     * @Gedmo\TreeParent
+     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
+     * @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
+     */
+    private $parent;
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setParent(Category $parent = null)
+    {
+        $this->parent = $parent;
+    }
+
+    public function getParent()
+    {
+        return $this->parent;
+    }
+
+    public function addClosure(CategoryClosure $closure)
+    {
+        $this->closures[] = $closure;
+    }
+
+    public function setLevel($level)
+    {
+        $this->level = $level;
+    }
+
+    public function getLevel()
+    {
+        return $this->level;
+    }
+}
+
+```
+
+And that's it!
+
+
+<a name="repository-methods"></a>
+
+## Repository Methods (All strategies)
+
+There are repository methods that are available for you in all the strategies:
+
+* **getRootNodes** / **getRootNodesQuery** / **getRootNodesQueryBuilder**: Returns an array with the available root nodes. Arguments:
+  - *sortByField*: An optional field to order the root nodes. Defaults to "null".
+  - *direction*: In case the first argument is used, you can pass the direction here: "asc" or "desc". Defaults to "asc".
+* **getChildren** / **getChildrenQuery** / **getChildrenQueryBuilder**: Returns an array of children nodes. Arguments:
+  - *node*: If you pass a node, the method will return its children. Defaults to "null" (this means it will return ALL nodes).
+  - *direct*: If you pass true as a value for this argument, you'll get only the direct children of the node
+  (or only the root nodes if you pass "null" to the "node" argument).
+  - *sortByField*: An optional field to sort the children. Defaults to "null".
+  - *direction*: If you use the "sortByField" argument, this allows you to set the direction: "asc" or "desc". Defaults to "asc".
+  - *includeNode*: Using "true", this argument allows you to include in the result the node you passed as the first argument. Defaults to "false".
+* **childrenHierarchy**: This useful method allows you to build an array of nodes representing the hierarchy of a tree. Arguments:
+  - *node*: If you pass a node, the method will return its children. Defaults to "null" (this means it will return ALL nodes).
+  - *direct*: If you pass true as a value for this argument, you'll get only the direct children of the node
+  - *options*: An array of options that allows you to decorate the results with HTML. Available options:
+      * decorate: boolean (false) - retrieves tree as UL->LI tree
+      * nodeDecorator: Closure (null) - uses $node as argument and returns decorated item as string
+      * rootOpen: string || Closure ('\<ul\>') - branch start, closure will be given $children as a parameter
+      * rootClose: string ('\</ul\>') - branch close
+      * childStart: string || Closure ('\<li\>') - start of node, closure will be given $node as a parameter
+      * childClose: string ('\</li\>') - close of node
+      * childSort: array || keys allowed: field: field to sort on, dir: direction. 'asc' or 'desc'
+  - *includeNode*: Using "true", this argument allows you to include in the result the node you passed as the first argument. Defaults to "false".
+* **setChildrenIndex** / **getChildrenIndex**: These methods allow you to change the default index used to hold the children when you use the **childrenHierarchy** method. Index defaults to "__children".
+
+This list is not complete yet. We're working on including more methods in the common API offered by repositories of all the strategies.
+Soon we'll be adding more helpful methods here.

+ 450 - 0
vendor/gedmo/doctrine-extensions/doc/uploadable.md

@@ -0,0 +1,450 @@
+# Uploadable behavior extension for Doctrine 2
+
+**Uploadable** behavior provides the tools to manage the persistance of files with
+Doctrine 2, including automatic handling of moving, renaming and removal of files and other features.
+
+Features:
+
+- Extension moves, removes and renames files according to configuration automatically
+- Lots of options: Allow overwrite, append a number if file exists, filename generators, post-move callbacks, etc.
+- It can be extended to work not only with uploaded files, but with files coming from any source (an URL, another
+ file in the same server, etc).
+- Validation of size and mime type
+
+Content:
+
+- [Including](#including-extension) the extension
+- Entity [example](#entity-mapping)
+- [Yaml](#yaml-mapping) mapping example
+- [Xml](#xml-mapping) mapping example
+- Usage [examples](#usage)
+- [Using](#additional-usages) the extension to handle not only uploaded files
+- [Custom](#custom-mime-type-guessers) mime type guessers
+
+<a name="including-extension"></a>
+
+## Setup and autoloading
+
+Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
+or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
+on how to setup and use the extensions in most optimized way.
+
+
+<a name="entity-mapping"></a>
+
+## Uploadable Entity example:
+
+### Uploadable annotations:
+1. **@Gedmo\Mapping\Annotation\Uploadable** this class annotation tells if a class is Uploadable. Available configuration options:
+    * **allowOverwrite** - If this option is true, it will overwrite a file if it already exists. If you set "false", an
+    exception will be thrown. Default: false
+    * **appendNumber** - If this option is true and "allowOverwrite" is false, in the case that the file already exists,
+    it will append a number to the filename. Example: if you're uploading a file named "test.txt", if the file already
+    exists and this option is true, the extension will modify the name of the uploaded file to "test-1.txt", where "1"
+    could be any number. The extension will check if the file exists until it finds a filename with a number as its postfix that is not used.
+    If you use a filename generator and this option is true, it will append a number to the filename anyway if a file with
+    the same name already exists.
+    Default value: false
+    * **path** - This option expects a string containing the path where the files represented by this entity will be moved.
+    Default: "". Path can be set in other ways: From the listener or from a method. More details later.
+    * **pathMethod** - Similar to option "path", but this time it represents the name of a method on the entity that
+    will return the path to which the files represented by this entity will be moved. This is useful in several cases.
+    For example, you can set specific paths for specific entities, or you can get the path from other sources (like a
+    framework configuration) instead of hardcoding it in the entity. Default: ""
+    * **callback** - This option allows you to set a method name. If this option is set, the method will be called after
+    the file is moved. Default value: "". As first argument, this method can receive an array with information about the uploaded file, which
+    includes the following keys:
+        1. **fileName**: The filename.
+        2. **fileExtension**: The extension of the file (including the dot). Example: .jpg
+        3. **fileWithoutExt**: The filename without the extension.
+        4. **filePath**: The file path. Example: /my/path/filename.jpg
+        5. **fileMimeType**: The mime-type of the file. Example: text/plain.
+        6. **fileSize**: Size of the file in bytes. Example: 140000.
+    * **filenameGenerator**: This option allows you to set a filename generator for the file. There are two already included
+    by the extension: **SHA1**, which generates a sha1 filename for the file, and **ALPHANUMERIC**, which "normalizes"
+    the filename, leaving only alphanumeric characters in the filename, and replacing anything else with a "-". You can
+    even create your own FileGenerator class (implementing the FileGeneratorInterface) and set this option with the
+    fully qualified class name. The other option available is "NONE" which, as you may guess, means no generation for the
+    filename will occur. Default: "NONE".
+    * **maxSize**: This option allows you to set a maximum size for the file in bytes. If file size exceeds the value
+    set in this configuration, an exception of type "UploadableMaxSizeException" will be thrown. By default, its value is set to 0, meaning
+    that no size validation will occur.
+    * **allowedTypes**: With this option you can set a comma-separated list of allowed mime types for the file. The extension
+    will use a simple mime type guesser to guess the file type, and then it will compare it to the list of allowed types.
+    If the mime type is not valid, then an exception of type "UploadableInvalidMimeTypeException" will be thrown. If you
+    set this option, you can't set the **disallowedTypes** option described next. By default, no validation of mime type
+    occurs. If you want to use a custom mime type guesser, see [this](#custom-mime-type-guessers).
+    * **disallowedTypes**: Similar to the option **allowedTypes**, but with this one you configure a "black list" of
+    mime types. If the mime type of the file is on this list, n exception of type "UploadableInvalidMimeTypeException" will be thrown. If you
+    set this option, you can't set the **allowedTypes** option described next. By default, no validation of mime type
+    occurs. If you want to use a custom mime type guesser, see [this](#custom-mime-type-guessers).
+2. **@Gedmo\Mapping\Annotation\UploadableFilePath**: This annotation is used to set which field will receive the path
+ to the file. The field MUST be of type "string" and this annotation is REQUIRED.
+3. **@Gedmo\Mapping\Annotation\UploadableFileMimeType**: This is an optional annotation used to set which field will
+ receive the mime type of the file as its value. This field MUST be of type "string".
+4. **@Gedmo\Mapping\Annotation\UploadableFileSize**: This is an optional annotation used to set which field will
+ receive the size in bytes of the file as its value. This field MUST be of type "decimal".
+
+### Notes about setting the path where the files will be moved:
+
+You have three choices to configure the path. You can set a default path on the listener, which will be used on every
+entity which doesn't have a path or pathMethod defined:
+
+``` php
+$listener->setDefaultPath('/my/path');
+```
+
+You can use the Uploadable "path" option to set the path:
+
+``` php
+/**
+ * @ORM\Entity
+ * @Gedmo\Uploadable(path="/my/path")
+ */
+class File
+{
+    //...
+}
+```
+
+Or you can use the Uploadable "pathMethod" option to set the name of the method which will return the path:
+
+``` php
+/**
+ * @ORM\Entity
+ * @Gedmo\Uploadable(pathMethod="getPath")
+ */
+class File
+{
+    public function getPath()
+    {
+        return '/my/path';
+    }
+}
+```
+
+
+### Note regarding the Uploadable interface:
+
+The Uploadable interface is not necessary, except in cases there
+you need to identify an entity as Uploadable. The metadata is loaded only once then
+you need to identify an entity as Uploadable. The metadata is loaded only once then
+cache is activated
+
+### Minimum configuration needed:
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+// If you don't set the path here, remember that you must set it on the listener!
+
+/**
+ * @ORM\Entity
+ * @Gedmo\Uploadable
+ */
+class File
+{
+    // Other fields..
+
+    /**
+     * @ORM\Column(name="path", type="string")
+     * @Gedmo\UploadableFilePath
+     */
+    private $path;
+}
+```
+
+### Example of an entity with all the configurations set:
+
+``` php
+<?php
+namespace Entity;
+
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ * @Gedmo\Uploadable(path="/my/path", callback="myCallbackMethod", filenameGenerator="SHA1", allowOverwrite=true, appendNumber=true)
+ */
+class File
+{
+    /**
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue(strategy="IDENTITY")
+     */
+    private $id;
+
+    /**
+     * @ORM\Column(name="path", type="string")
+     * @Gedmo\UploadableFilePath
+     */
+    private $path;
+
+    /**
+     * @ORM\Column(name="mime_type", type="string")
+     * @Gedmo\UploadableFileMimeType
+     */
+    private $mimeType;
+
+    /**
+     * @ORM\Column(name="size", type="decimal")
+     * @Gedmo\UploadableFileSize
+     */
+    private $size;
+
+
+    public function myCallbackMethod(array $info)
+    {
+        // Do some stuff with the file..
+    }
+
+    // Other methods..
+}
+```
+
+
+<a name="yaml-mapping"></a>
+
+## Yaml mapping example:
+
+Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
+
+```
+---
+Entity\File:
+  type: entity
+  table: files
+  gedmo:
+    uploadable:
+      allowOverwrite: true
+      appendNumber: true
+      path: '/my/path'
+      pathMethod: getPath
+      callback: callbackMethod
+      filenameGenerator: SHA1
+  id:
+    id:
+      type: integer
+      generator:
+        strategy: AUTO
+  fields:
+    path:
+      type: string
+      gedmo:
+        - uploadableFilePath
+    mimeType:
+      type: string
+      gedmo:
+        - uploadableFileMimeType
+    size:
+      type: decimal
+      gedmo:
+        - uploadableFileSize
+```
+
+<a name="xml-mapping"></a>
+
+## Xml mapping example
+
+``` xml
+<?xml version="1.0" encoding="UTF-8"?>
+
+<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
+                  xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
+
+    <entity name="Entity\File" table="files">
+
+        <id name="id" type="integer" column="id">
+            <generator strategy="AUTO"/>
+        </id>
+
+        <field name="mimeType" column="mime" type="string">
+            <gedmo:uploadable-file-mime-type />
+        </field>
+
+        <field name="size" column="size" type="decimal">
+            <gedmo:uploadable-file-size />
+        </field>
+
+        <field name="path" column="path" type="string">
+            <gedmo:uploadable-file-path />
+        </field>
+
+        <gedmo:uploadable
+            allow-overwrite="true"
+            append-number="true"
+            path="/my/path"
+            path-method="getPath"
+            callback="callbackMethod"
+            filename-generator="SHA1" />
+
+    </entity>
+
+</doctrine-mapping>
+```
+
+<a name="usage"></a>
+
+## Usage:
+
+``` php
+<?php
+// Example setting the path directly on the listener:
+
+$listener->setDefaultPath('/my/app/web/upload');
+
+if (isset($_FILES['images']) && is_array($_FILES['images']) {
+    foreach ($_FILES['images'] as $fileInfo) {
+        $file = new File();
+
+        $listener->addEntityFileInfo($file, $fileInfo);
+
+        // You can set the file info directly with a FileInfoInterface object, like this:
+        //
+        // $listener->addEntityFileInfo($file, new FileInfoArray($fileInfo));
+        //
+        // Or create your own class which implements FileInfoInterface
+        //
+        // $listener->addEntityFileInfo($file, new MyOwnFileInfo($fileInfo));
+
+
+        $em->persist($file);
+    }
+}
+
+$em->flush();
+```
+
+Easy like that, any suggestions on improvements are very welcome.
+
+<a name="additional-usages"></a>
+
+### Using the extension to handle not only uploaded files
+
+Maybe you want to handle files obtained from an URL, or even files that are already located in the same server than your app.
+This can be handled in a very simple way. First, you need to create a class that implements the FileInfoInterface
+interface. As an example:
+
+``` php
+use Gedmo\Uploadable\FileInfo\FileInfoInterface;
+
+class CustomFileInfo implements FileInfoInterface
+{
+    protected $path;
+    protected $size;
+    protected $type;
+    protected $filename;
+    protected $error = 0;
+
+    public function __construct($path)
+    {
+        $this->path = $path;
+
+        // Now, process the file and fill the rest of the properties.
+    }
+
+    // This returns the actual path of the file
+    public function getTmpName()
+    {
+        return $path;
+    }
+
+    // This returns the filename
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    // This returns the file size in bytes
+    public function getSize()
+    {
+        return $this->size;
+    }
+
+    // This returns the mime type
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    public function getError()
+    {
+        // This should return 0, as it's only used to return the codes from PHP file upload errors.
+        return $this->error;
+    }
+
+    // If this method returns true, it will produce that the extension uses "move_uploaded_file" function to move
+    // the file. If it returns false, the extension will use the "copy" function.
+    public function isUploadedFile()
+    {
+        return false;
+    }
+}
+```
+
+Or you could simply extend the FileInfoArray class and do the following:
+
+``` php
+use Gedmo\Uploadable\FileInfo\FileInfoArray;
+
+class CustomFileInfo extends FileInfoArray
+{
+    public function __construct($path)
+    {
+        // There's already a $fileInfo property, which needs to be an array with the
+        // following keys: tmp_name, name, size, type, error
+        $this->fileInfo = array(
+            'tmp_name'      => '',
+            'name'          => '',
+            'size'          => 0,
+            'type'          => '',
+            'error'         => 0
+        );
+
+        // Now process the file at $path and fill the keys with the correct values.
+        //
+        // In this example we use a $path as the first argument, but it could be an URL
+        // to the file we need to obtain, etc.
+    }
+
+    public function isUploadedFile()
+    {
+        // Remember to set this to false so we use "copy" instead of "move_uploaded_file"
+
+        return false;
+    }
+}
+```
+
+And that's it. Then, instead of getting the file info from the $_FILES array, you would do:
+
+``` php
+// We set the default path in the listener again
+$listener->setDefaultPath('/my/path');
+
+$file = new File();
+
+$listener->addEntityFileInfo($file, new CustomFileInfo('/path/to/file.txt'));
+
+$em->persist($file);
+$em->flush();
+```
+
+<a name="custom-mime-type-guessers"></a>
+
+### Custom Mime type guessers
+
+If you want to use your own mime type guesser, you need to implement the interface "Gedmo\Uploadable\MimeType\MimeTypeGuesserInterface",
+which has only one method: "guess($filePath)". Then, you can set the mime type guesser used on the listener in the following
+way:
+
+``` php
+$listener->setMimeTypeGuesser(new MyCustomMimeTypeGuesser());
+
+```

+ 219 - 0
vendor/gedmo/doctrine-extensions/example/app/Entity/Category.php

@@ -0,0 +1,219 @@
+<?php
+namespace Entity;
+
+use Doctrine\Common\Collections\ArrayCollection;
+use Gedmo\Mapping\Annotation as Gedmo;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @Gedmo\Tree(type="nested")
+ * @ORM\Table(name="ext_categories")
+ * @ORM\Entity(repositoryClass="Entity\Repository\CategoryRepository")
+ * @Gedmo\TranslationEntity(class="Entity\CategoryTranslation")
+ */
+class Category
+{
+    /**
+     * @ORM\Column(type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     */
+    private $id;
+
+    /**
+     * @Gedmo\Translatable
+     * @ORM\Column(length=64)
+     */
+    private $title;
+
+    /**
+     * @Gedmo\Translatable
+     * @ORM\Column(type="text", nullable=true)
+     */
+    private $description;
+
+    /**
+     * @Gedmo\Translatable
+     * @Gedmo\Slug(fields={"title"})
+     * @ORM\Column(length=64, unique=true)
+     */
+    private $slug;
+
+    /**
+     * @Gedmo\TreeLeft
+     * @ORM\Column(type="integer")
+     */
+    private $lft;
+
+    /**
+     * @Gedmo\TreeRight
+     * @ORM\Column(type="integer")
+     */
+    private $rgt;
+
+    /**
+     * @Gedmo\TreeParent
+     * @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
+     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
+     */
+    private $parent;
+
+    /**
+     * @Gedmo\TreeRoot
+     * @ORM\Column(type="integer", nullable=true)
+     */
+    private $root;
+
+    /**
+     * @Gedmo\TreeLevel
+     * @ORM\Column(name="lvl", type="integer")
+     */
+    private $level;
+
+    /**
+     * @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
+     */
+    private $children;
+
+    /**
+     * @Gedmo\Timestampable(on="create")
+     * @ORM\Column(type="datetime")
+     */
+    private $created;
+
+    /**
+     * @Gedmo\Timestampable(on="update")
+     * @ORM\Column(type="datetime")
+     */
+    private $updated;
+
+    /**
+     * @Gedmo\Blameable(on="create")
+     * @ORM\Column(type="string")
+     */
+    private $createdBy;
+
+    /**
+     * @Gedmo\Blameable(on="update")
+     * @ORM\Column(type="string")
+     */
+    private $updatedBy;
+
+    /**
+     * @ORM\OneToMany(
+     *   targetEntity="CategoryTranslation",
+     *   mappedBy="object",
+     *   cascade={"persist", "remove"}
+     * )
+     */
+    private $translations;
+
+    public function __construct()
+    {
+        $this->children = new ArrayCollection();
+        $this->translations = new ArrayCollection();
+    }
+
+    public function getTranslations()
+    {
+        return $this->translations;
+    }
+
+    public function addTranslation(CategoryTranslation $t)
+    {
+        if (!$this->translations->contains($t)) {
+            $this->translations[] = $t;
+            $t->setObject($this);
+        }
+    }
+
+    public function getSlug()
+    {
+        return $this->slug;
+    }
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    public function setDescription($description)
+    {
+        $this->description = $description;
+    }
+
+    public function getDescription()
+    {
+        return $this->description;
+    }
+
+	public function setParent($parent)
+    {
+        $this->parent = $parent;
+    }
+
+    public function getParent()
+    {
+        return $this->parent;
+    }
+
+    public function getRoot()
+    {
+        return $this->root;
+    }
+
+    public function getLevel()
+    {
+        return $this->level;
+    }
+
+    public function getChildren()
+    {
+        return $this->children;
+    }
+
+    public function getLeft()
+    {
+    	return $this->lft;
+    }
+
+	public function getRight()
+    {
+        return $this->rgt;
+    }
+
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    public function getUpdated()
+    {
+        return $this->updated;
+    }
+
+    public function getCreatedBy()
+    {
+        return $this->createdBy;
+    }
+
+    public function getUpdatedBy()
+    {
+        return $this->updatedBy;
+    }
+
+    public function __toString()
+    {
+        return $this->getTitle();
+    }
+}

+ 37 - 0
vendor/gedmo/doctrine-extensions/example/app/Entity/CategoryTranslation.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+use Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation;
+
+/**
+ * @ORM\Entity
+ * @ORM\Table(name="category_translations",
+ *     uniqueConstraints={@ORM\UniqueConstraint(name="lookup_unique_idx", columns={
+ *         "locale", "object_id", "field"
+ *     })}
+ * )
+ */
+class CategoryTranslation extends AbstractPersonalTranslation
+{
+    /**
+     * Convinient constructor
+     *
+     * @param string $locale
+     * @param string $field
+     * @param string $value
+     */
+    public function __construct($locale, $field, $value)
+    {
+        $this->setLocale($locale);
+        $this->setField($field);
+        $this->setContent($value);
+    }
+
+    /**
+     * @ORM\ManyToOne(targetEntity="Category", inversedBy="translations")
+     * @ORM\JoinColumn(name="object_id", referencedColumnName="id", onDelete="CASCADE")
+     */
+    protected $object;
+}

+ 10 - 0
vendor/gedmo/doctrine-extensions/example/app/Entity/Repository/CategoryRepository.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace Entity\Repository;
+
+use Gedmo\Tree\Entity\Repository\NestedTreeRepository;
+
+class CategoryRepository extends NestedTreeRepository
+{
+
+}

+ 6 - 0
vendor/gedmo/doctrine-extensions/example/bin/console

@@ -0,0 +1,6 @@
+#!/usr/bin/env php
+<?php
+
+$cli = include __DIR__.'/console.php';
+$cli->run();
+

+ 40 - 0
vendor/gedmo/doctrine-extensions/example/bin/console.php

@@ -0,0 +1,40 @@
+<?php
+
+$em = include __DIR__.'/../em.php';
+
+$cli = new Symfony\Component\Console\Application('My CLI interface', '1.0.0');
+$cli->setCatchExceptions(true);
+// commands
+$cli->addCommands(array(
+    // DBAL Commands
+    new Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(),
+    new Doctrine\DBAL\Tools\Console\Command\ImportCommand(),
+
+    // ORM Commands
+    new Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(),
+    new Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(),
+    new Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(),
+    new Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(),
+    new Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(),
+    new Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(),
+    new Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(),
+    new Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(),
+    new Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(),
+    new Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(),
+    new Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(),
+    new Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(),
+    new Doctrine\ORM\Tools\Console\Command\RunDqlCommand(),
+    new Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(),
+));
+// helpers
+$helpers = array(
+    'db' => new Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
+    'em' => new Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em),
+    'dialog' => new Symfony\Component\Console\Helper\DialogHelper(),
+);
+foreach ($helpers as $name => $helper) {
+    $cli->getHelperSet()->set($helper, $name);
+}
+
+return $cli;
+

+ 123 - 0
vendor/gedmo/doctrine-extensions/example/em.php

@@ -0,0 +1,123 @@
+<?php
+/**
+ * This entity manager configuration works with doctrine 2.1.x and 2.2.x
+ * versions. Regarding AnnotationDriver setup it most probably will be changed into
+ * xml. Because annotation driver fails to read other classes in same namespace
+ */
+// connection args, modify at will
+$connection = array(
+    'host' => 'localhost',
+    'port' => 3306,
+    'user' => 'root',
+    'password' => 'nimda',
+    'dbname' => 'test',
+    'driver' => 'pdo_mysql'
+);
+if (!file_exists(__DIR__.'/../vendor/autoload.php')) {
+    die('cannot find vendors, read README.md how to use composer');
+}
+// First of all autoloading of vendors
+$loader = require __DIR__.'/../vendor/autoload.php';
+
+// gedmo extensions
+$loader->add('Gedmo', __DIR__.'/../lib');
+
+// autoloader for Entity namespace
+$loader->add('Entity', __DIR__.'/app');
+
+// ensure standard doctrine annotations are registered
+Doctrine\Common\Annotations\AnnotationRegistry::registerFile(
+    __DIR__.'/../vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php'
+);
+
+// Second configure ORM
+// globally used cache driver, in production use APC or memcached
+$cache = new Doctrine\Common\Cache\ArrayCache;
+// standard annotation reader
+$annotationReader = new Doctrine\Common\Annotations\AnnotationReader;
+$cachedAnnotationReader = new Doctrine\Common\Annotations\CachedReader(
+    $annotationReader, // use reader
+    $cache // and a cache driver
+);
+// create a driver chain for metadata reading
+$driverChain = new Doctrine\ORM\Mapping\Driver\DriverChain();
+// load superclass metadata mapping only, into driver chain
+// also registers Gedmo annotations.NOTE: you can personalize it
+Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM(
+    $driverChain, // our metadata driver chain, to hook into
+    $cachedAnnotationReader // our cached annotation reader
+);
+
+// now we want to register our application entities,
+// for that we need another metadata driver used for Entity namespace
+$annotationDriver = new Doctrine\ORM\Mapping\Driver\AnnotationDriver(
+    $cachedAnnotationReader, // our cached annotation reader
+    array(__DIR__.'/app/Entity') // paths to look in
+);
+// NOTE: driver for application Entity can be different, Yaml, Xml or whatever
+// register annotation driver for our application Entity namespace
+$driverChain->addDriver($annotationDriver, 'Entity');
+
+// general ORM configuration
+$config = new Doctrine\ORM\Configuration;
+$config->setProxyDir(sys_get_temp_dir());
+$config->setProxyNamespace('Proxy');
+$config->setAutoGenerateProxyClasses(false); // this can be based on production config.
+// register metadata driver
+$config->setMetadataDriverImpl($driverChain);
+// use our allready initialized cache driver
+$config->setMetadataCacheImpl($cache);
+$config->setQueryCacheImpl($cache);
+
+// Third, create event manager and hook prefered extension listeners
+$evm = new Doctrine\Common\EventManager();
+// gedmo extension listeners
+
+// sluggable
+$sluggableListener = new Gedmo\Sluggable\SluggableListener;
+// you should set the used annotation reader to listener, to avoid creating new one for mapping drivers
+$sluggableListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($sluggableListener);
+
+// tree
+$treeListener = new Gedmo\Tree\TreeListener;
+$treeListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($treeListener);
+
+// loggable, not used in example
+//$loggableListener = new Gedmo\Loggable\LoggableListener;
+//$loggableListener->setAnnotationReader($cachedAnnotationReader);
+//$evm->addEventSubscriber($loggableListener);
+
+// timestampable
+$timestampableListener = new Gedmo\Timestampable\TimestampableListener;
+$timestampableListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($timestampableListener);
+
+// blameable
+
+$blameableListener = new \Gedmo\Blameable\BlameableListener();
+$blameableListener->setAnnotationReader($cachedAnnotationReader);
+$blameableListener->setUserValue('MyUsername'); // determine from your environment
+$evm->addEventSubscriber($blameableListener);
+
+
+// translatable
+$translatableListener = new Gedmo\Translatable\TranslatableListener;
+// current translation locale should be set from session or hook later into the listener
+// most important, before entity manager is flushed
+$translatableListener->setTranslatableLocale('en');
+$translatableListener->setDefaultLocale('en');
+$translatableListener->setAnnotationReader($cachedAnnotationReader);
+$evm->addEventSubscriber($translatableListener);
+
+// sortable, not used in example
+//$sortableListener = new Gedmo\Sortable\SortableListener;
+//$sortableListener->setAnnotationReader($cachedAnnotationReader);
+//$evm->addEventSubscriber($sortableListener);
+
+// mysql set names UTF-8 if required
+$evm->addEventSubscriber(new Doctrine\DBAL\Event\Listeners\MysqlSessionInit());
+// Finally, create entity manager
+return Doctrine\ORM\EntityManager::create($connection, $config, $evm);
+

+ 80 - 0
vendor/gedmo/doctrine-extensions/example/run.php

@@ -0,0 +1,80 @@
+<?php
+
+use Doctrine\ORM\Query;
+use Gedmo\Translatable\TranslatableListener;
+
+$executionStart = microtime(true);
+$memoryStart = memory_get_usage(true);
+
+$em = include 'em.php';
+
+/**
+ * initialized in em.php
+ *
+ * Gedmo\Translatable\TranslationListener
+ */
+$translatable;
+
+$repository = $em->getRepository('Entity\Category');
+$food = $repository->findOneByTitle('Food');
+if (!$food) {
+    // lets create some categories
+    $food = new Entity\Category;
+    $food->setTitle('Food');
+    $food->addTranslation(new Entity\CategoryTranslation('lt', 'title', 'Maistas'));
+
+    $fruits = new Entity\Category;
+    $fruits->setParent($food);
+    $fruits->setTitle('Fruits');
+    $fruits->addTranslation(new Entity\CategoryTranslation('lt', 'title', 'Vaisiai'));
+
+    $apple = new Entity\Category;
+    $apple->setParent($fruits);
+    $apple->setTitle('Apple');
+    $apple->addTranslation(new Entity\CategoryTranslation('lt', 'title', 'Obuolys'));
+
+    $milk = new Entity\Category;
+    $milk->setParent($food);
+    $milk->setTitle('Milk');
+    $milk->addTranslation(new Entity\CategoryTranslation('lt', 'title', 'Pienas'));
+
+    $em->persist($food);
+    $em->persist($milk);
+    $em->persist($fruits);
+    $em->persist($apple);
+    $em->flush();
+}
+
+// create query to fetch tree nodes
+$query = $em
+    ->createQueryBuilder()
+    ->select('node')
+    ->from('Entity\Category', 'node')
+    ->orderBy('node.root, node.lft', 'ASC')
+    ->getQuery()
+;
+// set hint to translate nodes
+$query->setHint(
+    Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
+    'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
+);
+$treeDecorationOptions = array(
+    'decorate' => true,
+    'rootOpen' => '',
+    'rootClose' => '',
+    'childOpen' => '',
+    'childClose' => '',
+    'nodeDecorator' => function($node) {
+        return str_repeat('-', $node['level']).$node['title'].PHP_EOL;
+    }
+);
+// build tree in english
+echo $repository->buildTree($query->getArrayResult(), $treeDecorationOptions).PHP_EOL.PHP_EOL;
+// change locale
+$query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, 'lt');
+// build tree in lithuanian
+echo $repository->buildTree($query->getArrayResult(), $treeDecorationOptions).PHP_EOL.PHP_EOL;
+
+$ms = round(microtime(true) - $executionStart, 4) * 1000;
+$mem = round((memory_get_usage(true) - $memoryStart) / 1000000, 2);
+echo "Execution took: {$ms} ms, memory consumed: {$mem} Mb";

+ 48 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Blameable.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace Gedmo\Blameable;
+
+/**
+ * This interface is not necessary but can be implemented for
+ * Entities which in some cases needs to be identified as
+ * Blameable
+ *
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Blameable
+ * @subpackage Blameable
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+interface Blameable
+{
+    // blameable expects annotations on properties
+
+    /**
+     * @gedmo:Blameable(on="create")
+     * dates which should be updated on insert only
+     */
+
+    /**
+     * @gedmo:Blameable(on="update")
+     * dates which should be updated on update and insert
+     */
+
+    /**
+     * @gedmo:Blameable(on="change", field="field", value="value")
+     * dates which should be updated on changed "property"
+     * value and become equal to given "value"
+     */
+
+    /**
+     * @gedmo:Blameable(on="change", field="field")
+     * dates which should be updated on changed "property"
+     */
+
+    /**
+     * example
+     *
+     * @gedmo:Blameable(on="create")
+     * @Column(type="date")
+     * $created
+     */
+}

+ 94 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/BlameableListener.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace Gedmo\Blameable;
+
+use Doctrine\Common\EventArgs;
+use Doctrine\Common\NotifyPropertyChanged;
+use Gedmo\Exception\InvalidArgumentException;
+use Gedmo\Mapping\MappedEventSubscriber;
+use Gedmo\Timestampable\TimestampableListener;
+use Gedmo\Blameable\Mapping\Event\BlameableAdapter;
+
+/**
+ * The Blameable listener handles the update of
+ * dates on creation and update.
+ *
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Blameable
+ * @subpackage BlameableListener
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class BlameableListener extends TimestampableListener
+{
+    private $user;
+
+    /**
+     * Get the user value to set on a blameable field
+     *
+     * @param object $meta
+     * @param string $field
+     * @return mixed
+     */
+    public function getUserValue($meta, $field)
+    {
+        if ($meta->hasAssociation($field)) {
+            if (null !== $this->user && ! is_object($this->user)) {
+                throw new InvalidArgumentException("Blame is reference, user must be an object");
+            }
+
+            return $this->user;
+        }
+
+        // ok so its not an association, then it is a string
+        if (is_object($this->user)) {
+            if (method_exists($this->user, 'getUsername')) {
+                return (string)$this->user->getUsername();
+            }
+            if (method_exists($this->user, '__toString()')) {
+                return $this->user->__toString();
+            }
+            throw new InvalidArgumentException("Field expects string, user must be a string, or object should have method getUsername or __toString");
+        }
+
+        return $this->user;
+    }
+
+    /**
+     * Set a user value to return
+     *
+     * @return mixed
+     */
+    public function setUserValue($user)
+    {
+        $this->user = $user;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getNamespace()
+    {
+        return __NAMESPACE__;
+    }
+
+    /**
+     * Updates a field
+     *
+     * @param mixed $object
+     * @param BlameableAdapter $ea
+     * @param $meta
+     * @param $field
+     */
+    protected function updateField($object, $ea, $meta, $field)
+    {
+        $property = $meta->getReflectionProperty($field);
+        $oldValue = $property->getValue($object);
+        $newValue = $this->getUserValue($meta, $field);
+        $property->setValue($object, $newValue);
+        if ($object instanceof NotifyPropertyChanged) {
+            $uow = $ea->getObjectManager()->getUnitOfWork();
+            $uow->propertyChanged($object, $field, $oldValue, $newValue);
+        }
+    }
+}

+ 86 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Driver/Annotation.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace Gedmo\Blameable\Mapping\Driver;
+
+use Gedmo\Mapping\Driver\AbstractAnnotationDriver,
+    Doctrine\Common\Annotations\AnnotationReader,
+    Gedmo\Exception\InvalidMappingException;
+
+/**
+ * This is an annotation mapping driver for Blameable
+ * behavioral extension. Used for extraction of extended
+ * metadata from Annotations specificaly for Blameable
+ * extension.
+ *
+ * @author David Buchmann <mail@davidbu.ch>
+ * @package Gedmo.Blameable.Mapping.Driver
+ * @subpackage Annotation
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class Annotation extends AbstractAnnotationDriver
+{
+    /**
+     * Annotation field is blameable
+     */
+    const BLAMEABLE = 'Gedmo\\Mapping\\Annotation\\Blameable';
+
+    /**
+     * List of types which are valid for blame
+     *
+     * @var array
+     */
+    protected $validTypes = array(
+        'string',
+        'int',
+    );
+
+    /**
+     * {@inheritDoc}
+     */
+    public function readExtendedMetadata($meta, array &$config)
+    {
+        $class = $this->getMetaReflectionClass($meta);
+        // property annotations
+        foreach ($class->getProperties() as $property) {
+            if ($meta->isMappedSuperclass && !$property->isPrivate() ||
+                $meta->isInheritedField($property->name) ||
+                isset($meta->associationMappings[$property->name]['inherited'])
+            ) {
+                continue;
+            }
+            if ($blameable = $this->reader->getPropertyAnnotation($property, self::BLAMEABLE)) {
+                $field = $property->getName();
+
+                if (!$meta->hasField($field) && !$meta->hasAssociation($field)) {
+                    throw new InvalidMappingException("Unable to find blameable [{$field}] as mapped property in entity - {$meta->name}");
+                }
+                if ($meta->hasField($field)) {
+                    if ( !$this->isValidField($meta, $field)) {
+                        throw new InvalidMappingException("Field - [{$field}] type is not valid and must be 'string' or a one-to-many relation in class - {$meta->name}");
+                    }
+                } else {
+                    // association
+                    if (! $meta->isSingleValuedAssociation($field)) {
+                        throw new InvalidMappingException("Association - [{$field}] is not valid, it must be a one-to-many relation or a string field - {$meta->name}");
+                    }
+                }
+                if (!in_array($blameable->on, array('update', 'create', 'change'))) {
+                    throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->name}");
+                }
+                if ($blameable->on == 'change') {
+                    if (!isset($blameable->field)) {
+                        throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->name}");
+                    }
+                    $field = array(
+                        'field' => $field,
+                        'trackedField' => $blameable->field,
+                        'value' => $blameable->value,
+                    );
+                }
+                // properties are unique and mapper checks that, no risk here
+                $config[$blameable->on][] = $field;
+            }
+        }
+    }
+}

+ 92 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Driver/Xml.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace Gedmo\Blameable\Mapping\Driver;
+
+use Gedmo\Mapping\Driver\Xml as BaseXml,
+    Gedmo\Exception\InvalidMappingException;
+
+/**
+ * This is a xml mapping driver for Blameable
+ * behavioral extension. Used for extraction of extended
+ * metadata from xml specificaly for Blameable
+ * extension.
+ *
+ * @author David Buchmann <mail@davidbu.ch>
+ * @package Gedmo.Blameable.Mapping.Driver
+ * @subpackage Xml
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class Xml extends BaseXml
+{
+
+    /**
+     * List of types which are valid for blame
+     *
+     * @var array
+     */
+    private $validTypes = array(
+        'string',
+        'int',
+    );
+
+    /**
+     * {@inheritDoc}
+     */
+    public function readExtendedMetadata($meta, array &$config)
+    {
+        /**
+         * @var \SimpleXmlElement $mapping
+         */
+        $mapping = $this->_getMapping($meta->name);
+
+        if (isset($mapping->field)) {
+            /**
+             * @var \SimpleXmlElement $fieldMapping
+             */
+            foreach ($mapping->field as $fieldMapping) {
+                $fieldMappingDoctrine = $fieldMapping;
+                $fieldMapping = $fieldMapping->children(self::GEDMO_NAMESPACE_URI);
+                if (isset($fieldMapping->blameable)) {
+                    /**
+                     * @var \SimpleXmlElement $data
+                     */
+                    $data = $fieldMapping->blameable;
+
+                    $field = $this->_getAttribute($fieldMappingDoctrine, 'name');
+                    if (!$this->isValidField($meta, $field)) {
+                        throw new InvalidMappingException("Field - [{$field}] type is not valid and must be 'string' or a reference in class - {$meta->name}");
+                    }
+                    if (!$this->_isAttributeSet($data, 'on') || !in_array($this->_getAttribute($data, 'on'), array('update', 'create', 'change'))) {
+                        throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->name}");
+                    }
+
+                    if ($this->_getAttribute($data, 'on') == 'change') {
+                        if (!$this->_isAttributeSet($data, 'field')) {
+                            throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->name}");
+                        }
+                        $field = array(
+                            'field' => $field,
+                            'trackedField' => $this->_getAttribute($data, 'field'),
+                            'value' => $this->_isAttributeSet($data, 'value') ? $this->_getAttribute($data, 'value') : null,
+                        );
+                    }
+                    $config[$this->_getAttribute($data, 'on')][] = $field;
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks if $field type is valid
+     *
+     * @param object $meta
+     * @param string $field
+     * @return boolean
+     */
+    protected function isValidField($meta, $field)
+    {
+        $mapping = $meta->getFieldMapping($field);
+        return $mapping && in_array($mapping['type'], $this->validTypes);
+    }
+}

+ 93 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Driver/Yaml.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace Gedmo\Blameable\Mapping\Driver;
+
+use Gedmo\Mapping\Driver\File,
+    Gedmo\Mapping\Driver,
+    Gedmo\Exception\InvalidMappingException;
+
+/**
+ * This is a yaml mapping driver for Blameable
+ * behavioral extension. Used for extraction of extended
+ * metadata from yaml specificaly for Blameable
+ * extension.
+ *
+ * @author David Buchmann <mail@davidbu.ch>
+ * @package Gedmo.Blameable.Mapping.Driver
+ * @subpackage Yaml
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class Yaml extends File implements Driver
+{
+    /**
+     * File extension
+     * @var string
+     */
+    protected $_extension = '.dcm.yml';
+
+    /**
+     * List of types which are valid for blameable
+     *
+     * @var array
+     */
+    private $validTypes = array(
+        'string',
+        'int',
+    );
+
+    /**
+     * {@inheritDoc}
+     */
+    public function readExtendedMetadata($meta, array &$config)
+    {
+        $mapping = $this->_getMapping($meta->name);
+
+        if (isset($mapping['fields'])) {
+            foreach ($mapping['fields'] as $field => $fieldMapping) {
+                if (isset($fieldMapping['gedmo']['blameable'])) {
+                    $mappingProperty = $fieldMapping['gedmo']['blameable'];
+                    if (!$this->isValidField($meta, $field)) {
+                        throw new InvalidMappingException("Field - [{$field}] type is not valid and must be 'string' or a reference in class - {$meta->name}");
+                    }
+                    if (!isset($mappingProperty['on']) || !in_array($mappingProperty['on'], array('update', 'create', 'change'))) {
+                        throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->name}");
+                    }
+
+                    if ($mappingProperty['on'] == 'change') {
+                        if (!isset($mappingProperty['field'])) {
+                            throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->name}");
+                        }
+                        $field = array(
+                            'field' => $field,
+                            'trackedField' => $mappingProperty['field'],
+                            'value' => isset($mappingProperty['value']) ? $mappingProperty['value'] : null,
+                        );
+                    }
+                    $config[$mappingProperty['on']][] = $field;
+                }
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function _loadMappingFile($file)
+    {
+        return \Symfony\Component\Yaml\Yaml::parse($file);
+    }
+
+    /**
+     * Checks if $field type is valid
+     *
+     * @param object $meta
+     * @param string $field
+     * @return boolean
+     */
+    protected function isValidField($meta, $field)
+    {
+        $mapping = $meta->getFieldMapping($field);
+        return $mapping && in_array($mapping['type'], $this->validTypes);
+    }
+}

+ 20 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Event/Adapter/ODM.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Gedmo\Blameable\Mapping\Event\Adapter;
+
+use Gedmo\Mapping\Event\Adapter\ODM as BaseAdapterODM;
+use Gedmo\Blameable\Mapping\Event\BlameableAdapter;
+
+/**
+ * Doctrine event adapter for ODM adapted
+ * for Blameable behavior.
+ *
+ * @author David Buchmann <mail@davidbu.ch>
+ * @package Gedmo\Blameable\Mapping\Event\Adapter
+ * @subpackage ODM
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+final class ODM extends BaseAdapterODM implements BlameableAdapter
+{
+}

+ 21 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Event/Adapter/ORM.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace Gedmo\Blameable\Mapping\Event\Adapter;
+
+use Gedmo\Mapping\Event\Adapter\ORM as BaseAdapterORM;
+use Gedmo\Blameable\Mapping\Event\BlameableAdapter;
+use Gedmo\Exception\InvalidArgumentException;
+
+/**
+ * Doctrine event adapter for ORM adapted
+ * for Blameable behavior.
+ *
+ * @author David Buchmann <mail@davidbu.ch>
+ * @package Gedmo\Blameable\Mapping\Event\Adapter
+ * @subpackage ORM
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+final class ORM extends BaseAdapterORM implements BlameableAdapter
+{
+}

+ 19 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Mapping/Event/BlameableAdapter.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Gedmo\Blameable\Mapping\Event;
+
+use Gedmo\Mapping\Event\AdapterInterface;
+
+/**
+ * Doctrine event adapter interface
+ * for Blameable behavior.
+ *
+ * @author David Buchmann <mail@davidbu.ch>
+ * @package Gedmo\Blameable\Mapping\Event
+ * @subpackage BlameableAdapter
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+interface BlameableAdapter extends AdapterInterface
+{
+}

+ 73 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Traits/BlameableDocument.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace Gedmo\Blameable\Traits;
+
+/**
+ * Blameable Trait, usable with PHP >= 5.4
+ *
+ * @author David Buchmann <mail@davidbu.ch>
+ * @package Gedmo.Blameable.Traits
+ * @subpackage BlameableDocument
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+trait BlameableDocument
+{
+    /**
+     * @Gedmo\Blameable(on="create")
+     * @ODM\String
+     */
+    private $createdBy;
+
+    /**
+     * @Gedmo\Blameable(on="update")
+     * @ODM\String
+     */
+    private $updatedBy;
+
+    /**
+     * Sets createdBy.
+     *
+     * @param  string $createdBy
+     * @return $this
+     */
+    public function setCreatedBy($createdBy)
+    {
+        $this->createdBy = $createdBy;
+
+        return $this;
+    }
+
+    /**
+     * Returns createdBy.
+     *
+     * @return string
+     */
+    public function getCreatedBy()
+    {
+        return $this->createdBy;
+    }
+
+    /**
+     * Sets updatedBy.
+     *
+     * @param  string $updatedBy
+     * @return $this
+     */
+    public function setUpdatedBy($updatedBy)
+    {
+        $this->updatedBy = $updatedBy;
+
+        return $this;
+    }
+
+    /**
+     * Returns updatedBy.
+     *
+     * @return string
+     */
+    public function getUpdatedBy()
+    {
+        return $this->updatedBy;
+    }
+}

+ 73 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Blameable/Traits/BlameableEntity.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace Gedmo\Blameable\Traits;
+
+/**
+ * Blameable Trait, usable with PHP >= 5.4
+ *
+ * @author David Buchmann <mail@davidbu.ch>
+ * @package Gedmo.Blameable.Traits
+ * @subpackage BlameableEntity
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+trait BlameableEntity
+{
+    /**
+     * @Gedmo\Blameable(on="create")
+     * @ORM\Column(type="string")
+     */
+    private $createdBy;
+
+    /**
+     * @Gedmo\Blameable(on="update")
+     * @ORM\Column(type="string")
+     */
+    private $updatedBy;
+
+    /**
+     * Sets createdBy.
+     *
+     * @param  string $createdBy
+     * @return $this
+     */
+    public function setCreatedBy($createdBy)
+    {
+        $this->createdBy = $createdBy;
+
+        return $this;
+    }
+
+    /**
+     * Returns createdBy.
+     *
+     * @return string
+     */
+    public function getCreatedBy()
+    {
+        return $this->createdBy;
+    }
+
+    /**
+     * Sets updatedBy.
+     *
+     * @param  string $updatedBy
+     * @return $this
+     */
+    public function setUpdatedBy($updatedBy)
+    {
+        $this->updatedBy = $updatedBy;
+
+        return $this;
+    }
+
+    /**
+     * Returns updatedBy.
+     *
+     * @return string
+     */
+    public function getUpdatedBy()
+    {
+        return $this->updatedBy;
+    }
+}

+ 130 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/DoctrineExtensions.php

@@ -0,0 +1,130 @@
+<?php
+
+namespace Gedmo;
+
+use Doctrine\Common\Annotations\AnnotationRegistry;
+use Doctrine\ORM\Mapping\Driver as DriverORM;
+use Doctrine\ODM\MongoDB\Mapping\Driver as DriverMongodbODM;
+use Doctrine\Common\Annotations\Reader;
+use Doctrine\Common\Annotations\CachedReader;
+use Doctrine\Common\Annotations\AnnotationReader;
+use Doctrine\Common\Cache\ArrayCache;
+
+/**
+ * Version class allows to checking the dependencies required
+ * and the current version of doctrine extensions
+ *
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @subpackage DoctrineExtensions
+ * @package Gedmo
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+final class DoctrineExtensions
+{
+    /**
+     * Current version of extensions
+     */
+    const VERSION = '2.3.0-DEV';
+
+    /**
+     * Flag if annotations were included into registry
+     * allready
+     *
+     * @var boolean
+     */
+    private static $autoloaded = false;
+
+    /**
+     * Hooks all extensions metadata mapping drivers
+     * into given $driverChain of drivers for ORM
+     *
+     * @param \Doctrine\ORM\Mapping\Driver\DriverChain $driverChain
+     * @param \Doctrine\Common\Annotations\Reader $reader
+     */
+    public static function registerMappingIntoDriverChainORM(DriverORM\DriverChain $driverChain, Reader $reader = null)
+    {
+        self::registerAnnotations();
+        if (!$reader) {
+            $reader = new CachedReader(new AnnotationReader, new ArrayCache);
+        }
+        $annotationDriver = new DriverORM\AnnotationDriver($reader, array(
+            __DIR__.'/Translatable/Entity',
+            __DIR__.'/Loggable/Entity',
+            __DIR__.'/Tree/Entity',
+        ));
+        $driverChain->addDriver($annotationDriver, 'Gedmo');
+    }
+
+    /**
+     * Hooks only superclass metadata mapping drivers
+     * into given $driverChain of drivers for ORM
+     *
+     * @param \Doctrine\ORM\Mapping\Driver\DriverChain $chain
+     * @param \Doctrine\Common\Annotations\Reader $reader
+     */
+    public static function registerAbstractMappingIntoDriverChainORM(DriverORM\DriverChain $driverChain, Reader $reader = null)
+    {
+        self::registerAnnotations();
+        if (!$reader) {
+            $reader = new CachedReader(new AnnotationReader, new ArrayCache);
+        }
+        $annotationDriver = new DriverORM\AnnotationDriver($reader, array(
+            __DIR__.'/Translatable/Entity/MappedSuperclass',
+            __DIR__.'/Loggable/Entity/MappedSuperclass',
+            __DIR__.'/Tree/Entity/MappedSuperclass',
+        ));
+        $driverChain->addDriver($annotationDriver, 'Gedmo');
+    }
+
+    /**
+     * Hooks all extensions metadata mapping drivers
+     * into given $driverChain of drivers for ODM MongoDB
+     *
+     * @param \Doctrine\ODM\MongoDB\Mapping\Driver\DriverChain $driverChain
+     * @param \Doctrine\Common\Annotations\Reader $reader
+     */
+    public static function registerMappingIntoDriverChainMongodbODM(DriverMongodbODM\DriverChain $driverChain, Reader $reader = null)
+    {
+        self::registerAnnotations();
+        if (!$reader) {
+            $reader = new CachedReader(new AnnotationReader, new ArrayCache);
+        }
+        $annotationDriver = new DriverMongodbODM\AnnotationDriver($reader, array(
+            __DIR__.'/Translatable/Document',
+            __DIR__.'/Loggable/Document',
+        ));
+        $driverChain->addDriver($annotationDriver, 'Gedmo');
+    }
+
+    /**
+     * Hooks only superclass metadata mapping drivers
+     * into given $driverChain of drivers for ODM MongoDB
+     *
+     * @param \Doctrine\ODM\MongoDB\Mapping\Driver\DriverChain $driverChain
+     * @param \Doctrine\Common\Annotations\Reader $reader
+     */
+    public static function registerAbstractMappingIntoDriverChainMongodbODM(DriverMongodbODM\DriverChain $driverChain, Reader $reader = null)
+    {
+        self::registerAnnotations();
+        if (!$reader) {
+            $reader = new CachedReader(new AnnotationReader, new ArrayCache);
+        }
+        $annotationDriver = new DriverMongodbODM\AnnotationDriver($reader, array(
+            __DIR__.'/Translatable/Document/MappedSuperclass',
+            __DIR__.'/Loggable/Document/MappedSuperclass',
+        ));
+        $driverChain->addDriver($annotationDriver, 'Gedmo');
+    }
+
+    /**
+     * Includes all extension annotations once
+     */
+    public static function registerAnnotations()
+    {
+        if (!self::$autoloaded) {
+            AnnotationRegistry::registerFile(__DIR__.'/Mapping/Annotation/All.php');
+            self::$autoloaded = true;
+        }
+    }
+}

+ 24 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace Gedmo;
+
+/**
+ * Common package exception interface to allow
+ * users of caching only this package specific
+ * exceptions thrown
+ * 
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo
+ * @subpackage Exception
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+interface Exception
+{
+    /**
+     * Following best practices for PHP5.3 package exceptions.
+     * All exceptions thrown in this package will have to implement this interface
+     * 
+     * @link http://wiki.php.net/pear/rfc/pear2_exception_policy
+     */
+}

+ 19 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/BadMethodCallException.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * BadMethodCallException
+ *
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage BadMethodCallException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class BadMethodCallException
+    extends \BadMethodCallException
+    implements Exception
+{}

+ 20 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/FeatureNotImplementedException.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * FeatureNotImplementedException
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage FeatureNotImplementedException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class FeatureNotImplementedException
+    extends \RuntimeException
+    implements Exception
+{}

+ 19 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/InvalidArgumentException.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * InvalidArgumentException
+ * 
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage InvalidArgumentException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class InvalidArgumentException 
+    extends \InvalidArgumentException
+    implements Exception
+{}

+ 22 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/InvalidMappingException.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * InvalidMappingException
+ * 
+ * Triggered when mapping user argument is not
+ * valid or incomplete.
+ * 
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage InvalidMappingException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class InvalidMappingException 
+    extends InvalidArgumentException
+    implements Exception
+{}

+ 19 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/RuntimeException.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * RuntimeException
+ * 
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage RuntimeException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class RuntimeException 
+    extends \RuntimeException
+    implements Exception
+{}

+ 18 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/TreeLockingException.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * TreeLockingException
+ * 
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage TreeLockingException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class TreeLockingException extends RuntimeException
+{}

+ 19 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UnexpectedValueException.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * UnexpectedValueException
+ * 
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage UnexpectedValueException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class UnexpectedValueException 
+    extends \UnexpectedValueException
+    implements Exception
+{}

+ 19 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UnsupportedObjectManagerException.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * UnsupportedObjectManager
+ *
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage UnsupportedObjectManager
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class UnsupportedObjectManager
+    extends InvalidArgumentException
+    implements Exception
+{}

+ 20 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UploadableCantWriteException.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * UploadableCantWriteException
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage UploadableCantWriteException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class UploadableCantWriteException
+    extends UploadableException
+    implements Exception
+{}

+ 20 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UploadableCouldntGuessMimeTypeException.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * UploadableCouldntGuessMimeTypeException
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage UploadableCouldntGuessMimeTypeException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class UploadableCouldntGuessMimeTypeException
+    extends UploadableException
+    implements Exception
+{}

+ 20 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UploadableDirectoryNotFoundException.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * UploadableDirectoryNotFoundException
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage UploadableDirectoryNotFoundException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class UploadableDirectoryNotFoundException
+    extends UploadableException
+    implements Exception
+{}

+ 20 - 0
vendor/gedmo/doctrine-extensions/lib/Gedmo/Exception/UploadableException.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Gedmo\Exception;
+
+use Gedmo\Exception;
+
+/**
+ * UploadableException
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Exception
+ * @subpackage UploadableException
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class UploadableException
+    extends RuntimeException
+    implements Exception
+{}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor