Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

DCOM-93 - Add ReflectionService and RuntimeReflectionService, change Cla... #89

Merged
merged 4 commits into from

5 participants

@beberlei
Owner

...ssMetadata to use it and ClassMetadataFactory to delegate reflection init/wakup to metadata. This way we can remove the ClassMetadata + ClassMetadataInfo double madness in all the managers.

beberlei added some commits
@beberlei beberlei DCOM-93 - Add ReflectionService and RuntimeReflectionService, change …
…ClassMetadata to use it and ClassMetadataFactory to delegate reflection init/wakup to metadata. This way we can remove the ClassMetadata + ClassMetadataInfo double madness in all the managers.
80cd74e
@beberlei beberlei DCOM-93 - Fix typo 6150024
@guilhermeblanco

Util is not a good namespace to place such an important Mapping feature.
I'd rather create a subnamespace inside of Mapping for that (Reflection is my suggestion).

Owner

This feature has nothing to do with mapping Its just a simple abstraction/factory for the reflection stuff.

@guilhermeblanco

I didn't like the *Service here. The purpose of this class contract is not to expose a Service, but rather a Implementor.
My naming suggestion for this interface is "Implementor".

Owner

by that reason every reason would be named "implementor". I don't like that name, it conveys no further meaning.

@guilhermeblanco

Following the same idea of the other class, this class would be called:

Doctrine\Common\Mapping\Reflection\RuntimeReflectionImplementor

Collaborator

Do you plan to provide a cache based reflection service? Otherwise a class with some static methods should be enough, no?

@beberlei beberlei merged commit 44ca64d into from
@suxxes

Why is "getClass" in "StaticReflectionService", while stating it should return ReflectionClass|null, returns always null, which leads to generate:entities in Symfony2 not working? Shouldn't it be something like that instead (which is working)?

return $class ? new \ReflectionClass($class) : null;
@stof
Collaborator

because this implementation is meant to be used in the EntityGenerator, when the class does not exist yet. So it cannot return a Reflection in such place (you would have an exception)

@suxxes

So this seems to be a temporary Symfony2 issue.

@stof
Collaborator

@suxxes btw, which version of Symfony are you using ? 2.0.x or master ?

@suxxes

@stof in this case it's an s-s edition, which is the master for Symfony2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 28, 2011
  1. @beberlei

    DCOM-93 - Add ReflectionService and RuntimeReflectionService, change …

    beberlei authored
    …ClassMetadata to use it and ClassMetadataFactory to delegate reflection init/wakup to metadata. This way we can remove the ClassMetadata + ClassMetadataInfo double madness in all the managers.
  2. @beberlei

    DCOM-93 - Fix typo

    beberlei authored
Commits on Dec 29, 2011
  1. @beberlei
  2. @beberlei
This page is out of date. Refresh to see the latest.
View
39 lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php
@@ -19,6 +19,8 @@
namespace Doctrine\Common\Persistence\Mapping;
+use Doctrine\Common\Cache\Cache;
+
/**
* The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
* metadata mapping informations of a class which describes how a class should be mapped
@@ -57,11 +59,16 @@
protected $initialized = false;
/**
+ * @var ReflectionService
+ */
+ private $reflectionService;
+
+ /**
* Sets the cache driver used by the factory to cache ClassMetadata instances.
*
* @param Doctrine\Common\Cache\Cache $cacheDriver
*/
- public function setCacheDriver($cacheDriver)
+ public function setCacheDriver(Cache $cacheDriver = null)
{
$this->cacheDriver = $cacheDriver;
}
@@ -158,6 +165,7 @@ public function getMetadataFor($className)
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch($realClassName . $this->cacheSalt)) !== false) {
$this->loadedMetadata[$realClassName] = $cached;
+ $cached->wakeupReflection($this->getReflectionService());
} else {
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
$this->cacheDriver->save(
@@ -212,7 +220,7 @@ protected function getParentClasses($name)
{
// Collect parent classes, ignoring transient (not-mapped) classes.
$parentClasses = array();
- foreach (array_reverse(class_parents($name)) as $parentClass) {
+ foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) {
if ( ! $this->getDriver()->isTransient($parentClass)) {
$parentClasses[] = $parentClass;
}
@@ -242,6 +250,7 @@ protected function loadMetadata($name)
$parent = null;
$rootEntityFound = false;
$visited = array();
+ $reflService = $this->getReflectionService();
foreach ($parentClasses as $className) {
if (isset($this->loadedMetadata[$className])) {
$parent = $this->loadedMetadata[$className];
@@ -265,6 +274,9 @@ protected function loadMetadata($name)
array_unshift($visited, $className);
}
+ $class->initializeReflection($reflService);
+ $class->wakeupReflection($reflService);
+
$loaded[] = $className;
}
@@ -303,4 +315,27 @@ public function isTransient($class)
return $this->getDriver()->isTransient($class);
}
+
+ /**
+ * Set reflectionService.
+ *
+ * @param ReflectionService $reflectionService
+ */
+ public function setReflectionService(ReflectionService $reflectionService)
+ {
+ $this->reflectionService = $reflectionService;
+ }
+
+ /**
+ * Get the reflection service associated with this metadata factory.
+ *
+ * @return ReflectionService
+ */
+ public function getReflectionService()
+ {
+ if ($this->reflectionService === null) {
+ $this->reflectionService = new RuntimeReflectionService();
+ }
+ return $this->reflectionService;
+ }
}
View
23 lib/Doctrine/Common/Persistence/Mapping/ClassMetadata.php
@@ -162,4 +162,27 @@ function getAssociationMappedByTargetField($assocName);
* @return array
*/
function getIdentifierValues($object);
+
+ /**
+ * Initialize Reflection services
+ *
+ * This method is called from a metadata factory after an uncached
+ * initialization. Data set in this method should be serialized and
+ * reconstituted on wakeup.
+ *
+ * @param ReflectionService $reflService
+ * @return void
+ */
+ function initializeReflection(ReflectionService $reflService);
+
+ /**
+ * Wakeup Reflection
+ *
+ * Method is called when the metadata instance is reconstituted from the
+ * cache and also after initialization.
+ *
+ * @param ReflectionService $reflService
+ * @return void
+ */
+ function wakeupReflection(ReflectionService $reflService);
}
View
80 lib/Doctrine/Common/Persistence/Mapping/ReflectionService.php
@@ -0,0 +1,80 @@
+<?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\Common\Persistence\Mapping;
+
+/**
+ * Very simple reflection service abstraction.
+ *
+ * This is required inside metadata layers that may require either
+ * static or runtime reflection.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
+interface ReflectionService
+{
+ /**
+ * Return an array of the parent classes (not interfaces) for the given class.
+ *
+ * @param string $class
+ * @return array
+ */
+ function getParentClasses($class);
+
+ /**
+ * Return the shortname of a class.
+ *
+ * @param string $class
+ * @return string
+ */
+ function getClassShortName($class);
+
+ /**
+ * @param string $class
+ * @return string
+ */
+ function getClassNamespace($class);
+
+ /**
+ * Return a reflection class instance or null
+ *
+ * @param string $class
+ * @return ReflectionClass|null
+ */
+ function getClass($class);
+
+ /**
+ * Return an accessible property (setAccessible(true)) or null.
+ *
+ * @param string $class
+ * @param string $property
+ * @return ReflectionProperty|null
+ */
+ function getAccessibleProperty($class, $property);
+
+ /**
+ * Check if the class have a public method with the given name.
+ *
+ * @param mixed $class
+ * @param mixed $method
+ * @return bool
+ */
+ function hasPublicMethod($class, $method);
+}
+
View
102 lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php
@@ -0,0 +1,102 @@
+<?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\Common\Persistence\Mapping;
+
+use ReflectionClass;
+use ReflectionProperty;
+
+/**
+ * PHP Runtime Reflection Service
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
+class RuntimeReflectionService implements ReflectionService
+{
+ /**
+ * Return an array of the parent classes (not interfaces) for the given class.
+ *
+ * @param string $class
+ * @return array
+ */
+ public function getParentClasses($class)
+ {
+ return class_parents($class);
+ }
+
+ /**
+ * Return the shortname of a class.
+ *
+ * @param string $class
+ * @return string
+ */
+ public function getClassShortName($class)
+ {
+ $r = new ReflectionClass($class);
+ return $r->getShortName();
+ }
+
+ /**
+ * @param string $class
+ * @return string
+ */
+ public function getClassNamespace($class)
+ {
+ $r = new ReflectionClass($class);
+ return $r->getNamespaceName();
+ }
+
+ /**
+ * Return a reflection class instance or null
+ *
+ * @param string $class
+ * @return ReflectionClass|null
+ */
+ public function getClass($class)
+ {
+ return new ReflectionClass($class);
+ }
+
+ /**
+ * Return an accessible property (setAccessible(true)) or null.
+ *
+ * @param string $class
+ * @param string $property
+ * @return ReflectionProperty|null
+ */
+ public function getAccessibleProperty($class, $property)
+ {
+ $property = new ReflectionProperty($class, $property);
+ $property->setAccessible(true);
+ return $property;
+ }
+
+ /**
+ * Check if the class have a public method with the given name.
+ *
+ * @param mixed $class
+ * @param mixed $method
+ * @return bool
+ */
+ public function hasPublicMethod($class, $method)
+ {
+ return method_exists($class, $method) && is_callable(array($class, $method));
+ }
+}
+
View
70 tests/Doctrine/Tests/Common/Persistence/Mapping/RuntimeReflectionServiceTest.php
@@ -0,0 +1,70 @@
+<?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\Persistence\Mapping;
+
+use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
+
+/**
+ * @group DCOM-93
+ */
+class RuntimeReflectionServiceTest extends \PHPUnit_Framework_TestCase
+{
+ private $reflectionService;
+
+ public function setUp()
+ {
+ $this->reflectionService = new RuntimeReflectionService();
+ }
+
+ public function testShortname()
+ {
+ $this->assertEquals("RuntimeReflectionServiceTest", $this->reflectionService->getClassShortName(__CLASS__));
+ }
+
+ public function testClassNamespaceName()
+ {
+ $this->assertEquals("Doctrine\Tests\Common\Persistence\Mapping", $this->reflectionService->getClassNamespace(__CLASS__));
+ }
+
+ public function testGetParentClasses()
+ {
+ $classes = $this->reflectionService->getParentClasses(__CLASS__);
+ $this->assertTrue(count($classes) >= 1, "The test class ".__CLASS__." should have at least one parent.");
+ }
+
+ public function testGetReflectionClass()
+ {
+ $class = $this->reflectionService->getClass(__CLASS__);
+ $this->assertInstanceOf("ReflectionClass", $class);
+ }
+
+ public function testGetMethods()
+ {
+ $this->assertTrue($this->reflectionService->hasPublicMethod(__CLASS__, "testGetMethods"));
+ $this->assertFalse($this->reflectionService->hasPublicMethod(__CLASS__, "testGetMethods2"));
+ }
+
+ public function testGetAccessibleProperty()
+ {
+ $reflProp = $this->reflectionService->getAccessibleProperty(__CLASS__, "reflectionService");
+ $this->assertInstanceOf("ReflectionProperty", $reflProp);
+ }
+}
+
View
11 tests/Doctrine/Tests/Common/Persistence/PersistentObjectTest.php
@@ -4,6 +4,7 @@
use Doctrine\Common\Persistence\PersistentObject;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
+use Doctrine\Common\Persistence\Mapping\ReflectionService;
/**
* @group DDC-1448
@@ -233,4 +234,14 @@ public function getIdentifierFieldNames()
{
}
+
+ public function initializeReflection(ReflectionService $reflService)
+ {
+
+ }
+
+ public function wakeupReflection(ReflectionService $reflService)
+ {
+
+ }
}
Something went wrong with that request. Please try again.