forked from wallabag/wallabag
twig implementation
This commit is contained in:
2
vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitattributes
vendored
Normal file
2
vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/Tests export-ignore
|
||||
phpunit.xml.dist export-ignore
|
||||
4
vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitignore
vendored
Normal file
4
vendor/symfony/property-access/Symfony/Component/PropertyAccess/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
|
||||
14
vendor/symfony/property-access/Symfony/Component/PropertyAccess/CHANGELOG.md
vendored
Normal file
14
vendor/symfony/property-access/Symfony/Component/PropertyAccess/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.3.0
|
||||
------
|
||||
|
||||
* added PropertyAccessorBuilder, to enable or disable the support of "__call"
|
||||
* added support for "__call" in the PropertyAccessor (disabled by default)
|
||||
* [BC BREAK] changed PropertyAccessor to continue its search for a property or
|
||||
method even if a non-public match was found. Before, a PropertyAccessDeniedException
|
||||
was thrown in this case. Class PropertyAccessDeniedException was removed
|
||||
now.
|
||||
* deprecated PropertyAccess::getPropertyAccessor
|
||||
* added PropertyAccess::createPropertyAccessor and PropertyAccess::createPropertyAccessorBuilder
|
||||
21
vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php
vendored
Normal file
21
vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess\Exception;
|
||||
|
||||
/**
|
||||
* Marker interface for the PropertyAccess component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface ExceptionInterface
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when a property path is malformed.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class InvalidPropertyPathException extends RuntimeException
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when a property cannot be found.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class NoSuchPropertyException extends RuntimeException
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess\Exception;
|
||||
|
||||
/**
|
||||
* Base OutOfBoundsException for the PropertyAccess component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
21
vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/RuntimeException.php
vendored
Normal file
21
vendor/symfony/property-access/Symfony/Component/PropertyAccess/Exception/RuntimeException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess\Exception;
|
||||
|
||||
/**
|
||||
* Base RuntimeException for the PropertyAccess component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when a value does not match an expected type.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class UnexpectedTypeException extends RuntimeException
|
||||
{
|
||||
public function __construct($value, $expectedType)
|
||||
{
|
||||
parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
|
||||
}
|
||||
}
|
||||
19
vendor/symfony/property-access/Symfony/Component/PropertyAccess/LICENSE
vendored
Normal file
19
vendor/symfony/property-access/Symfony/Component/PropertyAccess/LICENSE
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2004-2013 Fabien Potencier
|
||||
|
||||
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.
|
||||
60
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccess.php
vendored
Normal file
60
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccess.php
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
/**
|
||||
* Entry point of the PropertyAccess component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
final class PropertyAccess
|
||||
{
|
||||
/**
|
||||
* Creates a property accessor with the default configuration.
|
||||
*
|
||||
* @return PropertyAccessor The new property accessor
|
||||
*/
|
||||
public static function createPropertyAccessor()
|
||||
{
|
||||
return self::createPropertyAccessorBuilder()->getPropertyAccessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a property accessor builder.
|
||||
*
|
||||
* @return PropertyAccessorBuilder The new property accessor builder
|
||||
*/
|
||||
public static function createPropertyAccessorBuilder()
|
||||
{
|
||||
return new PropertyAccessorBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of {@link getPropertyAccessor}.
|
||||
*
|
||||
* @return PropertyAccessor The new property accessor
|
||||
*
|
||||
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
|
||||
* {@link createPropertyAccessor()} instead.
|
||||
*/
|
||||
public static function getPropertyAccessor()
|
||||
{
|
||||
return self::createPropertyAccessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class cannot be instantiated.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
}
|
||||
442
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessor.php
vendored
Normal file
442
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessor.php
vendored
Normal file
@ -0,0 +1,442 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
|
||||
use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link PropertyAccessorInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class PropertyAccessor implements PropertyAccessorInterface
|
||||
{
|
||||
const VALUE = 0;
|
||||
const IS_REF = 1;
|
||||
|
||||
private $magicCall;
|
||||
|
||||
/**
|
||||
* Should not be used by application code. Use
|
||||
* {@link PropertyAccess::getPropertyAccessor()} instead.
|
||||
*/
|
||||
public function __construct($magicCall = false)
|
||||
{
|
||||
$this->magicCall = $magicCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValue($objectOrArray, $propertyPath)
|
||||
{
|
||||
if (is_string($propertyPath)) {
|
||||
$propertyPath = new PropertyPath($propertyPath);
|
||||
} elseif (!$propertyPath instanceof PropertyPathInterface) {
|
||||
throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface');
|
||||
}
|
||||
|
||||
$propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength());
|
||||
|
||||
return $propertyValues[count($propertyValues) - 1][self::VALUE];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setValue(&$objectOrArray, $propertyPath, $value)
|
||||
{
|
||||
if (is_string($propertyPath)) {
|
||||
$propertyPath = new PropertyPath($propertyPath);
|
||||
} elseif (!$propertyPath instanceof PropertyPathInterface) {
|
||||
throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface');
|
||||
}
|
||||
|
||||
$propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength() - 1);
|
||||
$overwrite = true;
|
||||
|
||||
// Add the root object to the list
|
||||
array_unshift($propertyValues, array(
|
||||
self::VALUE => &$objectOrArray,
|
||||
self::IS_REF => true,
|
||||
));
|
||||
|
||||
for ($i = count($propertyValues) - 1; $i >= 0; --$i) {
|
||||
$objectOrArray =& $propertyValues[$i][self::VALUE];
|
||||
|
||||
if ($overwrite) {
|
||||
if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
|
||||
throw new UnexpectedTypeException($objectOrArray, 'object or array');
|
||||
}
|
||||
|
||||
$property = $propertyPath->getElement($i);
|
||||
//$singular = $propertyPath->singulars[$i];
|
||||
$singular = null;
|
||||
|
||||
if ($propertyPath->isIndex($i)) {
|
||||
$this->writeIndex($objectOrArray, $property, $value);
|
||||
} else {
|
||||
$this->writeProperty($objectOrArray, $property, $singular, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$value =& $objectOrArray;
|
||||
$overwrite = !$propertyValues[$i][self::IS_REF];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the path from an object up to a given path index.
|
||||
*
|
||||
* @param object|array $objectOrArray The object or array to read from
|
||||
* @param PropertyPathInterface $propertyPath The property path to read
|
||||
* @param integer $lastIndex The index up to which should be read
|
||||
*
|
||||
* @return array The values read in the path.
|
||||
*
|
||||
* @throws UnexpectedTypeException If a value within the path is neither object nor array.
|
||||
*/
|
||||
private function &readPropertiesUntil(&$objectOrArray, PropertyPathInterface $propertyPath, $lastIndex)
|
||||
{
|
||||
$propertyValues = array();
|
||||
|
||||
for ($i = 0; $i < $lastIndex; ++$i) {
|
||||
if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
|
||||
throw new UnexpectedTypeException($objectOrArray, 'object or array');
|
||||
}
|
||||
|
||||
$property = $propertyPath->getElement($i);
|
||||
$isIndex = $propertyPath->isIndex($i);
|
||||
$isArrayAccess = is_array($objectOrArray) || $objectOrArray instanceof \ArrayAccess;
|
||||
|
||||
// Create missing nested arrays on demand
|
||||
if ($isIndex && $isArrayAccess && !isset($objectOrArray[$property])) {
|
||||
$objectOrArray[$property] = $i + 1 < $propertyPath->getLength() ? array() : null;
|
||||
}
|
||||
|
||||
if ($isIndex) {
|
||||
$propertyValue =& $this->readIndex($objectOrArray, $property);
|
||||
} else {
|
||||
$propertyValue =& $this->readProperty($objectOrArray, $property);
|
||||
}
|
||||
|
||||
$objectOrArray =& $propertyValue[self::VALUE];
|
||||
|
||||
$propertyValues[] =& $propertyValue;
|
||||
}
|
||||
|
||||
return $propertyValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a key from an array-like structure.
|
||||
*
|
||||
* @param \ArrayAccess|array $array The array or \ArrayAccess object to read from
|
||||
* @param string|integer $index The key to read
|
||||
*
|
||||
* @return mixed The value of the key
|
||||
*
|
||||
* @throws NoSuchPropertyException If the array does not implement \ArrayAccess or it is not an array
|
||||
*/
|
||||
private function &readIndex(&$array, $index)
|
||||
{
|
||||
if (!$array instanceof \ArrayAccess && !is_array($array)) {
|
||||
throw new NoSuchPropertyException(sprintf('Index "%s" cannot be read from object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array)));
|
||||
}
|
||||
|
||||
// Use an array instead of an object since performance is very crucial here
|
||||
$result = array(
|
||||
self::VALUE => null,
|
||||
self::IS_REF => false
|
||||
);
|
||||
|
||||
if (isset($array[$index])) {
|
||||
if (is_array($array)) {
|
||||
$result[self::VALUE] =& $array[$index];
|
||||
$result[self::IS_REF] = true;
|
||||
} else {
|
||||
$result[self::VALUE] = $array[$index];
|
||||
// Objects are always passed around by reference
|
||||
$result[self::IS_REF] = is_object($array[$index]) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the a property from an object or array.
|
||||
*
|
||||
* @param object $object The object to read from.
|
||||
* @param string $property The property to read.
|
||||
*
|
||||
* @return mixed The value of the read property
|
||||
*
|
||||
* @throws NoSuchPropertyException If the property does not exist or is not
|
||||
* public.
|
||||
*/
|
||||
private function &readProperty(&$object, $property)
|
||||
{
|
||||
// Use an array instead of an object since performance is
|
||||
// very crucial here
|
||||
$result = array(
|
||||
self::VALUE => null,
|
||||
self::IS_REF => false
|
||||
);
|
||||
|
||||
if (!is_object($object)) {
|
||||
throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you should write the property path as "[%s]" instead?', $property, $property));
|
||||
}
|
||||
|
||||
$camelProp = $this->camelize($property);
|
||||
$reflClass = new \ReflectionClass($object);
|
||||
$getter = 'get'.$camelProp;
|
||||
$isser = 'is'.$camelProp;
|
||||
$hasser = 'has'.$camelProp;
|
||||
$classHasProperty = $reflClass->hasProperty($property);
|
||||
|
||||
if ($reflClass->hasMethod($getter) && $reflClass->getMethod($getter)->isPublic()) {
|
||||
$result[self::VALUE] = $object->$getter();
|
||||
} elseif ($reflClass->hasMethod($isser) && $reflClass->getMethod($isser)->isPublic()) {
|
||||
$result[self::VALUE] = $object->$isser();
|
||||
} elseif ($reflClass->hasMethod($hasser) && $reflClass->getMethod($hasser)->isPublic()) {
|
||||
$result[self::VALUE] = $object->$hasser();
|
||||
} elseif ($reflClass->hasMethod('__get') && $reflClass->getMethod('__get')->isPublic()) {
|
||||
$result[self::VALUE] = $object->$property;
|
||||
} elseif ($classHasProperty && $reflClass->getProperty($property)->isPublic()) {
|
||||
$result[self::VALUE] =& $object->$property;
|
||||
$result[self::IS_REF] = true;
|
||||
} elseif (!$classHasProperty && property_exists($object, $property)) {
|
||||
// Needed to support \stdClass instances. We need to explicitly
|
||||
// exclude $classHasProperty, otherwise if in the previous clause
|
||||
// a *protected* property was found on the class, property_exists()
|
||||
// returns true, consequently the following line will result in a
|
||||
// fatal error.
|
||||
$result[self::VALUE] =& $object->$property;
|
||||
$result[self::IS_REF] = true;
|
||||
} elseif ($this->magicCall && $reflClass->hasMethod('__call') && $reflClass->getMethod('__call')->isPublic()) {
|
||||
// we call the getter and hope the __call do the job
|
||||
$result[self::VALUE] = $object->$getter();
|
||||
} else {
|
||||
throw new NoSuchPropertyException(sprintf(
|
||||
'Neither the property "%s" nor one of the methods "%s()", '.
|
||||
'"%s()", "%s()", "__get()" or "__call()" exist and have public access in '.
|
||||
'class "%s".',
|
||||
$property,
|
||||
$getter,
|
||||
$isser,
|
||||
$hasser,
|
||||
$reflClass->name
|
||||
));
|
||||
}
|
||||
|
||||
// Objects are always passed around by reference
|
||||
if (is_object($result[self::VALUE])) {
|
||||
$result[self::IS_REF] = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the property at the given index in the path
|
||||
*
|
||||
* @param \ArrayAccess|array $array An array or \ArrayAccess object to write to
|
||||
* @param string|integer $index The index to write at
|
||||
* @param mixed $value The value to write
|
||||
*
|
||||
* @throws NoSuchPropertyException If the array does not implement \ArrayAccess or it is not an array
|
||||
*/
|
||||
private function writeIndex(&$array, $index, $value)
|
||||
{
|
||||
if (!$array instanceof \ArrayAccess && !is_array($array)) {
|
||||
throw new NoSuchPropertyException(sprintf('Index "%s" cannot be modified in object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array)));
|
||||
}
|
||||
|
||||
$array[$index] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the property at the given index in the path
|
||||
*
|
||||
* @param object|array $object The object or array to write to
|
||||
* @param string $property The property to write
|
||||
* @param string|null $singular The singular form of the property name or null
|
||||
* @param mixed $value The value to write
|
||||
*
|
||||
* @throws NoSuchPropertyException If the property does not exist or is not
|
||||
* public.
|
||||
*/
|
||||
private function writeProperty(&$object, $property, $singular, $value)
|
||||
{
|
||||
$guessedAdders = '';
|
||||
|
||||
if (!is_object($object)) {
|
||||
throw new NoSuchPropertyException(sprintf('Cannot write property "%s" to an array. Maybe you should write the property path as "[%s]" instead?', $property, $property));
|
||||
}
|
||||
|
||||
$reflClass = new \ReflectionClass($object);
|
||||
$plural = $this->camelize($property);
|
||||
|
||||
// Any of the two methods is required, but not yet known
|
||||
$singulars = null !== $singular ? array($singular) : (array) StringUtil::singularify($plural);
|
||||
|
||||
if (is_array($value) || $value instanceof \Traversable) {
|
||||
$methods = $this->findAdderAndRemover($reflClass, $singulars);
|
||||
|
||||
if (null !== $methods) {
|
||||
// At this point the add and remove methods have been found
|
||||
// Use iterator_to_array() instead of clone in order to prevent side effects
|
||||
// see https://github.com/symfony/symfony/issues/4670
|
||||
$itemsToAdd = is_object($value) ? iterator_to_array($value) : $value;
|
||||
$itemToRemove = array();
|
||||
$propertyValue = $this->readProperty($object, $property);
|
||||
$previousValue = $propertyValue[self::VALUE];
|
||||
|
||||
if (is_array($previousValue) || $previousValue instanceof \Traversable) {
|
||||
foreach ($previousValue as $previousItem) {
|
||||
foreach ($value as $key => $item) {
|
||||
if ($item === $previousItem) {
|
||||
// Item found, don't add
|
||||
unset($itemsToAdd[$key]);
|
||||
|
||||
// Next $previousItem
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Item not found, add to remove list
|
||||
$itemToRemove[] = $previousItem;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($itemToRemove as $item) {
|
||||
call_user_func(array($object, $methods[1]), $item);
|
||||
}
|
||||
|
||||
foreach ($itemsToAdd as $item) {
|
||||
call_user_func(array($object, $methods[0]), $item);
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
// It is sufficient to include only the adders in the error
|
||||
// message. If the user implements the adder but not the remover,
|
||||
// an exception will be thrown in findAdderAndRemover() that
|
||||
// the remover has to be implemented as well.
|
||||
$guessedAdders = '"add'.implode('()", "add', $singulars).'()", ';
|
||||
}
|
||||
}
|
||||
|
||||
$setter = 'set'.$this->camelize($property);
|
||||
$classHasProperty = $reflClass->hasProperty($property);
|
||||
|
||||
if ($reflClass->hasMethod($setter) && $reflClass->getMethod($setter)->isPublic()) {
|
||||
$object->$setter($value);
|
||||
} elseif ($reflClass->hasMethod('__set') && $reflClass->getMethod('__set')->isPublic()) {
|
||||
$object->$property = $value;
|
||||
} elseif ($classHasProperty && $reflClass->getProperty($property)->isPublic()) {
|
||||
$object->$property = $value;
|
||||
} elseif (!$classHasProperty && property_exists($object, $property)) {
|
||||
// Needed to support \stdClass instances. We need to explicitly
|
||||
// exclude $classHasProperty, otherwise if in the previous clause
|
||||
// a *protected* property was found on the class, property_exists()
|
||||
// returns true, consequently the following line will result in a
|
||||
// fatal error.
|
||||
$object->$property = $value;
|
||||
} elseif ($this->magicCall && $reflClass->hasMethod('__call') && $reflClass->getMethod('__call')->isPublic()) {
|
||||
// we call the getter and hope the __call do the job
|
||||
$object->$setter($value);
|
||||
} else {
|
||||
throw new NoSuchPropertyException(sprintf(
|
||||
'Neither the property "%s" nor one of the methods %s"%s()", '.
|
||||
'"__set()" or "__call()" exist and have public access in class "%s".',
|
||||
$property,
|
||||
$guessedAdders,
|
||||
$setter,
|
||||
$reflClass->name
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Camelizes a given string.
|
||||
*
|
||||
* @param string $string Some string
|
||||
*
|
||||
* @return string The camelized version of the string
|
||||
*/
|
||||
private function camelize($string)
|
||||
{
|
||||
return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for add and remove methods.
|
||||
*
|
||||
* @param \ReflectionClass $reflClass The reflection class for the given object
|
||||
* @param array $singulars The singular form of the property name or null
|
||||
*
|
||||
* @return array|null An array containing the adder and remover when found, null otherwise
|
||||
*
|
||||
* @throws NoSuchPropertyException If the property does not exist
|
||||
*/
|
||||
private function findAdderAndRemover(\ReflectionClass $reflClass, array $singulars)
|
||||
{
|
||||
foreach ($singulars as $singular) {
|
||||
$addMethod = 'add'.$singular;
|
||||
$removeMethod = 'remove'.$singular;
|
||||
|
||||
$addMethodFound = $this->isAccessible($reflClass, $addMethod, 1);
|
||||
$removeMethodFound = $this->isAccessible($reflClass, $removeMethod, 1);
|
||||
|
||||
if ($addMethodFound && $removeMethodFound) {
|
||||
return array($addMethod, $removeMethod);
|
||||
}
|
||||
|
||||
if ($addMethodFound xor $removeMethodFound) {
|
||||
throw new NoSuchPropertyException(sprintf(
|
||||
'Found the public method "%s()", but did not find a public "%s()" on class %s',
|
||||
$addMethodFound ? $addMethod : $removeMethod,
|
||||
$addMethodFound ? $removeMethod : $addMethod,
|
||||
$reflClass->name
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a method is public and has a specific number of required parameters.
|
||||
*
|
||||
* @param \ReflectionClass $class The class of the method
|
||||
* @param string $methodName The method name
|
||||
* @param integer $parameters The number of parameters
|
||||
*
|
||||
* @return Boolean Whether the method is public and has $parameters
|
||||
* required parameters
|
||||
*/
|
||||
private function isAccessible(\ReflectionClass $class, $methodName, $parameters)
|
||||
{
|
||||
if ($class->hasMethod($methodName)) {
|
||||
$method = $class->getMethod($methodName);
|
||||
|
||||
if ($method->isPublic() && $method->getNumberOfRequiredParameters() === $parameters) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
67
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php
vendored
Normal file
67
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
/**
|
||||
* A configurable builder for PropertyAccessorInterface objects.
|
||||
*
|
||||
* @author Jérémie Augustin <jeremie.augustin@pixel-cookers.com>
|
||||
*/
|
||||
class PropertyAccessorBuilder
|
||||
{
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $magicCall = false;
|
||||
|
||||
/**
|
||||
* Enables the use of "__call" by the ProperyAccessor.
|
||||
*
|
||||
* @return PropertyAccessorBuilder The builder object
|
||||
*/
|
||||
public function enableMagicCall()
|
||||
{
|
||||
$this->magicCall = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the use of "__call" by the ProperyAccessor.
|
||||
*
|
||||
* @return PropertyAccessorBuilder The builder object
|
||||
*/
|
||||
public function disableMagicCall()
|
||||
{
|
||||
$this->magicCall = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Boolean true if the use of "__call" by the ProperyAccessor is enabled
|
||||
*/
|
||||
public function isMagicCallEnabled()
|
||||
{
|
||||
return $this->magicCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns a new propertyAccessor object.
|
||||
*
|
||||
* @return PropertyAccessorInterface The built propertyAccessor
|
||||
*/
|
||||
public function getPropertyAccessor()
|
||||
{
|
||||
return new PropertyAccessor($this->magicCall);
|
||||
}
|
||||
}
|
||||
81
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php
vendored
Normal file
81
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
/**
|
||||
* Writes and reads values to/from an object/array graph.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface PropertyAccessorInterface
|
||||
{
|
||||
/**
|
||||
* Sets the value at the end of the property path of the object
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
*
|
||||
* $propertyAccessor = PropertyAccess::getPropertyAccessor();
|
||||
*
|
||||
* echo $propertyAccessor->setValue($object, 'child.name', 'Fabien');
|
||||
* // equals echo $object->getChild()->setName('Fabien');
|
||||
*
|
||||
* This method first tries to find a public setter for each property in the
|
||||
* path. The name of the setter must be the camel-cased property name
|
||||
* prefixed with "set".
|
||||
*
|
||||
* If the setter does not exist, this method tries to find a public
|
||||
* property. The value of the property is then changed.
|
||||
*
|
||||
* If neither is found, an exception is thrown.
|
||||
*
|
||||
* @param object|array $objectOrArray The object or array to modify
|
||||
* @param string|PropertyPathInterface $propertyPath The property path to modify
|
||||
* @param mixed $value The value to set at the end of the property path
|
||||
*
|
||||
* @throws Exception\NoSuchPropertyException If a property does not exist or is not public.
|
||||
* @throws Exception\UnexpectedTypeException If a value within the path is neither object
|
||||
* nor array
|
||||
*/
|
||||
public function setValue(&$objectOrArray, $propertyPath, $value);
|
||||
|
||||
/**
|
||||
* Returns the value at the end of the property path of the object
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
*
|
||||
* $propertyAccessor = PropertyAccess::getPropertyAccessor();
|
||||
*
|
||||
* echo $propertyAccessor->getValue($object, 'child.name);
|
||||
* // equals echo $object->getChild()->getName();
|
||||
*
|
||||
* This method first tries to find a public getter for each property in the
|
||||
* path. The name of the getter must be the camel-cased property name
|
||||
* prefixed with "get", "is", or "has".
|
||||
*
|
||||
* If the getter does not exist, this method tries to find a public
|
||||
* property. The value of the property is then returned.
|
||||
*
|
||||
* If none of them are found, an exception is thrown.
|
||||
*
|
||||
* @param object|array $objectOrArray The object or array to traverse
|
||||
* @param string|PropertyPathInterface $propertyPath The property path to read
|
||||
*
|
||||
* @return mixed The value at the end of the property path
|
||||
*
|
||||
* @throws Exception\NoSuchPropertyException If a property does not exist or is not public.
|
||||
*/
|
||||
public function getValue($objectOrArray, $propertyPath);
|
||||
}
|
||||
225
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPath.php
vendored
Normal file
225
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPath.php
vendored
Normal file
@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
use Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException;
|
||||
use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException;
|
||||
use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link PropertyPathInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class PropertyPath implements \IteratorAggregate, PropertyPathInterface
|
||||
{
|
||||
/**
|
||||
* Character used for separating between plural and singular of an element.
|
||||
* @var string
|
||||
*/
|
||||
const SINGULAR_SEPARATOR = '|';
|
||||
|
||||
/**
|
||||
* The elements of the property path
|
||||
* @var array
|
||||
*/
|
||||
private $elements = array();
|
||||
|
||||
/**
|
||||
* The singular forms of the elements in the property path.
|
||||
* @var array
|
||||
*/
|
||||
private $singulars = array();
|
||||
|
||||
/**
|
||||
* The number of elements in the property path
|
||||
* @var integer
|
||||
*/
|
||||
private $length;
|
||||
|
||||
/**
|
||||
* Contains a Boolean for each property in $elements denoting whether this
|
||||
* element is an index. It is a property otherwise.
|
||||
* @var array
|
||||
*/
|
||||
private $isIndex = array();
|
||||
|
||||
/**
|
||||
* String representation of the path
|
||||
* @var string
|
||||
*/
|
||||
private $pathAsString;
|
||||
|
||||
/**
|
||||
* Constructs a property path from a string.
|
||||
*
|
||||
* @param PropertyPath|string $propertyPath The property path as string or instance
|
||||
*
|
||||
* @throws UnexpectedTypeException If the given path is not a string
|
||||
* @throws InvalidPropertyPathException If the syntax of the property path is not valid
|
||||
*/
|
||||
public function __construct($propertyPath)
|
||||
{
|
||||
// Can be used as copy constructor
|
||||
if ($propertyPath instanceof PropertyPath) {
|
||||
/* @var PropertyPath $propertyPath */
|
||||
$this->elements = $propertyPath->elements;
|
||||
$this->singulars = $propertyPath->singulars;
|
||||
$this->length = $propertyPath->length;
|
||||
$this->isIndex = $propertyPath->isIndex;
|
||||
$this->pathAsString = $propertyPath->pathAsString;
|
||||
|
||||
return;
|
||||
}
|
||||
if (!is_string($propertyPath)) {
|
||||
throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPath');
|
||||
}
|
||||
|
||||
if ('' === $propertyPath) {
|
||||
throw new InvalidPropertyPathException('The property path should not be empty.');
|
||||
}
|
||||
|
||||
$this->pathAsString = $propertyPath;
|
||||
$position = 0;
|
||||
$remaining = $propertyPath;
|
||||
|
||||
// first element is evaluated differently - no leading dot for properties
|
||||
$pattern = '/^(([^\.\[]+)|\[([^\]]+)\])(.*)/';
|
||||
|
||||
while (preg_match($pattern, $remaining, $matches)) {
|
||||
if ('' !== $matches[2]) {
|
||||
$element = $matches[2];
|
||||
$this->isIndex[] = false;
|
||||
} else {
|
||||
$element = $matches[3];
|
||||
$this->isIndex[] = true;
|
||||
}
|
||||
// Disabled this behaviour as the syntax is not yet final
|
||||
//$pos = strpos($element, self::SINGULAR_SEPARATOR);
|
||||
$pos = false;
|
||||
$singular = null;
|
||||
|
||||
if (false !== $pos) {
|
||||
$singular = substr($element, $pos + 1);
|
||||
$element = substr($element, 0, $pos);
|
||||
}
|
||||
|
||||
$this->elements[] = $element;
|
||||
$this->singulars[] = $singular;
|
||||
|
||||
$position += strlen($matches[1]);
|
||||
$remaining = $matches[4];
|
||||
$pattern = '/^(\.(\w+)|\[([^\]]+)\])(.*)/';
|
||||
}
|
||||
|
||||
if ('' !== $remaining) {
|
||||
throw new InvalidPropertyPathException(sprintf(
|
||||
'Could not parse property path "%s". Unexpected token "%s" at position %d',
|
||||
$propertyPath,
|
||||
$remaining{0},
|
||||
$position
|
||||
));
|
||||
}
|
||||
|
||||
$this->length = count($this->elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->pathAsString;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLength()
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
if ($this->length <= 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parent = clone $this;
|
||||
|
||||
--$parent->length;
|
||||
$parent->pathAsString = substr($parent->pathAsString, 0, max(strrpos($parent->pathAsString, '.'), strrpos($parent->pathAsString, '[')));
|
||||
array_pop($parent->elements);
|
||||
array_pop($parent->singulars);
|
||||
array_pop($parent->isIndex);
|
||||
|
||||
return $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new iterator for this path
|
||||
*
|
||||
* @return PropertyPathIteratorInterface
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new PropertyPathIterator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElements()
|
||||
{
|
||||
return $this->elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElement($index)
|
||||
{
|
||||
if (!isset($this->elements[$index])) {
|
||||
throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index));
|
||||
}
|
||||
|
||||
return $this->elements[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isProperty($index)
|
||||
{
|
||||
if (!isset($this->isIndex[$index])) {
|
||||
throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index));
|
||||
}
|
||||
|
||||
return !$this->isIndex[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isIndex($index)
|
||||
{
|
||||
if (!isset($this->isIndex[$index])) {
|
||||
throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index));
|
||||
}
|
||||
|
||||
return $this->isIndex[$index];
|
||||
}
|
||||
}
|
||||
306
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathBuilder.php
vendored
Normal file
306
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathBuilder.php
vendored
Normal file
@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class PropertyPathBuilder
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $elements = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $isIndex = array();
|
||||
|
||||
/**
|
||||
* Creates a new property path builder.
|
||||
*
|
||||
* @param null|PropertyPathInterface|string $path The path to initially store
|
||||
* in the builder. Optional.
|
||||
*/
|
||||
public function __construct($path = null)
|
||||
{
|
||||
if (null !== $path) {
|
||||
$this->append($path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a (sub-) path to the current path.
|
||||
*
|
||||
* @param PropertyPathInterface|string $path The path to append.
|
||||
* @param integer $offset The offset where the appended
|
||||
* piece starts in $path.
|
||||
* @param integer $length The length of the appended piece.
|
||||
* If 0, the full path is appended.
|
||||
*/
|
||||
public function append($path, $offset = 0, $length = 0)
|
||||
{
|
||||
if (is_string($path)) {
|
||||
$path = new PropertyPath($path);
|
||||
}
|
||||
|
||||
if (0 === $length) {
|
||||
$end = $path->getLength();
|
||||
} else {
|
||||
$end = $offset + $length;
|
||||
}
|
||||
|
||||
for (; $offset < $end; ++$offset) {
|
||||
$this->elements[] = $path->getElement($offset);
|
||||
$this->isIndex[] = $path->isIndex($offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an index element to the current path.
|
||||
*
|
||||
* @param string $name The name of the appended index
|
||||
*/
|
||||
public function appendIndex($name)
|
||||
{
|
||||
$this->elements[] = $name;
|
||||
$this->isIndex[] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a property element to the current path.
|
||||
*
|
||||
* @param string $name The name of the appended property
|
||||
*/
|
||||
public function appendProperty($name)
|
||||
{
|
||||
$this->elements[] = $name;
|
||||
$this->isIndex[] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes elements from the current path.
|
||||
*
|
||||
* @param integer $offset The offset at which to remove
|
||||
* @param integer $length The length of the removed piece
|
||||
*
|
||||
* @throws OutOfBoundsException if offset is invalid
|
||||
*/
|
||||
public function remove($offset, $length = 1)
|
||||
{
|
||||
if (!isset($this->elements[$offset])) {
|
||||
throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset));
|
||||
}
|
||||
|
||||
$this->resize($offset, $length, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a sub-path by a different (sub-) path.
|
||||
*
|
||||
* @param integer $offset The offset at which to replace.
|
||||
* @param integer $length The length of the piece to replace.
|
||||
* @param PropertyPathInterface|string $path The path to insert.
|
||||
* @param integer $pathOffset The offset where the inserted piece
|
||||
* starts in $path.
|
||||
* @param integer $pathLength The length of the inserted piece.
|
||||
* If 0, the full path is inserted.
|
||||
*
|
||||
* @throws OutOfBoundsException If the offset is invalid
|
||||
*/
|
||||
public function replace($offset, $length, $path, $pathOffset = 0, $pathLength = 0)
|
||||
{
|
||||
if (is_string($path)) {
|
||||
$path = new PropertyPath($path);
|
||||
}
|
||||
|
||||
if ($offset < 0 && abs($offset) <= $this->getLength()) {
|
||||
$offset = $this->getLength() + $offset;
|
||||
} elseif (!isset($this->elements[$offset])) {
|
||||
throw new OutOfBoundsException('The offset ' . $offset . ' is not within the property path');
|
||||
}
|
||||
|
||||
if (0 === $pathLength) {
|
||||
$pathLength = $path->getLength() - $pathOffset;
|
||||
}
|
||||
|
||||
$this->resize($offset, $length, $pathLength);
|
||||
|
||||
for ($i = 0; $i < $pathLength; ++$i) {
|
||||
$this->elements[$offset + $i] = $path->getElement($pathOffset + $i);
|
||||
$this->isIndex[$offset + $i] = $path->isIndex($pathOffset + $i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a property element by an index element.
|
||||
*
|
||||
* @param integer $offset The offset at which to replace
|
||||
* @param string $name The new name of the element. Optional.
|
||||
*
|
||||
* @throws OutOfBoundsException If the offset is invalid
|
||||
*/
|
||||
public function replaceByIndex($offset, $name = null)
|
||||
{
|
||||
if (!isset($this->elements[$offset])) {
|
||||
throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset));
|
||||
}
|
||||
|
||||
if (null !== $name) {
|
||||
$this->elements[$offset] = $name;
|
||||
}
|
||||
|
||||
$this->isIndex[$offset] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces an index element by a property element.
|
||||
*
|
||||
* @param integer $offset The offset at which to replace
|
||||
* @param string $name The new name of the element. Optional.
|
||||
*
|
||||
* @throws OutOfBoundsException If the offset is invalid
|
||||
*/
|
||||
public function replaceByProperty($offset, $name = null)
|
||||
{
|
||||
if (!isset($this->elements[$offset])) {
|
||||
throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset));
|
||||
}
|
||||
|
||||
if (null !== $name) {
|
||||
$this->elements[$offset] = $name;
|
||||
}
|
||||
|
||||
$this->isIndex[$offset] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the current path.
|
||||
*
|
||||
* @return integer The path length
|
||||
*/
|
||||
public function getLength()
|
||||
{
|
||||
return count($this->elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current property path.
|
||||
*
|
||||
* @return PropertyPathInterface The constructed property path
|
||||
*/
|
||||
public function getPropertyPath()
|
||||
{
|
||||
$pathAsString = $this->__toString();
|
||||
|
||||
return '' !== $pathAsString ? new PropertyPath($pathAsString) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current property path as string.
|
||||
*
|
||||
* @return string The property path as string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$string = '';
|
||||
|
||||
foreach ($this->elements as $offset => $element) {
|
||||
if ($this->isIndex[$offset]) {
|
||||
$element = '['.$element.']';
|
||||
} elseif ('' !== $string) {
|
||||
$string .= '.';
|
||||
}
|
||||
|
||||
$string .= $element;
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the path so that a chunk of length $cutLength is
|
||||
* removed at $offset and another chunk of length $insertionLength
|
||||
* can be inserted.
|
||||
*
|
||||
* @param integer $offset The offset where the removed chunk starts
|
||||
* @param integer $cutLength The length of the removed chunk
|
||||
* @param integer $insertionLength The length of the inserted chunk
|
||||
*/
|
||||
private function resize($offset, $cutLength, $insertionLength)
|
||||
{
|
||||
// Nothing else to do in this case
|
||||
if ($insertionLength === $cutLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
$length = count($this->elements);
|
||||
|
||||
if ($cutLength > $insertionLength) {
|
||||
// More elements should be removed than inserted
|
||||
$diff = $cutLength - $insertionLength;
|
||||
$newLength = $length - $diff;
|
||||
|
||||
// Shift elements to the left (left-to-right until the new end)
|
||||
// Max allowed offset to be shifted is such that
|
||||
// $offset + $diff < $length (otherwise invalid index access)
|
||||
// i.e. $offset < $length - $diff = $newLength
|
||||
for ($i = $offset; $i < $newLength; ++$i) {
|
||||
$this->elements[$i] = $this->elements[$i + $diff];
|
||||
$this->isIndex[$i] = $this->isIndex[$i + $diff];
|
||||
}
|
||||
|
||||
// All remaining elements should be removed
|
||||
for (; $i < $length; ++$i) {
|
||||
unset($this->elements[$i]);
|
||||
unset($this->isIndex[$i]);
|
||||
}
|
||||
} else {
|
||||
$diff = $insertionLength - $cutLength;
|
||||
|
||||
$newLength = $length + $diff;
|
||||
$indexAfterInsertion = $offset + $insertionLength;
|
||||
|
||||
// $diff <= $insertionLength
|
||||
// $indexAfterInsertion >= $insertionLength
|
||||
// => $diff <= $indexAfterInsertion
|
||||
|
||||
// In each of the following loops, $i >= $diff must hold,
|
||||
// otherwise ($i - $diff) becomes negative.
|
||||
|
||||
// Shift old elements to the right to make up space for the
|
||||
// inserted elements. This needs to be done left-to-right in
|
||||
// order to preserve an ascending array index order
|
||||
// Since $i = max($length, $indexAfterInsertion) and $indexAfterInsertion >= $diff,
|
||||
// $i >= $diff is guaranteed.
|
||||
for ($i = max($length, $indexAfterInsertion); $i < $newLength; ++$i) {
|
||||
$this->elements[$i] = $this->elements[$i - $diff];
|
||||
$this->isIndex[$i] = $this->isIndex[$i - $diff];
|
||||
}
|
||||
|
||||
// Shift remaining elements to the right. Do this right-to-left
|
||||
// so we don't overwrite elements before copying them
|
||||
// The last written index is the immediate index after the inserted
|
||||
// string, because the indices before that will be overwritten
|
||||
// anyway.
|
||||
// Since $i >= $indexAfterInsertion and $indexAfterInsertion >= $diff,
|
||||
// $i >= $diff is guaranteed.
|
||||
for ($i = $length - 1; $i >= $indexAfterInsertion; --$i) {
|
||||
$this->elements[$i] = $this->elements[$i - $diff];
|
||||
$this->isIndex[$i] = $this->isIndex[$i - $diff];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathInterface.php
vendored
Normal file
86
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathInterface.php
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
/**
|
||||
* A sequence of property names or array indices.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface PropertyPathInterface extends \Traversable
|
||||
{
|
||||
/**
|
||||
* Returns the string representation of the property path
|
||||
*
|
||||
* @return string The path as string
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* Returns the length of the property path, i.e. the number of elements.
|
||||
*
|
||||
* @return integer The path length
|
||||
*/
|
||||
public function getLength();
|
||||
|
||||
/**
|
||||
* Returns the parent property path.
|
||||
*
|
||||
* The parent property path is the one that contains the same items as
|
||||
* this one except for the last one.
|
||||
*
|
||||
* If this property path only contains one item, null is returned.
|
||||
*
|
||||
* @return PropertyPath The parent path or null
|
||||
*/
|
||||
public function getParent();
|
||||
|
||||
/**
|
||||
* Returns the elements of the property path as array
|
||||
*
|
||||
* @return array An array of property/index names
|
||||
*/
|
||||
public function getElements();
|
||||
|
||||
/**
|
||||
* Returns the element at the given index in the property path
|
||||
*
|
||||
* @param integer $index The index key
|
||||
*
|
||||
* @return string A property or index name
|
||||
*
|
||||
* @throws Exception\OutOfBoundsException If the offset is invalid
|
||||
*/
|
||||
public function getElement($index);
|
||||
|
||||
/**
|
||||
* Returns whether the element at the given index is a property
|
||||
*
|
||||
* @param integer $index The index in the property path
|
||||
*
|
||||
* @return Boolean Whether the element at this index is a property
|
||||
*
|
||||
* @throws Exception\OutOfBoundsException If the offset is invalid
|
||||
*/
|
||||
public function isProperty($index);
|
||||
|
||||
/**
|
||||
* Returns whether the element at the given index is an array index
|
||||
*
|
||||
* @param integer $index The index in the property path
|
||||
*
|
||||
* @return Boolean Whether the element at this index is an array index
|
||||
*
|
||||
* @throws Exception\OutOfBoundsException If the offset is invalid
|
||||
*/
|
||||
public function isIndex($index);
|
||||
}
|
||||
55
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIterator.php
vendored
Normal file
55
vendor/symfony/property-access/Symfony/Component/PropertyAccess/PropertyPathIterator.php
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
/**
|
||||
* Traverses a property path and provides additional methods to find out
|
||||
* information about the current element
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class PropertyPathIterator extends \ArrayIterator implements PropertyPathIteratorInterface
|
||||
{
|
||||
/**
|
||||
* The traversed property path
|
||||
* @var PropertyPathInterface
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param PropertyPathInterface $path The property path to traverse
|
||||
*/
|
||||
public function __construct(PropertyPathInterface $path)
|
||||
{
|
||||
parent::__construct($path->getElements());
|
||||
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isIndex()
|
||||
{
|
||||
return $this->path->isIndex($this->key());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isProperty()
|
||||
{
|
||||
return $this->path->isProperty($this->key());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface PropertyPathIteratorInterface extends \Iterator, \SeekableIterator
|
||||
{
|
||||
/**
|
||||
* Returns whether the current element in the property path is an array
|
||||
* index.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isIndex();
|
||||
|
||||
/**
|
||||
* Returns whether the current element in the property path is a property
|
||||
* name.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isProperty();
|
||||
}
|
||||
14
vendor/symfony/property-access/Symfony/Component/PropertyAccess/README.md
vendored
Normal file
14
vendor/symfony/property-access/Symfony/Component/PropertyAccess/README.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
PropertyAccess Component
|
||||
========================
|
||||
|
||||
PropertyAccess reads/writes values from/to object/array graphs using a simple
|
||||
string notation.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
$ cd path/to/Symfony/Component/PropertyAccess/
|
||||
$ composer.phar install --dev
|
||||
$ phpunit
|
||||
195
vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php
vendored
Normal file
195
vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyAccess;
|
||||
|
||||
/**
|
||||
* Creates singulars from plurals.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class StringUtil
|
||||
{
|
||||
/**
|
||||
* Map english plural to singular suffixes
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see http://english-zone.com/spelling/plurals.html
|
||||
* @see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English
|
||||
*/
|
||||
private static $pluralMap = array(
|
||||
// First entry: plural suffix, reversed
|
||||
// Second entry: length of plural suffix
|
||||
// Third entry: Whether the suffix may succeed a vocal
|
||||
// Fourth entry: Whether the suffix may succeed a consonant
|
||||
// Fifth entry: singular suffix, normal
|
||||
|
||||
// bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
|
||||
array('a', 1, true, true, array('on', 'um')),
|
||||
|
||||
// nebulae (nebula)
|
||||
array('ea', 2, true, true, 'a'),
|
||||
|
||||
// mice (mouse), lice (louse)
|
||||
array('eci', 3, false, true, 'ouse'),
|
||||
|
||||
// geese (goose)
|
||||
array('esee', 4, false, true, 'oose'),
|
||||
|
||||
// fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
|
||||
array('i', 1, true, true, 'us'),
|
||||
|
||||
// men (man), women (woman)
|
||||
array('nem', 3, true, true, 'man'),
|
||||
|
||||
// children (child)
|
||||
array('nerdlihc', 8, true, true, 'child'),
|
||||
|
||||
// oxen (ox)
|
||||
array('nexo', 4, false, false, 'ox'),
|
||||
|
||||
// indices (index), appendices (appendix), prices (price)
|
||||
array('seci', 4, false, true, array('ex', 'ix', 'ice')),
|
||||
|
||||
// babies (baby)
|
||||
array('sei', 3, false, true, 'y'),
|
||||
|
||||
// analyses (analysis), ellipses (ellipsis), funguses (fungus),
|
||||
// neuroses (neurosis), theses (thesis), emphases (emphasis),
|
||||
// oases (oasis), crises (crisis), houses (house), bases (base),
|
||||
// atlases (atlas), kisses (kiss)
|
||||
array('ses', 3, true, true, array('s', 'se', 'sis')),
|
||||
|
||||
// objectives (objective), alternative (alternatives)
|
||||
array('sevit', 5, true, true, 'tive'),
|
||||
|
||||
// lives (life), wives (wife)
|
||||
array('sevi', 4, false, true, 'ife'),
|
||||
|
||||
// hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
|
||||
array('sev', 3, true, true, 'f'),
|
||||
|
||||
// axes (axis), axes (ax), axes (axe)
|
||||
array('sexa', 4, false, false, array('ax', 'axe', 'axis')),
|
||||
|
||||
// indexes (index), matrixes (matrix)
|
||||
array('sex', 3, true, false, 'x'),
|
||||
|
||||
// quizzes (quiz)
|
||||
array('sezz', 4, true, false, 'z'),
|
||||
|
||||
// bureaus (bureau)
|
||||
array('suae', 4, false, true, 'eau'),
|
||||
|
||||
// roses (rose), garages (garage), cassettes (cassette),
|
||||
// waltzes (waltz), heroes (hero), bushes (bush), arches (arch),
|
||||
// shoes (shoe)
|
||||
array('se', 2, true, true, array('', 'e')),
|
||||
|
||||
// tags (tag)
|
||||
array('s', 1, true, true, ''),
|
||||
|
||||
// chateaux (chateau)
|
||||
array('xuae', 4, false, true, 'eau'),
|
||||
);
|
||||
|
||||
/**
|
||||
* This class should not be instantiated
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Returns the singular form of a word
|
||||
*
|
||||
* If the method can't determine the form with certainty, an array of the
|
||||
* possible singulars is returned.
|
||||
*
|
||||
* @param string $plural A word in plural form
|
||||
* @return string|array The singular form or an array of possible singular
|
||||
* forms
|
||||
*/
|
||||
public static function singularify($plural)
|
||||
{
|
||||
$pluralRev = strrev($plural);
|
||||
$lowerPluralRev = strtolower($pluralRev);
|
||||
$pluralLength = strlen($lowerPluralRev);
|
||||
|
||||
// The outer loop iterates over the entries of the plural table
|
||||
// The inner loop $j iterates over the characters of the plural suffix
|
||||
// in the plural table to compare them with the characters of the actual
|
||||
// given plural suffix
|
||||
foreach (self::$pluralMap as $map) {
|
||||
$suffix = $map[0];
|
||||
$suffixLength = $map[1];
|
||||
$j = 0;
|
||||
|
||||
// Compare characters in the plural table and of the suffix of the
|
||||
// given plural one by one
|
||||
while ($suffix[$j] === $lowerPluralRev[$j]) {
|
||||
// Let $j point to the next character
|
||||
++$j;
|
||||
|
||||
// Successfully compared the last character
|
||||
// Add an entry with the singular suffix to the singular array
|
||||
if ($j === $suffixLength) {
|
||||
// Is there any character preceding the suffix in the plural string?
|
||||
if ($j < $pluralLength) {
|
||||
$nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]);
|
||||
|
||||
if (!$map[2] && $nextIsVocal) {
|
||||
// suffix may not succeed a vocal but next char is one
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$map[3] && !$nextIsVocal) {
|
||||
// suffix may not succeed a consonant but next char is one
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$newBase = substr($plural, 0, $pluralLength - $suffixLength);
|
||||
$newSuffix = $map[4];
|
||||
|
||||
// Check whether the first character in the plural suffix
|
||||
// is uppercased. If yes, uppercase the first character in
|
||||
// the singular suffix too
|
||||
$firstUpper = ctype_upper($pluralRev[$j - 1]);
|
||||
|
||||
if (is_array($newSuffix)) {
|
||||
$singulars = array();
|
||||
|
||||
foreach ($newSuffix as $newSuffixEntry) {
|
||||
$singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);
|
||||
}
|
||||
|
||||
return $singulars;
|
||||
}
|
||||
|
||||
return $newBase.($firstUpper ? ucFirst($newSuffix) : $newSuffix);
|
||||
}
|
||||
|
||||
// Suffix is longer than word
|
||||
if ($j === $pluralLength) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert teeth to tooth, feet to foot
|
||||
if (false !== ($pos = strpos($plural, 'ee'))) {
|
||||
return substr_replace($plural, 'oo', $pos, 2);
|
||||
}
|
||||
|
||||
// Assume that plural and singular is identical
|
||||
return $plural;
|
||||
}
|
||||
}
|
||||
31
vendor/symfony/property-access/Symfony/Component/PropertyAccess/composer.json
vendored
Normal file
31
vendor/symfony/property-access/Symfony/Component/PropertyAccess/composer.json
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "symfony/property-access",
|
||||
"type": "library",
|
||||
"description": "Symfony PropertyAccess Component",
|
||||
"keywords": ["property", "index", "access", "object", "array", "extraction", "injection", "reflection", "property path"],
|
||||
"homepage": "http://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "Symfony\\Component\\PropertyAccess\\": "" }
|
||||
},
|
||||
"target-dir": "Symfony/Component/PropertyAccess",
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user