Skip to content

Commit

Permalink
Merge branch 'fix/#761-#762-support-nullable-identifier-hint-in-proxi…
Browse files Browse the repository at this point in the history
…es-2.7' into 2.7

Backport #761
Backport #762
Backport #763
  • Loading branch information
Ocramius committed Jan 13, 2017
2 parents 5954c29 + 3a3d246 commit 9302970
Show file tree
Hide file tree
Showing 5 changed files with 348 additions and 202 deletions.
2 changes: 1 addition & 1 deletion lib/Doctrine/Common/Proxy/ProxyGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ 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+%s\s*\(\)\s*)\s*(?::\s*\\\\?[a-z_\x7f-\xff][\w\x7f-\xff]*(?:\\\\[a-z_\x7f-\xff][\w\x7f-\xff]*)*\s*)?{\s*return\s*\$this->%s;\s*})i';
const PATTERN_MATCH_ID_METHOD = '((public\s+)?(function\s+%s\s*\(\)\s*)\s*(?::\s*\??\s*\\\\?[a-z_\x7f-\xff][\w\x7f-\xff]*(?:\\\\[a-z_\x7f-\xff][\w\x7f-\xff]*)*\s*)?{\s*return\s*\$this->%s;\s*})i';

/**
* The namespace that contains all proxy classes.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?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;
use stdClass as A;

/**
* Test asset representing a lazy loadable object
*
* @author Marco Pivetta <[email protected]>
* @since 2.4
*/
class LazyLoadableObjectWithNullableTypehints
{

/** @var \stdClass */
private $identifierFieldReturnClassOneLetterNullable;

/** @var \stdClass */
private $identifierFieldReturnClassOneLetterNullableWithSpace;

public function getIdentifierFieldReturnClassOneLetterNullable(): ?A
{
return $this->identifierFieldReturnClassOneLetterNullable;
}

public function getIdentifierFieldReturnClassOneLetterNullableWithSpace(): ? A
{
return $this->identifierFieldReturnClassOneLetterNullableWithSpace;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?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 <[email protected]>
* @since 2.4
*/
class LazyLoadableObjectWithNullableTypehintsClassMetadata implements ClassMetadata
{
/**
* @var ReflectionClass
*/
protected $reflectionClass;

/**
* @var array
*/
protected $identifier = [
'identifierFieldReturnClassOneLetterNullable' => true,
'identifierFieldReturnClassOneLetterNullableWithSpace' => true,
];

/**
* @var array
*/
protected $fields = [
'identifierFieldReturnClassOneLetterNullable' => true,
'identifierFieldReturnClassOneLetterNullableWithSpace' => 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__ . '\LazyLoadableObjectWithNullableTypehints');
}

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 false;
}

/**
* {@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 [];
}

/**
* {@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');
}
}
112 changes: 112 additions & 0 deletions tests/Doctrine/Tests/Common/Proxy/ProxyLogicIdentifierGetterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?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\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Proxy\ProxyGenerator;
use PHPUnit_Framework_TestCase;
use stdClass;

/**
* Test that identifier getter does not cause lazy loading.
* These tests make assumptions about the structure of LazyLoadableObjectWithTypehints
*
* @author Marco Pivetta <[email protected]>
* @author Jan Langer <[email protected]>
*/
class ProxyLogicIdentifierGetterTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider methodsForWhichLazyLoadingShouldBeDisabled
*
* @param ClassMetadata $metadata
* @param string $fieldName
* @param mixed $expectedReturnedValue
*/
public function testNoLazyLoadingForIdentifier(ClassMetadata $metadata, $fieldName, $expectedReturnedValue)
{
$className = $metadata->getName();
$proxyClassName = 'Doctrine\Tests\Common\ProxyProxy\__CG__\\' . $className;
$proxyGenerator = new ProxyGenerator(__DIR__ . '/generated', __NAMESPACE__ . 'Proxy', true);
$proxyFileName = $proxyGenerator->getProxyFileName($className);

if (! class_exists($proxyClassName, false)) {
$proxyGenerator->generateProxyClass($metadata, $proxyFileName);

/** @noinspection PhpIncludeInspection */
require_once $proxyFileName;
}

$proxy = new $proxyClassName(
function () {
self::fail('Initialization is never supposed to happen');
},
function () {
self::fail('Initialization is never supposed to happen');
}
);

$reflection = $metadata->getReflectionClass()->getProperty($fieldName);

$reflection->setAccessible(true);
$reflection->setValue($proxy, $expectedReturnedValue);

$this->assertSame($expectedReturnedValue, $proxy->{'get' . $fieldName}());
}

/**
* @return array
*/
public function methodsForWhichLazyLoadingShouldBeDisabled()
{
$methods = [
[new LazyLoadableObjectClassMetadata(), 'protectedIdentifierField', 'foo'],
];

if (! class_exists(\ReflectionType::class, false)) {
return $methods;
}

$methods = array_merge(
$methods,
[
[new LazyLoadableObjectWithTypehintsClassMetadata(), 'identifierFieldNoReturnTypehint', 'noTypeHint'],
[new LazyLoadableObjectWithTypehintsClassMetadata(), 'identifierFieldReturnTypehintScalar', 'scalarValue'],
[new LazyLoadableObjectWithTypehintsClassMetadata(), 'identifierFieldReturnClassFullyQualified', new LazyLoadableObjectWithTypehints()],
[new LazyLoadableObjectWithTypehintsClassMetadata(), 'identifierFieldReturnClassPartialUse', new LazyLoadableObjectWithTypehints()],
[new LazyLoadableObjectWithTypehintsClassMetadata(), 'identifierFieldReturnClassFullUse', new LazyLoadableObjectWithTypehints()],
[new LazyLoadableObjectWithTypehintsClassMetadata(), 'identifierFieldReturnClassOneWord', new stdClass()],
[new LazyLoadableObjectWithTypehintsClassMetadata(), 'identifierFieldReturnClassOneLetter', new stdClass()],
]
);

if (PHP_VERSION_ID < 70100) {
return $methods;
}

return array_merge(
$methods,
[
[new LazyLoadableObjectWithNullableTypehintsClassMetadata(), 'identifierFieldReturnClassOneLetterNullable', new stdClass()],
[new LazyLoadableObjectWithNullableTypehintsClassMetadata(), 'identifierFieldReturnClassOneLetterNullableWithSpace', new stdClass()],
]
);
}
}
Loading

0 comments on commit 9302970

Please sign in to comment.