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

Benjamin Eberlei Fedor Christophe Coevoet Johannes Guilherme Blanco
Benjamin Eberlei
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
Benjamin Eberlei 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
Benjamin Eberlei beberlei DCOM-93 - Fix typo 6150024
Guilherme Blanco

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.

Guilherme Blanco

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.

Guilherme Blanco

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?

Benjamin Eberlei beberlei merged commit 44ca64d into from
Fedor

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;
Christophe Coevoet
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)

Fedor

So this seems to be a temporary Symfony2 issue.

Christophe Coevoet
Collaborator

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

Fedor

@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. Benjamin Eberlei

    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. Benjamin Eberlei

    DCOM-93 - Fix typo

    beberlei authored
Commits on Dec 29, 2011
  1. Benjamin Eberlei
  2. Benjamin Eberlei
This page is out of date. Refresh to see the latest.
39 lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php
View
@@ -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;
+ }
}
23 lib/Doctrine/Common/Persistence/Mapping/ClassMetadata.php
View
@@ -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);
}
80 lib/Doctrine/Common/Persistence/Mapping/ReflectionService.php
View
@@ -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);
+}
+
102 lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php
View
@@ -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));
+ }
+}
+
70 tests/Doctrine/Tests/Common/Persistence/Mapping/RuntimeReflectionServiceTest.php
View
@@ -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);
+ }
+}
+
11 tests/Doctrine/Tests/Common/Persistence/PersistentObjectTest.php
View
@@ -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.