diff options
author | Phie <phie@phie.ovh> | 2018-08-21 18:39:12 +0300 |
---|---|---|
committer | Phie <phie@phie.ovh> | 2018-08-21 18:39:12 +0300 |
commit | 7d24cc0120859fc4e46b301c08effc97ddfbb1bb (patch) | |
tree | 94b5b52074022ceccd4c91073f217feaec38ca40 /vendor/myclabs |
first commit for Carnet NC server
Diffstat (limited to 'vendor/myclabs')
47 files changed, 1633 insertions, 0 deletions
diff --git a/vendor/myclabs/deep-copy/.gitattributes b/vendor/myclabs/deep-copy/.gitattributes new file mode 100755 index 0000000..8018068 --- /dev/null +++ b/vendor/myclabs/deep-copy/.gitattributes @@ -0,0 +1,7 @@ +# Auto detect text files and perform LF normalization +* text=auto + +*.png binary + +tests/ export-ignore +phpunit.xml.dist export-ignore diff --git a/vendor/myclabs/deep-copy/.gitignore b/vendor/myclabs/deep-copy/.gitignore new file mode 100755 index 0000000..eef72f7 --- /dev/null +++ b/vendor/myclabs/deep-copy/.gitignore @@ -0,0 +1,3 @@ +/composer.phar +/composer.lock +/vendor/* diff --git a/vendor/myclabs/deep-copy/.scrutinizer.yml b/vendor/myclabs/deep-copy/.scrutinizer.yml new file mode 100644 index 0000000..6934299 --- /dev/null +++ b/vendor/myclabs/deep-copy/.scrutinizer.yml @@ -0,0 +1,4 @@ +build: + environment: + variables: + COMPOSER_ROOT_VERSION: '1.8.0' diff --git a/vendor/myclabs/deep-copy/.travis.yml b/vendor/myclabs/deep-copy/.travis.yml new file mode 100755 index 0000000..88f9d2e --- /dev/null +++ b/vendor/myclabs/deep-copy/.travis.yml @@ -0,0 +1,40 @@ +language: php + +sudo: false + +env: + global: + - COMPOSER_ROOT_VERSION=1.8.0 + +php: + - '7.1' + - '7.2' + - nightly + +matrix: + fast_finish: true + include: + - php: '7.1' + env: COMPOSER_FLAGS="--prefer-lowest" + allow_failures: + - php: nightly + +cache: + directories: + - $HOME/.composer/cache/files + +install: + - composer update --no-interaction --no-progress --no-suggest --prefer-dist $COMPOSER_FLAGS + - wget https://github.com/satooshi/php-coveralls/releases/download/v1.0.0/coveralls.phar + +before_script: + - mkdir -p build/logs + +script: + - vendor/bin/phpunit --coverage-clover build/logs/clover.xml + +after_script: + - php coveralls.phar -v + +notifications: + email: false diff --git a/vendor/myclabs/deep-copy/LICENSE b/vendor/myclabs/deep-copy/LICENSE new file mode 100644 index 0000000..c3e8350 --- /dev/null +++ b/vendor/myclabs/deep-copy/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 My C-Sense + +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. diff --git a/vendor/myclabs/deep-copy/README.md b/vendor/myclabs/deep-copy/README.md new file mode 100644 index 0000000..7abe5dc --- /dev/null +++ b/vendor/myclabs/deep-copy/README.md @@ -0,0 +1,376 @@ +# DeepCopy + +DeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph. + +[![Build Status](https://travis-ci.org/myclabs/DeepCopy.png?branch=1.x)](https://travis-ci.org/myclabs/DeepCopy) +[![Coverage Status](https://coveralls.io/repos/myclabs/DeepCopy/badge.png?branch=1.x)](https://coveralls.io/r/myclabs/DeepCopy?branch=1.x) +[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/myclabs/DeepCopy/badges/quality-score.png?s=2747100c19b275f93a777e3297c6c12d1b68b934)](https://scrutinizer-ci.com/g/myclabs/DeepCopy/) +[![Total Downloads](https://poser.pugx.org/myclabs/deep-copy/downloads.svg)](https://packagist.org/packages/myclabs/deep-copy) + + +**You are browsing the 1.x version, this version is in maintenance mode only. Please check the new +[2.x](https://github.com/myclabs/DeepCopy/tree/2.x) version.** + + +## Table of Contents + +1. [How](#how) +1. [Why](#why) + 1. [Using simply `clone`](#using-simply-clone) + 1. [Overridding `__clone()`](#overridding-__clone) + 1. [With `DeepCopy`](#with-deepcopy) +1. [How it works](#how-it-works) +1. [Going further](#going-further) + 1. [Matchers](#matchers) + 1. [Property name](#property-name) + 1. [Specific property](#specific-property) + 1. [Type](#type) + 1. [Filters](#filters) + 1. [`SetNullFilter`](#setnullfilter-filter) + 1. [`KeepFilter`](#keepfilter-filter) + 1. [`DoctrineCollectionFilter`](#doctrinecollectionfilter-filter) + 1. [`DoctrineEmptyCollectionFilter`](#doctrineemptycollectionfilter-filter) + 1. [`DoctrineProxyFilter`](#doctrineproxyfilter-filter) + 1. [`ReplaceFilter`](#replacefilter-type-filter) + 1. [`ShallowCopyFilter`](#shallowcopyfilter-type-filter) +1. [Edge cases](#edge-cases) +1. [Contributing](#contributing) + 1. [Tests](#tests) + + +## How? + +Install with Composer: + +```json +composer require myclabs/deep-copy +``` + +Use simply: + +```php +use DeepCopy\DeepCopy; + +$copier = new DeepCopy(); +$myCopy = $copier->copy($myObject); +``` + + +## Why? + +- How do you create copies of your objects? + +```php +$myCopy = clone $myObject; +``` + +- How do you create **deep** copies of your objects (i.e. copying also all the objects referenced in the properties)? + +You use [`__clone()`](http://www.php.net/manual/en/language.oop5.cloning.php#object.clone) and implement the behavior +yourself. + +- But how do you handle **cycles** in the association graph? + +Now you're in for a big mess :( + +![association graph](doc/graph.png) + + +### Using simply `clone` + +![Using clone](doc/clone.png) + + +### Overridding `__clone()` + +![Overridding __clone](doc/deep-clone.png) + + +### With `DeepCopy` + +![With DeepCopy](doc/deep-copy.png) + + +## How it works + +DeepCopy recursively traverses all the object's properties and clones them. To avoid cloning the same object twice it +keeps a hash map of all instances and thus preserves the object graph. + +To use it: + +```php +use function DeepCopy\deep_copy; + +$copy = deep_copy($var); +``` + +Alternatively, you can create your own `DeepCopy` instance to configure it differently for example: + +```php +use DeepCopy\DeepCopy; + +$copier = new DeepCopy(true); + +$copy = $copier->copy($var); +``` + +You may want to roll your own deep copy function: + +```php +namespace Acme; + +use DeepCopy\DeepCopy; + +function deep_copy($var) +{ + static $copier = null; + + if (null === $copier) { + $copier = new DeepCopy(true); + } + + return $copier->copy($var); +} +``` + + +## Going further + +You can add filters to customize the copy process. + +The method to add a filter is `DeepCopy\DeepCopy::addFilter($filter, $matcher)`, +with `$filter` implementing `DeepCopy\Filter\Filter` +and `$matcher` implementing `DeepCopy\Matcher\Matcher`. + +We provide some generic filters and matchers. + + +### Matchers + + - `DeepCopy\Matcher` applies on a object attribute. + - `DeepCopy\TypeMatcher` applies on any element found in graph, including array elements. + + +#### Property name + +The `PropertyNameMatcher` will match a property by its name: + +```php +use DeepCopy\Matcher\PropertyNameMatcher; + +// Will apply a filter to any property of any objects named "id" +$matcher = new PropertyNameMatcher('id'); +``` + + +#### Specific property + +The `PropertyMatcher` will match a specific property of a specific class: + +```php +use DeepCopy\Matcher\PropertyMatcher; + +// Will apply a filter to the property "id" of any objects of the class "MyClass" +$matcher = new PropertyMatcher('MyClass', 'id'); +``` + + +#### Type + +The `TypeMatcher` will match any element by its type (instance of a class or any value that could be parameter of +[gettype()](http://php.net/manual/en/function.gettype.php) function): + +```php +use DeepCopy\TypeMatcher\TypeMatcher; + +// Will apply a filter to any object that is an instance of Doctrine\Common\Collections\Collection +$matcher = new TypeMatcher('Doctrine\Common\Collections\Collection'); +``` + + +### Filters + +- `DeepCopy\Filter` applies a transformation to the object attribute matched by `DeepCopy\Matcher` +- `DeepCopy\TypeFilter` applies a transformation to any element matched by `DeepCopy\TypeMatcher` + + +#### `SetNullFilter` (filter) + +Let's say for example that you are copying a database record (or a Doctrine entity), so you want the copy not to have +any ID: + +```php +use DeepCopy\DeepCopy; +use DeepCopy\Filter\SetNullFilter; +use DeepCopy\Matcher\PropertyNameMatcher; + +$object = MyClass::load(123); +echo $object->id; // 123 + +$copier = new DeepCopy(); +$copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id')); + +$copy = $copier->copy($object); + +echo $copy->id; // null +``` + + +#### `KeepFilter` (filter) + +If you want a property to remain untouched (for example, an association to an object): + +```php +use DeepCopy\DeepCopy; +use DeepCopy\Filter\KeepFilter; +use DeepCopy\Matcher\PropertyMatcher; + +$copier = new DeepCopy(); +$copier->addFilter(new KeepFilter(), new PropertyMatcher('MyClass', 'category')); + +$copy = $copier->copy($object); +// $copy->category has not been touched +``` + + +#### `DoctrineCollectionFilter` (filter) + +If you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`: + +```php +use DeepCopy\DeepCopy; +use DeepCopy\Filter\Doctrine\DoctrineCollectionFilter; +use DeepCopy\Matcher\PropertyTypeMatcher; + +$copier = new DeepCopy(); +$copier->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection')); + +$copy = $copier->copy($object); +``` + + +#### `DoctrineEmptyCollectionFilter` (filter) + +If you use Doctrine and want to copy an entity who contains a `Collection` that you want to be reset, you can use the +`DoctrineEmptyCollectionFilter` + +```php +use DeepCopy\DeepCopy; +use DeepCopy\Filter\Doctrine\DoctrineEmptyCollectionFilter; +use DeepCopy\Matcher\PropertyMatcher; + +$copier = new DeepCopy(); +$copier->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty')); + +$copy = $copier->copy($object); + +// $copy->myProperty will return an empty collection +``` + + +#### `DoctrineProxyFilter` (filter) + +If you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a +Doctrine proxy class (...\\\_\_CG\_\_\Proxy). +You can use the `DoctrineProxyFilter` to load the actual entity behind the Doctrine proxy class. +**Make sure, though, to put this as one of your very first filters in the filter chain so that the entity is loaded +before other filters are applied!** + +```php +use DeepCopy\DeepCopy; +use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; +use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; + +$copier = new DeepCopy(); +$copier->addFilter(new DoctrineProxyFilter(), new DoctrineProxyMatcher()); + +$copy = $copier->copy($object); + +// $copy should now contain a clone of all entities, including those that were not yet fully loaded. +``` + + +#### `ReplaceFilter` (type filter) + +1. If you want to replace the value of a property: + +```php +use DeepCopy\DeepCopy; +use DeepCopy\Filter\ReplaceFilter; +use DeepCopy\Matcher\PropertyMatcher; + +$copier = new DeepCopy(); +$callback = function ($currentValue) { + return $currentValue . ' (copy)' +}; +$copier->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title')); + +$copy = $copier->copy($object); + +// $copy->title will contain the data returned by the callback, e.g. 'The title (copy)' +``` + +2. If you want to replace whole element: + +```php +use DeepCopy\DeepCopy; +use DeepCopy\TypeFilter\ReplaceFilter; +use DeepCopy\TypeMatcher\TypeMatcher; + +$copier = new DeepCopy(); +$callback = function (MyClass $myClass) { + return get_class($myClass); +}; +$copier->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass')); + +$copy = $copier->copy([new MyClass, 'some string', new MyClass]); + +// $copy will contain ['MyClass', 'some string', 'MyClass'] +``` + + +The `$callback` parameter of the `ReplaceFilter` constructor accepts any PHP callable. + + +#### `ShallowCopyFilter` (type filter) + +Stop *DeepCopy* from recursively copying element, using standard `clone` instead: + +```php +use DeepCopy\DeepCopy; +use DeepCopy\TypeFilter\ShallowCopyFilter; +use DeepCopy\TypeMatcher\TypeMatcher; +use Mockery as m; + +$this->deepCopy = new DeepCopy(); +$this->deepCopy->addTypeFilter( + new ShallowCopyFilter, + new TypeMatcher(m\MockInterface::class) +); + +$myServiceWithMocks = new MyService(m::mock(MyDependency1::class), m::mock(MyDependency2::class)); +// All mocks will be just cloned, not deep copied +``` + + +## Edge cases + +The following structures cannot be deep-copied with PHP Reflection. As a result they are shallow cloned and filters are +not applied. There is two ways for you to handle them: + +- Implement your own `__clone()` method +- Use a filter with a type matcher + + +## Contributing + +DeepCopy is distributed under the MIT license. + + +### Tests + +Running the tests is simple: + +```php +vendor/bin/phpunit +``` diff --git a/vendor/myclabs/deep-copy/composer.json b/vendor/myclabs/deep-copy/composer.json new file mode 100644 index 0000000..4108a23 --- /dev/null +++ b/vendor/myclabs/deep-copy/composer.json @@ -0,0 +1,38 @@ +{ + "name": "myclabs/deep-copy", + "type": "library", + "description": "Create deep copies (clones) of your objects", + "keywords": ["clone", "copy", "duplicate", "object", "object graph"], + "license": "MIT", + + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "autoload-dev": { + "psr-4": { + "DeepCopy\\": "fixtures/", + "DeepCopyTest\\": "tests/DeepCopyTest/" + } + }, + + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + + "config": { + "sort-packages": true + } +} diff --git a/vendor/myclabs/deep-copy/doc/clone.png b/vendor/myclabs/deep-copy/doc/clone.png Binary files differnew file mode 100644 index 0000000..376afd4 --- /dev/null +++ b/vendor/myclabs/deep-copy/doc/clone.png diff --git a/vendor/myclabs/deep-copy/doc/deep-clone.png b/vendor/myclabs/deep-copy/doc/deep-clone.png Binary files differnew file mode 100644 index 0000000..2b37a6d --- /dev/null +++ b/vendor/myclabs/deep-copy/doc/deep-clone.png diff --git a/vendor/myclabs/deep-copy/doc/deep-copy.png b/vendor/myclabs/deep-copy/doc/deep-copy.png Binary files differnew file mode 100644 index 0000000..68c508a --- /dev/null +++ b/vendor/myclabs/deep-copy/doc/deep-copy.png diff --git a/vendor/myclabs/deep-copy/doc/graph.png b/vendor/myclabs/deep-copy/doc/graph.png Binary files differnew file mode 100644 index 0000000..4d5c942 --- /dev/null +++ b/vendor/myclabs/deep-copy/doc/graph.png diff --git a/vendor/myclabs/deep-copy/fixtures/f001/A.php b/vendor/myclabs/deep-copy/fixtures/f001/A.php new file mode 100644 index 0000000..648d5df --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f001/A.php @@ -0,0 +1,20 @@ +<?php + +namespace DeepCopy\f001; + +class A +{ + private $aProp; + + public function getAProp() + { + return $this->aProp; + } + + public function setAProp($prop) + { + $this->aProp = $prop; + + return $this; + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f001/B.php b/vendor/myclabs/deep-copy/fixtures/f001/B.php new file mode 100644 index 0000000..462bb44 --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f001/B.php @@ -0,0 +1,20 @@ +<?php + +namespace DeepCopy\f001; + +class B extends A +{ + private $bProp; + + public function getBProp() + { + return $this->bProp; + } + + public function setBProp($prop) + { + $this->bProp = $prop; + + return $this; + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f002/A.php b/vendor/myclabs/deep-copy/fixtures/f002/A.php new file mode 100644 index 0000000..d9aa5c3 --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f002/A.php @@ -0,0 +1,33 @@ +<?php + +namespace DeepCopy\f002; + +class A +{ + private $prop1; + private $prop2; + + public function getProp1() + { + return $this->prop1; + } + + public function setProp1($prop) + { + $this->prop1 = $prop; + + return $this; + } + + public function getProp2() + { + return $this->prop2; + } + + public function setProp2($prop) + { + $this->prop2 = $prop; + + return $this; + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f003/Foo.php b/vendor/myclabs/deep-copy/fixtures/f003/Foo.php new file mode 100644 index 0000000..9cd7622 --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f003/Foo.php @@ -0,0 +1,26 @@ +<?php + +namespace DeepCopy\f003; + +class Foo +{ + private $name; + private $prop; + + public function __construct($name) + { + $this->name = $name; + } + + public function getProp() + { + return $this->prop; + } + + public function setProp($prop) + { + $this->prop = $prop; + + return $this; + } +}
\ No newline at end of file diff --git a/vendor/myclabs/deep-copy/fixtures/f004/UnclonableItem.php b/vendor/myclabs/deep-copy/fixtures/f004/UnclonableItem.php new file mode 100644 index 0000000..82c6c67 --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f004/UnclonableItem.php @@ -0,0 +1,13 @@ +<?php + +namespace DeepCopy\f004; + +use BadMethodCallException; + +class UnclonableItem +{ + private function __clone() + { + throw new BadMethodCallException('Unsupported call.'); + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f005/Foo.php b/vendor/myclabs/deep-copy/fixtures/f005/Foo.php new file mode 100644 index 0000000..a4c86c6 --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f005/Foo.php @@ -0,0 +1,13 @@ +<?php + +namespace DeepCopy\f005; + +class Foo +{ + public $cloned = false; + + public function __clone() + { + $this->cloned = true; + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f006/A.php b/vendor/myclabs/deep-copy/fixtures/f006/A.php new file mode 100644 index 0000000..d9efb11 --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f006/A.php @@ -0,0 +1,26 @@ +<?php + +namespace DeepCopy\f006; + +class A +{ + public $cloned = false; + private $aProp; + + public function getAProp() + { + return $this->aProp; + } + + public function setAProp($prop) + { + $this->aProp = $prop; + + return $this; + } + + public function __clone() + { + $this->cloned = true; + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f006/B.php b/vendor/myclabs/deep-copy/fixtures/f006/B.php new file mode 100644 index 0000000..1f80b3d --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f006/B.php @@ -0,0 +1,26 @@ +<?php + +namespace DeepCopy\f006; + +class B +{ + public $cloned = false; + private $bProp; + + public function getBProp() + { + return $this->bProp; + } + + public function setBProp($prop) + { + $this->bProp = $prop; + + return $this; + } + + public function __clone() + { + $this->cloned = true; + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f007/FooDateInterval.php b/vendor/myclabs/deep-copy/fixtures/f007/FooDateInterval.php new file mode 100644 index 0000000..e16bc6a --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f007/FooDateInterval.php @@ -0,0 +1,15 @@ +<?php + +namespace DeepCopy\f007; + +use DateInterval; + +class FooDateInterval extends DateInterval +{ + public $cloned = false; + + public function __clone() + { + $this->cloned = true; + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f007/FooDateTimeZone.php b/vendor/myclabs/deep-copy/fixtures/f007/FooDateTimeZone.php new file mode 100644 index 0000000..6f4e61f --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f007/FooDateTimeZone.php @@ -0,0 +1,15 @@ +<?php + +namespace DeepCopy\f007; + +use DateTimeZone; + +class FooDateTimeZone extends DateTimeZone +{ + public $cloned = false; + + public function __clone() + { + $this->cloned = true; + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f008/A.php b/vendor/myclabs/deep-copy/fixtures/f008/A.php new file mode 100644 index 0000000..88471d0 --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f008/A.php @@ -0,0 +1,18 @@ +<?php + +namespace DeepCopy\f008; + +class A +{ + private $foo; + + public function __construct($foo) + { + $this->foo = $foo; + } + + public function getFoo() + { + return $this->foo; + } +} diff --git a/vendor/myclabs/deep-copy/fixtures/f008/B.php b/vendor/myclabs/deep-copy/fixtures/f008/B.php new file mode 100644 index 0000000..6053092 --- /dev/null +++ b/vendor/myclabs/deep-copy/fixtures/f008/B.php @@ -0,0 +1,7 @@ +<?php + +namespace DeepCopy\f008; + +class B extends A +{ +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php b/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php new file mode 100644 index 0000000..d461ff6 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php @@ -0,0 +1,281 @@ +<?php + +namespace DeepCopy; + +use DateInterval; +use DateTimeInterface; +use DateTimeZone; +use DeepCopy\Exception\CloneException; +use DeepCopy\Filter\Filter; +use DeepCopy\Matcher\Matcher; +use DeepCopy\TypeFilter\Date\DateIntervalFilter; +use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter; +use DeepCopy\TypeFilter\TypeFilter; +use DeepCopy\TypeMatcher\TypeMatcher; +use ReflectionObject; +use ReflectionProperty; +use DeepCopy\Reflection\ReflectionHelper; +use SplDoublyLinkedList; + +/** + * @final + */ +class DeepCopy +{ + /** + * @var object[] List of objects copied. + */ + private $hashMap = []; + + /** + * Filters to apply. + * + * @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs. + */ + private $filters = []; + + /** + * Type Filters to apply. + * + * @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs. + */ + private $typeFilters = []; + + /** + * @var bool + */ + private $skipUncloneable = false; + + /** + * @var bool + */ + private $useCloneMethod; + + /** + * @param bool $useCloneMethod If set to true, when an object implements the __clone() function, it will be used + * instead of the regular deep cloning. + */ + public function __construct($useCloneMethod = false) + { + $this->useCloneMethod = $useCloneMethod; + + $this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class)); + $this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class)); + } + + /** + * If enabled, will not throw an exception when coming across an uncloneable property. + * + * @param $skipUncloneable + * + * @return $this + */ + public function skipUncloneable($skipUncloneable = true) + { + $this->skipUncloneable = $skipUncloneable; + + return $this; + } + + /** + * Deep copies the given object. + * + * @param mixed $object + * + * @return mixed + */ + public function copy($object) + { + $this->hashMap = []; + + return $this->recursiveCopy($object); + } + + public function addFilter(Filter $filter, Matcher $matcher) + { + $this->filters[] = [ + 'matcher' => $matcher, + 'filter' => $filter, + ]; + } + + public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher) + { + $this->typeFilters[] = [ + 'matcher' => $matcher, + 'filter' => $filter, + ]; + } + + private function recursiveCopy($var) + { + // Matches Type Filter + if ($filter = $this->getFirstMatchedTypeFilter($this->typeFilters, $var)) { + return $filter->apply($var); + } + + // Resource + if (is_resource($var)) { + return $var; + } + + // Array + if (is_array($var)) { + return $this->copyArray($var); + } + + // Scalar + if (! is_object($var)) { + return $var; + } + + // Object + return $this->copyObject($var); + } + + /** + * Copy an array + * @param array $array + * @return array + */ + private function copyArray(array $array) + { + foreach ($array as $key => $value) { + $array[$key] = $this->recursiveCopy($value); + } + + return $array; + } + + /** + * Copies an object. + * + * @param object $object + * + * @throws CloneException + * + * @return object + */ + private function copyObject($object) + { + $objectHash = spl_object_hash($object); + + if (isset($this->hashMap[$objectHash])) { + return $this->hashMap[$objectHash]; + } + + $reflectedObject = new ReflectionObject($object); + $isCloneable = $reflectedObject->isCloneable(); + + if (false === $isCloneable) { + if ($this->skipUncloneable) { + $this->hashMap[$objectHash] = $object; + + return $object; + } + + throw new CloneException( + sprintf( + 'The class "%s" is not cloneable.', + $reflectedObject->getName() + ) + ); + } + + $newObject = clone $object; + $this->hashMap[$objectHash] = $newObject; + + if ($this->useCloneMethod && $reflectedObject->hasMethod('__clone')) { + return $newObject; + } + + if ($newObject instanceof DateTimeInterface || $newObject instanceof DateTimeZone) { + return $newObject; + } + + foreach (ReflectionHelper::getProperties($reflectedObject) as $property) { + $this->copyObjectProperty($newObject, $property); + } + + return $newObject; + } + + private function copyObjectProperty($object, ReflectionProperty $property) + { + // Ignore static properties + if ($property->isStatic()) { + return; + } + + // Apply the filters + foreach ($this->filters as $item) { + /** @var Matcher $matcher */ + $matcher = $item['matcher']; + /** @var Filter $filter */ + $filter = $item['filter']; + + if ($matcher->matches($object, $property->getName())) { + $filter->apply( + $object, + $property->getName(), + function ($object) { + return $this->recursiveCopy($object); + } + ); + + // If a filter matches, we stop processing this property + return; + } + } + + $property->setAccessible(true); + $propertyValue = $property->getValue($object); + + // Copy the property + $property->setValue($object, $this->recursiveCopy($propertyValue)); + } + + /** + * Returns first filter that matches variable, `null` if no such filter found. + * + * @param array $filterRecords Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and + * 'matcher' with value of type {@see TypeMatcher} + * @param mixed $var + * + * @return TypeFilter|null + */ + private function getFirstMatchedTypeFilter(array $filterRecords, $var) + { + $matched = $this->first( + $filterRecords, + function (array $record) use ($var) { + /* @var TypeMatcher $matcher */ + $matcher = $record['matcher']; + + return $matcher->matches($var); + } + ); + + return isset($matched) ? $matched['filter'] : null; + } + + /** + * Returns first element that matches predicate, `null` if no such element found. + * + * @param array $elements Array of ['filter' => Filter, 'matcher' => Matcher] pairs. + * @param callable $predicate Predicate arguments are: element. + * + * @return array|null Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and 'matcher' + * with value of type {@see TypeMatcher} or `null`. + */ + private function first(array $elements, callable $predicate) + { + foreach ($elements as $element) { + if (call_user_func($predicate, $element)) { + return $element; + } + } + + return null; + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php b/vendor/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php new file mode 100644 index 0000000..c046706 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php @@ -0,0 +1,9 @@ +<?php + +namespace DeepCopy\Exception; + +use UnexpectedValueException; + +class CloneException extends UnexpectedValueException +{ +}
\ No newline at end of file diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.php b/vendor/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.php new file mode 100644 index 0000000..9702101 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.php @@ -0,0 +1,9 @@ +<?php + +namespace DeepCopy\Exception; + +use ReflectionException; + +class PropertyException extends ReflectionException +{ +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php new file mode 100644 index 0000000..e6d9377 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php @@ -0,0 +1,33 @@ +<?php + +namespace DeepCopy\Filter\Doctrine; + +use DeepCopy\Filter\Filter; +use DeepCopy\Reflection\ReflectionHelper; + +/** + * @final + */ +class DoctrineCollectionFilter implements Filter +{ + /** + * Copies the object property doctrine collection. + * + * {@inheritdoc} + */ + public function apply($object, $property, $objectCopier) + { + $reflectionProperty = ReflectionHelper::getProperty($object, $property); + + $reflectionProperty->setAccessible(true); + $oldCollection = $reflectionProperty->getValue($object); + + $newCollection = $oldCollection->map( + function ($item) use ($objectCopier) { + return $objectCopier($item); + } + ); + + $reflectionProperty->setValue($object, $newCollection); + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php new file mode 100644 index 0000000..7b33fd5 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php @@ -0,0 +1,28 @@ +<?php + +namespace DeepCopy\Filter\Doctrine; + +use DeepCopy\Filter\Filter; +use DeepCopy\Reflection\ReflectionHelper; +use Doctrine\Common\Collections\ArrayCollection; + +/** + * @final + */ +class DoctrineEmptyCollectionFilter implements Filter +{ + /** + * Sets the object property to an empty doctrine collection. + * + * @param object $object + * @param string $property + * @param callable $objectCopier + */ + public function apply($object, $property, $objectCopier) + { + $reflectionProperty = ReflectionHelper::getProperty($object, $property); + $reflectionProperty->setAccessible(true); + + $reflectionProperty->setValue($object, new ArrayCollection()); + } +}
\ No newline at end of file diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php new file mode 100644 index 0000000..8bee8f7 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php @@ -0,0 +1,22 @@ +<?php + +namespace DeepCopy\Filter\Doctrine; + +use DeepCopy\Filter\Filter; + +/** + * @final + */ +class DoctrineProxyFilter implements Filter +{ + /** + * Triggers the magic method __load() on a Doctrine Proxy class to load the + * actual entity from the database. + * + * {@inheritdoc} + */ + public function apply($object, $property, $objectCopier) + { + $object->__load(); + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Filter.php b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Filter.php new file mode 100644 index 0000000..85ba18c --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Filter.php @@ -0,0 +1,18 @@ +<?php + +namespace DeepCopy\Filter; + +/** + * Filter to apply to a property while copying an object + */ +interface Filter +{ + /** + * Applies the filter to the object. + * + * @param object $object + * @param string $property + * @param callable $objectCopier + */ + public function apply($object, $property, $objectCopier); +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Filter/KeepFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/KeepFilter.php new file mode 100644 index 0000000..4b11a08 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/KeepFilter.php @@ -0,0 +1,16 @@ +<?php + +namespace DeepCopy\Filter; + +class KeepFilter implements Filter +{ + /** + * Keeps the value of the object property. + * + * {@inheritdoc} + */ + public function apply($object, $property, $objectCopier) + { + // Nothing to do + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php new file mode 100644 index 0000000..7aca593 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php @@ -0,0 +1,39 @@ +<?php + +namespace DeepCopy\Filter; + +use DeepCopy\Reflection\ReflectionHelper; + +/** + * @final + */ +class ReplaceFilter implements Filter +{ + /** + * @var callable + */ + protected $callback; + + /** + * @param callable $callable Will be called to get the new value for each property to replace + */ + public function __construct(callable $callable) + { + $this->callback = $callable; + } + + /** + * Replaces the object property by the result of the callback called with the object property. + * + * {@inheritdoc} + */ + public function apply($object, $property, $objectCopier) + { + $reflectionProperty = ReflectionHelper::getProperty($object, $property); + $reflectionProperty->setAccessible(true); + + $value = call_user_func($this->callback, $reflectionProperty->getValue($object)); + + $reflectionProperty->setValue($object, $value); + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php new file mode 100644 index 0000000..bea86b8 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php @@ -0,0 +1,24 @@ +<?php + +namespace DeepCopy\Filter; + +use DeepCopy\Reflection\ReflectionHelper; + +/** + * @final + */ +class SetNullFilter implements Filter +{ + /** + * Sets the object property to null. + * + * {@inheritdoc} + */ + public function apply($object, $property, $objectCopier) + { + $reflectionProperty = ReflectionHelper::getProperty($object, $property); + + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($object, null); + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php new file mode 100644 index 0000000..ec8856f --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php @@ -0,0 +1,22 @@ +<?php + +namespace DeepCopy\Matcher\Doctrine; + +use DeepCopy\Matcher\Matcher; +use Doctrine\Common\Persistence\Proxy; + +/** + * @final + */ +class DoctrineProxyMatcher implements Matcher +{ + /** + * Matches a Doctrine Proxy class. + * + * {@inheritdoc} + */ + public function matches($object, $property) + { + return $object instanceof Proxy; + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Matcher.php b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Matcher.php new file mode 100644 index 0000000..d67f3ca --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Matcher.php @@ -0,0 +1,14 @@ +<?php + +namespace DeepCopy\Matcher; + +interface Matcher +{ + /** + * @param object $object + * @param string $property + * + * @return boolean + */ + public function matches($object, $property); +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyMatcher.php b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyMatcher.php new file mode 100644 index 0000000..073b20c --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyMatcher.php @@ -0,0 +1,39 @@ +<?php + +namespace DeepCopy\Matcher; + +/** + * @final + */ +class PropertyMatcher implements Matcher +{ + /** + * @var string + */ + private $class; + + /** + * @var string + */ + private $property; + + /** + * @param string $class Class name + * @param string $property Property name + */ + public function __construct($class, $property) + { + $this->class = $class; + $this->property = $property; + } + + /** + * Matches a specific property of a specific class. + * + * {@inheritdoc} + */ + public function matches($object, $property) + { + return ($object instanceof $this->class) && $property == $this->property; + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php new file mode 100644 index 0000000..c8ec0d2 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php @@ -0,0 +1,32 @@ +<?php + +namespace DeepCopy\Matcher; + +/** + * @final + */ +class PropertyNameMatcher implements Matcher +{ + /** + * @var string + */ + private $property; + + /** + * @param string $property Property name + */ + public function __construct($property) + { + $this->property = $property; + } + + /** + * Matches a property by its name. + * + * {@inheritdoc} + */ + public function matches($object, $property) + { + return $property == $this->property; + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php new file mode 100644 index 0000000..a6b0c0b --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php @@ -0,0 +1,46 @@ +<?php + +namespace DeepCopy\Matcher; + +use DeepCopy\Reflection\ReflectionHelper; +use ReflectionException; + +/** + * Matches a property by its type. + * + * It is recommended to use {@see DeepCopy\TypeFilter\TypeFilter} instead, as it applies on all occurrences + * of given type in copied context (eg. array elements), not just on object properties. + * + * @final + */ +class PropertyTypeMatcher implements Matcher +{ + /** + * @var string + */ + private $propertyType; + + /** + * @param string $propertyType Property type + */ + public function __construct($propertyType) + { + $this->propertyType = $propertyType; + } + + /** + * {@inheritdoc} + */ + public function matches($object, $property) + { + try { + $reflectionProperty = ReflectionHelper::getProperty($object, $property); + } catch (ReflectionException $exception) { + return false; + } + + $reflectionProperty->setAccessible(true); + + return $reflectionProperty->getValue($object) instanceof $this->propertyType; + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php b/vendor/myclabs/deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php new file mode 100644 index 0000000..742410c --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php @@ -0,0 +1,78 @@ +<?php + +namespace DeepCopy\Reflection; + +use DeepCopy\Exception\PropertyException; +use ReflectionClass; +use ReflectionException; +use ReflectionObject; +use ReflectionProperty; + +class ReflectionHelper +{ + /** + * Retrieves all properties (including private ones), from object and all its ancestors. + * + * Standard \ReflectionClass->getProperties() does not return private properties from ancestor classes. + * + * @author muratyaman@gmail.com + * @see http://php.net/manual/en/reflectionclass.getproperties.php + * + * @param ReflectionClass $ref + * + * @return ReflectionProperty[] + */ + public static function getProperties(ReflectionClass $ref) + { + $props = $ref->getProperties(); + $propsArr = array(); + + foreach ($props as $prop) { + $propertyName = $prop->getName(); + $propsArr[$propertyName] = $prop; + } + + if ($parentClass = $ref->getParentClass()) { + $parentPropsArr = self::getProperties($parentClass); + foreach ($propsArr as $key => $property) { + $parentPropsArr[$key] = $property; + } + + return $parentPropsArr; + } + + return $propsArr; + } + + /** + * Retrieves property by name from object and all its ancestors. + * + * @param object|string $object + * @param string $name + * + * @throws PropertyException + * @throws ReflectionException + * + * @return ReflectionProperty + */ + public static function getProperty($object, $name) + { + $reflection = is_object($object) ? new ReflectionObject($object) : new ReflectionClass($object); + + if ($reflection->hasProperty($name)) { + return $reflection->getProperty($name); + } + + if ($parentClass = $reflection->getParentClass()) { + return self::getProperty($parentClass->getName(), $name); + } + + throw new PropertyException( + sprintf( + 'The class "%s" doesn\'t have a property with the given name: "%s".', + is_object($object) ? get_class($object) : $object, + $name + ) + ); + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php new file mode 100644 index 0000000..becd1cf --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php @@ -0,0 +1,33 @@ +<?php + +namespace DeepCopy\TypeFilter\Date; + +use DateInterval; +use DeepCopy\TypeFilter\TypeFilter; + +/** + * @final + * + * @deprecated Will be removed in 2.0. This filter will no longer be necessary in PHP 7.1+. + */ +class DateIntervalFilter implements TypeFilter +{ + + /** + * {@inheritdoc} + * + * @param DateInterval $element + * + * @see http://news.php.net/php.bugs/205076 + */ + public function apply($element) + { + $copy = new DateInterval('P0D'); + + foreach ($element as $propertyName => $propertyValue) { + $copy->{$propertyName} = $propertyValue; + } + + return $copy; + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php new file mode 100644 index 0000000..164f8b8 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php @@ -0,0 +1,30 @@ +<?php + +namespace DeepCopy\TypeFilter; + +/** + * @final + */ +class ReplaceFilter implements TypeFilter +{ + /** + * @var callable + */ + protected $callback; + + /** + * @param callable $callable Will be called to get the new value for each element to replace + */ + public function __construct(callable $callable) + { + $this->callback = $callable; + } + + /** + * {@inheritdoc} + */ + public function apply($element) + { + return call_user_func($this->callback, $element); + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php new file mode 100644 index 0000000..a5fbd7a --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php @@ -0,0 +1,17 @@ +<?php + +namespace DeepCopy\TypeFilter; + +/** + * @final + */ +class ShallowCopyFilter implements TypeFilter +{ + /** + * {@inheritdoc} + */ + public function apply($element) + { + return clone $element; + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php new file mode 100644 index 0000000..c5644cf --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php @@ -0,0 +1,10 @@ +<?php + +namespace DeepCopy\TypeFilter\Spl; + +/** + * @deprecated Use {@see SplDoublyLinkedListFilter} instead. + */ +class SplDoublyLinkedList extends SplDoublyLinkedListFilter +{ +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php new file mode 100644 index 0000000..c33be45 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php @@ -0,0 +1,51 @@ +<?php + +namespace DeepCopy\TypeFilter\Spl; + +use Closure; +use DeepCopy\DeepCopy; +use DeepCopy\TypeFilter\TypeFilter; +use SplDoublyLinkedList; + +/** + * @final + */ +class SplDoublyLinkedListFilter implements TypeFilter +{ + private $copier; + + public function __construct(DeepCopy $copier) + { + $this->copier = $copier; + } + + /** + * {@inheritdoc} + */ + public function apply($element) + { + $newElement = clone $element; + + $copy = $this->createCopyClosure(); + + return $copy($newElement); + } + + private function createCopyClosure() + { + $copier = $this->copier; + + $copy = function (SplDoublyLinkedList $list) use ($copier) { + // Replace each element in the list with a deep copy of itself + for ($i = 1; $i <= $list->count(); $i++) { + $copy = $copier->recursiveCopy($list->shift()); + + $list->push($copy); + } + + return $list; + }; + + return Closure::bind($copy, null, DeepCopy::class); + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/TypeFilter.php b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/TypeFilter.php new file mode 100644 index 0000000..5785a7d --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/TypeFilter.php @@ -0,0 +1,13 @@ +<?php + +namespace DeepCopy\TypeFilter; + +interface TypeFilter +{ + /** + * Applies the filter to the object. + * + * @param mixed $element + */ + public function apply($element); +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php b/vendor/myclabs/deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php new file mode 100644 index 0000000..a563cb2 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php @@ -0,0 +1,29 @@ +<?php + +namespace DeepCopy\TypeMatcher; + +class TypeMatcher +{ + /** + * @var string + */ + private $type; + + /** + * @param string $type + */ + public function __construct($type) + { + $this->type = $type; + } + + /** + * @param mixed $element + * + * @return boolean + */ + public function matches($element) + { + return is_object($element) ? is_a($element, $this->type) : gettype($element) === $this->type; + } +} diff --git a/vendor/myclabs/deep-copy/src/DeepCopy/deep_copy.php b/vendor/myclabs/deep-copy/src/DeepCopy/deep_copy.php new file mode 100644 index 0000000..55dcc92 --- /dev/null +++ b/vendor/myclabs/deep-copy/src/DeepCopy/deep_copy.php @@ -0,0 +1,20 @@ +<?php + +namespace DeepCopy; + +use function function_exists; + +if (false === function_exists('DeepCopy\deep_copy')) { + /** + * Deep copies the given value. + * + * @param mixed $value + * @param bool $useCloneMethod + * + * @return mixed + */ + function deep_copy($value, $useCloneMethod = false) + { + return (new DeepCopy($useCloneMethod))->copy($value); + } +} |