From 03cd01777a963e655609d2edec2a80c08c47f174 Mon Sep 17 00:00:00 2001 From: peter279k Date: Fri, 28 Aug 2020 19:05:22 +0800 Subject: [PATCH 01/20] Fix namespace and improve assertEquals --- tests/DeepCopyTest/Filter/SetNullFilterTest.php | 2 +- .../DeepCopyTest/Matcher/Doctrine/DoctrineProxyMatcherTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/DeepCopyTest/Filter/SetNullFilterTest.php b/tests/DeepCopyTest/Filter/SetNullFilterTest.php index 2f41f16..6ca7f1a 100644 --- a/tests/DeepCopyTest/Filter/SetNullFilterTest.php +++ b/tests/DeepCopyTest/Filter/SetNullFilterTest.php @@ -22,6 +22,6 @@ public function test_it_sets_the_given_property_to_null() $filter->apply($object, 'foo', null); $this->assertNull($object->foo); - $this->assertEquals('bam', $object->bim); + $this->assertSame('bam', $object->bim); } } diff --git a/tests/DeepCopyTest/Matcher/Doctrine/DoctrineProxyMatcherTest.php b/tests/DeepCopyTest/Matcher/Doctrine/DoctrineProxyMatcherTest.php index 23f8cc7..6303a4c 100644 --- a/tests/DeepCopyTest/Matcher/Doctrine/DoctrineProxyMatcherTest.php +++ b/tests/DeepCopyTest/Matcher/Doctrine/DoctrineProxyMatcherTest.php @@ -1,6 +1,6 @@ Date: Thu, 1 Oct 2020 09:36:13 +0200 Subject: [PATCH 02/20] Fix Travis warning The sudo key is deprecated and has no effect anymore --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7987cc2..902950c 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: php -sudo: false - env: global: - COMPOSER_ROOT_VERSION=1.8.0 From a3d27ba0f82e4344df003028037d232b8318fd43 Mon Sep 17 00:00:00 2001 From: Peter van der Wal Date: Thu, 12 Nov 2020 17:35:03 +0100 Subject: [PATCH 03/20] Add isInitialized check on PropertyTypeMatcher for PHP 7.4 --- fixtures/f009/TypedObjectProperty.php | 10 +++++++ src/DeepCopy/Matcher/PropertyTypeMatcher.php | 6 +++++ .../Matcher/PropertyTypeMatcherTest.php | 26 +++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 fixtures/f009/TypedObjectProperty.php diff --git a/fixtures/f009/TypedObjectProperty.php b/fixtures/f009/TypedObjectProperty.php new file mode 100644 index 0000000..b6fec59 --- /dev/null +++ b/fixtures/f009/TypedObjectProperty.php @@ -0,0 +1,10 @@ +setAccessible(true); + // Uninitialized properties (for PHP >7.4) + if (method_exists($reflectionProperty, 'isInitialized') && !$reflectionProperty->isInitialized($object)) { + // null instanceof $this->propertyType + return false; + } + return $reflectionProperty->getValue($object) instanceof $this->propertyType; } } diff --git a/tests/DeepCopyTest/Matcher/PropertyTypeMatcherTest.php b/tests/DeepCopyTest/Matcher/PropertyTypeMatcherTest.php index 25bf553..5ba58b3 100644 --- a/tests/DeepCopyTest/Matcher/PropertyTypeMatcherTest.php +++ b/tests/DeepCopyTest/Matcher/PropertyTypeMatcherTest.php @@ -2,6 +2,7 @@ namespace DeepCopyTest\Matcher; +use DeepCopy\f009; use DeepCopy\Matcher\PropertyTypeMatcher; use PHPUnit\Framework\TestCase; use stdClass; @@ -23,6 +24,31 @@ public function test_it_matches_the_given_property($object, $expected) $this->assertEquals($expected, $actual); } + /** + * @requires PHP 7.4 + */ + public function test_it_ignores_uninitialized_typed_properties() + { + $object = new f009\TypedObjectProperty(); + + $matcher = new PropertyTypeMatcher(\DateTime::class); + + $this->assertFalse($matcher->matches($object, 'date')); + } + + /** + * @requires PHP 7.4 + */ + public function test_it_matches_initialized_typed_properties() + { + $object = new f009\TypedObjectProperty(); + $object->date = new \DateTime(); + + $matcher = new PropertyTypeMatcher(\DateTime::class); + + $this->assertTrue($matcher->matches($object, 'date')); + } + public function providePairs() { $object1 = new PropertyTypeMatcherTestFixture1(); From c91958f9c1c09fd98769be38a3e9129de092cc95 Mon Sep 17 00:00:00 2001 From: Robert Fridzema Date: Thu, 3 Feb 2022 14:06:50 +0100 Subject: [PATCH 04/20] Tiny typo ;) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 007ad5b..baec62d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ DeepCopy helps you create deep copies (clones) of your objects. It is designed t 1. [How](#how) 1. [Why](#why) 1. [Using simply `clone`](#using-simply-clone) - 1. [Overridding `__clone()`](#overridding-__clone) + 1. [Overriding `__clone()`](#overriding-__clone) 1. [With `DeepCopy`](#with-deepcopy) 1. [How it works](#how-it-works) 1. [Going further](#going-further) @@ -76,9 +76,9 @@ Now you're in for a big mess :( ![Using clone](doc/clone.png) -### Overridding `__clone()` +### Overriding `__clone()` -![Overridding __clone](doc/deep-clone.png) +![Overriding __clone](doc/deep-clone.png) ### With `DeepCopy` From cd769016572e4bb18fd1b2d32487977828da9fff Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Thu, 17 Feb 2022 15:01:06 +0100 Subject: [PATCH 05/20] Move from Travis to Github Actions --- .github/workflows/ci.yaml | 105 ++++++++++++++++++++++++++++++++++++++ .travis.yml | 40 --------------- 2 files changed, 105 insertions(+), 40 deletions(-) create mode 100644 .github/workflows/ci.yaml delete mode 100755 .travis.yml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..9090248 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,105 @@ +name: "Continuous Integration" + +on: + - pull_request + - push + +jobs: + composer-json-lint: + name: "Lint composer.json" + + runs-on: "ubuntu-latest" + + strategy: + matrix: + php-version: + - "8.1" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + tools: composer-normalize + + - name: "Get composer cache directory" + id: composercache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: "Cache dependencies" + uses: actions/cache@v2 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer- + + - name: "Install dependencies" + run: "composer update --no-interaction --no-progress" + + - name: "Validate composer.json" + run: "composer validate --strict" + + - name: "Normalize composer.json" + run: "composer-normalize --dry-run" + + tests: + name: "Tests" + + runs-on: "ubuntu-latest" + + strategy: + matrix: + php-version: + - "7.1" + - "7.2" + - "7.3" + - "7.4" + - "8.0" + - "8.1" + dependencies: + - "lowest" + - "highest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "pcov" + php-version: "${{ matrix.php-version }}" + ini-values: zend.assertions=1 + + - name: "Get composer cache directory" + id: composercache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: "Cache dependencies" + uses: actions/cache@v2 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer- + + - name: "Install lowest dependencies" + if: ${{ matrix.dependencies == 'lowest' }} + run: "composer update --no-interaction --no-progress --prefer-lowest" + + - name: "Install highest dependencies" + if: ${{ matrix.dependencies == 'highest' }} + run: "composer update --no-interaction --no-progress" + + - name: "Run tests" + timeout-minutes: 3 + run: "vendor/bin/phpunit --coverage-clover build/logs/clover.xml" + + - name: "Coveralls" + if: ${{ matrix.php-version == '8.1' && matrix.dependencies == 'highest' }} + run: | + wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.5.2/php-coveralls.phar + php coveralls.phar -v diff --git a/.travis.yml b/.travis.yml deleted file mode 100755 index 902950c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,40 +0,0 @@ -language: php - -env: - global: - - COMPOSER_ROOT_VERSION=1.8.0 - -php: - - '7.1' - - '7.2' - - '7.3' - - '7.4' - - 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 From 613e77a7407b30e1896a46df48d8ca26eb05209a Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Thu, 17 Feb 2022 15:01:32 +0100 Subject: [PATCH 06/20] composer-normalize --- composer.json | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index 45656c9..24acb82 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,26 @@ { "name": "myclabs/deep-copy", - "type": "library", "description": "Create deep copies (clones) of your objects", - "keywords": ["clone", "copy", "duplicate", "object", "object graph"], "license": "MIT", - + "type": "library", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, "autoload": { "psr-4": { "DeepCopy\\": "src/DeepCopy/" @@ -19,19 +35,6 @@ "DeepCopyTest\\": "tests/DeepCopyTest/" } }, - - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" - }, - "replace": { - "myclabs/deep-copy": "self.version" - }, - "config": { "sort-packages": true } From 3391e7a3addc666ffab46e5f425a5b1cb47fa041 Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Thu, 17 Feb 2022 15:02:00 +0100 Subject: [PATCH 07/20] Remove composer invalid entries --- composer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/composer.json b/composer.json index 24acb82..2c3b62c 100644 --- a/composer.json +++ b/composer.json @@ -18,9 +18,6 @@ "doctrine/common": "^2.6", "phpunit/phpunit": "^7.1" }, - "replace": { - "myclabs/deep-copy": "self.version" - }, "autoload": { "psr-4": { "DeepCopy\\": "src/DeepCopy/" From 6ed901b9976d2f2c3bcc56bf74ba581609939f46 Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Thu, 17 Feb 2022 15:36:49 +0100 Subject: [PATCH 08/20] Adapt test to new tools --- .gitignore | 1 + composer.json | 6 +++--- tests/DeepCopyTest/Reflection/ReflectionHelperTest.php | 5 ++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index eef72f7..dcb61b9 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /composer.phar /composer.lock /vendor/* +.phpunit.result.cache diff --git a/composer.json b/composer.json index 2c3b62c..c6278f2 100644 --- a/composer.json +++ b/composer.json @@ -14,9 +14,9 @@ "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "doctrine/collections": "^1.6", + "doctrine/common": "^2.13", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" }, "autoload": { "psr-4": { diff --git a/tests/DeepCopyTest/Reflection/ReflectionHelperTest.php b/tests/DeepCopyTest/Reflection/ReflectionHelperTest.php index 9b2f2e3..8935f57 100644 --- a/tests/DeepCopyTest/Reflection/ReflectionHelperTest.php +++ b/tests/DeepCopyTest/Reflection/ReflectionHelperTest.php @@ -2,6 +2,7 @@ namespace DeepCopyTest\Reflection; +use DeepCopy\Exception\PropertyException; use DeepCopy\Reflection\ReflectionHelper; use PHPUnit\Framework\TestCase; use ReflectionClass; @@ -60,13 +61,11 @@ public function provideProperties() ]; } - /** - * @expectedException \DeepCopy\Exception\PropertyException - */ public function test_it_cannot_retrieve_a_non_existent_prperty() { $object = new ReflectionHelperTestChild(); + $this->expectException(PropertyException::class); ReflectionHelper::getProperty($object, 'non existent property'); } } From 6265e1563cc210e6caf2294939568aab6ca2c3bf Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Thu, 17 Feb 2022 18:52:41 +0100 Subject: [PATCH 09/20] Fix code example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index baec62d..72657a5 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ DeepCopy helps you create deep copies (clones) of your objects. It is designed t Install with Composer: -```json +``` composer require myclabs/deep-copy ``` From 6ec81859f59948b34fdbcceed108aae3c89438d9 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Thu, 17 Feb 2022 18:53:23 +0100 Subject: [PATCH 10/20] Improve README --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 72657a5..c98d7df 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,6 @@ 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) ## Table of Contents @@ -41,7 +38,7 @@ Install with Composer: composer require myclabs/deep-copy ``` -Use simply: +Use it: ```php use DeepCopy\DeepCopy; From 8263fc30b63ea463b22e7f264ed77f2ceb022cdc Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Thu, 17 Feb 2022 18:54:39 +0100 Subject: [PATCH 11/20] Disable code coverage --- .github/workflows/ci.yaml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9090248..ef96ef3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -71,7 +71,6 @@ jobs: - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: - coverage: "pcov" php-version: "${{ matrix.php-version }}" ini-values: zend.assertions=1 @@ -96,10 +95,4 @@ jobs: - name: "Run tests" timeout-minutes: 3 - run: "vendor/bin/phpunit --coverage-clover build/logs/clover.xml" - - - name: "Coveralls" - if: ${{ matrix.php-version == '8.1' && matrix.dependencies == 'highest' }} - run: | - wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.5.2/php-coveralls.phar - php coveralls.phar -v + run: "vendor/bin/phpunit" From 8068e0aae31b68eda0a198085dd2c7ba9d14874e Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Fri, 18 Feb 2022 07:57:31 +0100 Subject: [PATCH 12/20] Raise minimum required version to pass --prefer-lowest build --- composer.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index c6278f2..8044574 100644 --- a/composer.json +++ b/composer.json @@ -14,9 +14,13 @@ "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/collections": "^1.6", - "doctrine/common": "^2.13", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3" }, "autoload": { "psr-4": { From dc9c15dae886b70df89ff83d3815339cce95ec52 Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Fri, 18 Feb 2022 08:12:26 +0100 Subject: [PATCH 13/20] Add support for doctrine/common v3 --- composer.json | 4 ++-- phpunit.xml.dist | 7 +++---- src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php | 2 +- .../Matcher/Doctrine/DoctrineProxyMatcherTest.php | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 8044574..66fb34a 100644 --- a/composer.json +++ b/composer.json @@ -15,12 +15,12 @@ }, "require-dev": { "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3", + "doctrine/common": "^2.13.3 || ^3.2.2", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3" + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3e3b07b..bfe4b0f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,12 +1,11 @@ + xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" + colors="true"> - ./tests + ./tests/DeepCopyTest diff --git a/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php b/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php index ec8856f..c5887b1 100644 --- a/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php +++ b/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php @@ -3,7 +3,7 @@ namespace DeepCopy\Matcher\Doctrine; use DeepCopy\Matcher\Matcher; -use Doctrine\Common\Persistence\Proxy; +use Doctrine\Persistence\Proxy; /** * @final diff --git a/tests/DeepCopyTest/Matcher/Doctrine/DoctrineProxyMatcherTest.php b/tests/DeepCopyTest/Matcher/Doctrine/DoctrineProxyMatcherTest.php index 6303a4c..22e380d 100644 --- a/tests/DeepCopyTest/Matcher/Doctrine/DoctrineProxyMatcherTest.php +++ b/tests/DeepCopyTest/Matcher/Doctrine/DoctrineProxyMatcherTest.php @@ -4,7 +4,7 @@ use BadMethodCallException; use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; -use Doctrine\Common\Persistence\Proxy; +use Doctrine\Persistence\Proxy; use PHPUnit\Framework\TestCase; use stdClass; From 3501e7a2f25241559b1f09f68c603df9fe4fe2ee Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Fri, 18 Feb 2022 08:13:39 +0100 Subject: [PATCH 14/20] Add CI badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c98d7df..503e93d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ DeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph. [![Total Downloads](https://poser.pugx.org/myclabs/deep-copy/downloads.svg)](https://packagist.org/packages/myclabs/deep-copy) +[![Integrate](https://github.com/myclabs/DeepCopy/workflows/ci/badge.svg?branch=1.x)](https://github.com/myclabs/DeepCopy/actions) ## Table of Contents From b116b003b34d25d5677443825fb0e826a90bf1af Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Fri, 18 Feb 2022 08:20:36 +0100 Subject: [PATCH 15/20] Explicit package version to tackle circular ref with phpunit --- .github/workflows/ci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ef96ef3..eac2812 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -4,6 +4,9 @@ on: - pull_request - push +env: + COMPOSER_ROOT_VERSION: 1.99 + jobs: composer-json-lint: name: "Lint composer.json" From f60028e45fe15e075cbdd285d68c6e3833b94b7a Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Thu, 17 Feb 2022 16:06:11 +0100 Subject: [PATCH 16/20] Keep PHP 8.1 enums as is --- fixtures/f012/Suit.php | 11 +++++++++++ src/DeepCopy/DeepCopy.php | 5 +++++ tests/DeepCopyTest/DeepCopyTest.php | 13 +++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 fixtures/f012/Suit.php diff --git a/fixtures/f012/Suit.php b/fixtures/f012/Suit.php new file mode 100644 index 0000000..9d77ddb --- /dev/null +++ b/fixtures/f012/Suit.php @@ -0,0 +1,11 @@ +copyObject($var); } diff --git a/tests/DeepCopyTest/DeepCopyTest.php b/tests/DeepCopyTest/DeepCopyTest.php index a079c23..8d11c5b 100644 --- a/tests/DeepCopyTest/DeepCopyTest.php +++ b/tests/DeepCopyTest/DeepCopyTest.php @@ -19,6 +19,7 @@ use DeepCopy\f008; use DeepCopy\f009; use DeepCopy\f011; +use DeepCopy\f012\Suit; use DeepCopy\Filter\KeepFilter; use DeepCopy\Filter\SetNullFilter; use DeepCopy\Matcher\PropertyNameMatcher; @@ -495,6 +496,18 @@ public function test_it_ignores_uninitialized_typed_properties() $this->assertFalse(isset($copy->foo)); } + /** + * @requires PHP 8.1 + */ + public function test_it_keeps_enums() + { + $enum = Suit::Clubs; + + $copy = (new DeepCopy())->copy($enum); + + $this->assertSame($enum, $copy); + } + private function assertEqualButNotSame($expected, $val) { $this->assertEquals($expected, $val); From c78e0516c19a72dd75aa258d55c1ede43b1ed9c2 Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Fri, 18 Feb 2022 08:26:49 +0100 Subject: [PATCH 17/20] enum_exists may have been manually declared on lower PHP versions, use strict PHP version check --- src/DeepCopy/DeepCopy.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DeepCopy/DeepCopy.php b/src/DeepCopy/DeepCopy.php index 863c0ca..678df40 100644 --- a/src/DeepCopy/DeepCopy.php +++ b/src/DeepCopy/DeepCopy.php @@ -140,8 +140,8 @@ private function recursiveCopy($var) return $var; } - // PHP 8.1 Enum - if (function_exists('enum_exists') && enum_exists($var::class)) { + // Enum + if (PHP_VERSION_ID >= 80100 && enum_exists($var::class)) { return $var; } From fe20811c6c719a4d5616755dd7feb7ae7a5c8bb0 Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Thu, 3 Mar 2022 09:17:33 +0100 Subject: [PATCH 18/20] Backward compatibility --- src/DeepCopy/DeepCopy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DeepCopy/DeepCopy.php b/src/DeepCopy/DeepCopy.php index 678df40..9aeea6d 100644 --- a/src/DeepCopy/DeepCopy.php +++ b/src/DeepCopy/DeepCopy.php @@ -141,7 +141,7 @@ private function recursiveCopy($var) } // Enum - if (PHP_VERSION_ID >= 80100 && enum_exists($var::class)) { + if (PHP_VERSION_ID >= 80100 && is_object($var) && enum_exists(get_class($var))) { return $var; } From 07364389e116387a81545f31854da87ebcff5b0e Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Thu, 3 Mar 2022 09:18:48 +0100 Subject: [PATCH 19/20] Remove redundant check --- src/DeepCopy/DeepCopy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DeepCopy/DeepCopy.php b/src/DeepCopy/DeepCopy.php index 9aeea6d..5e68c64 100644 --- a/src/DeepCopy/DeepCopy.php +++ b/src/DeepCopy/DeepCopy.php @@ -141,7 +141,7 @@ private function recursiveCopy($var) } // Enum - if (PHP_VERSION_ID >= 80100 && is_object($var) && enum_exists(get_class($var))) { + if (PHP_VERSION_ID >= 80100 && enum_exists(get_class($var))) { return $var; } From 0de033622bb94266a9ac30809db342daaab11091 Mon Sep 17 00:00:00 2001 From: fsevestre Date: Tue, 7 Mar 2023 10:55:10 +0100 Subject: [PATCH 20/20] Allow applying further filters with ChainableFilter --- README.md | 35 ++++++++++++++++++++++++- fixtures/f013/A.php | 24 +++++++++++++++++ fixtures/f013/B.php | 34 ++++++++++++++++++++++++ fixtures/f013/C.php | 13 +++++++++ src/DeepCopy/DeepCopy.php | 5 ++++ src/DeepCopy/Filter/ChainableFilter.php | 24 +++++++++++++++++ tests/DeepCopyTest/DeepCopyTest.php | 34 ++++++++++++++++++++++++ 7 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 fixtures/f013/A.php create mode 100644 fixtures/f013/B.php create mode 100644 fixtures/f013/C.php create mode 100644 src/DeepCopy/Filter/ChainableFilter.php diff --git a/README.md b/README.md index 503e93d..94aaa06 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,9 @@ $matcher = new TypeMatcher('Doctrine\Common\Collections\Collection'); - `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` +By design, matching a filter will stop the chain of filters (i.e. the next ones will not be applied). +Using the ([`ChainableFilter`](#chainablefilter-filter)) won't stop the chain of filters. + #### `SetNullFilter` (filter) @@ -226,6 +229,34 @@ $copy = $copier->copy($object); ``` +#### `ChainableFilter` (filter) + +If you use cloning on proxy classes, you might want to apply two filters for: +1. loading the data +2. applying a transformation + +You can use the `ChainableFilter` as a decorator of the proxy loader filter, which won't stop the chain of filters (i.e. +the next ones may be applied). + + +```php +use DeepCopy\DeepCopy; +use DeepCopy\Filter\ChainableFilter; +use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; +use DeepCopy\Filter\SetNullFilter; +use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; +use DeepCopy\Matcher\PropertyNameMatcher; + +$copier = new DeepCopy(); +$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); +$copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id')); + +$copy = $copier->copy($object); + +echo $copy->id; // null +``` + + #### `DoctrineCollectionFilter` (filter) If you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`: @@ -268,6 +299,8 @@ 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!** +We recommend to decorate the `DoctrineProxyFilter` with the `ChainableFilter` to allow applying other filters to the +cloned lazy loaded entities. ```php use DeepCopy\DeepCopy; @@ -275,7 +308,7 @@ use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; $copier = new DeepCopy(); -$copier->addFilter(new DoctrineProxyFilter(), new DoctrineProxyMatcher()); +$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); $copy = $copier->copy($object); diff --git a/fixtures/f013/A.php b/fixtures/f013/A.php new file mode 100644 index 0000000..aa0393d --- /dev/null +++ b/fixtures/f013/A.php @@ -0,0 +1,24 @@ +foo; + } + + public function setFoo($foo) + { + $this->foo = $foo; + } +} diff --git a/fixtures/f013/C.php b/fixtures/f013/C.php new file mode 100644 index 0000000..26d4af2 --- /dev/null +++ b/fixtures/f013/C.php @@ -0,0 +1,13 @@ +foo = null; + } +} diff --git a/src/DeepCopy/DeepCopy.php b/src/DeepCopy/DeepCopy.php index 5e68c64..6e766d8 100644 --- a/src/DeepCopy/DeepCopy.php +++ b/src/DeepCopy/DeepCopy.php @@ -7,6 +7,7 @@ use DateTimeInterface; use DateTimeZone; use DeepCopy\Exception\CloneException; +use DeepCopy\Filter\ChainableFilter; use DeepCopy\Filter\Filter; use DeepCopy\Matcher\Matcher; use DeepCopy\Reflection\ReflectionHelper; @@ -239,6 +240,10 @@ function ($object) { } ); + if ($filter instanceof ChainableFilter) { + continue; + } + // If a filter matches, we stop processing this property return; } diff --git a/src/DeepCopy/Filter/ChainableFilter.php b/src/DeepCopy/Filter/ChainableFilter.php new file mode 100644 index 0000000..4e3f7bb --- /dev/null +++ b/src/DeepCopy/Filter/ChainableFilter.php @@ -0,0 +1,24 @@ +filter = $filter; + } + + public function apply($object, $property, $objectCopier) + { + $this->filter->apply($object, $property, $objectCopier); + } +} diff --git a/tests/DeepCopyTest/DeepCopyTest.php b/tests/DeepCopyTest/DeepCopyTest.php index 8d11c5b..0b44648 100644 --- a/tests/DeepCopyTest/DeepCopyTest.php +++ b/tests/DeepCopyTest/DeepCopyTest.php @@ -20,8 +20,12 @@ use DeepCopy\f009; use DeepCopy\f011; use DeepCopy\f012\Suit; +use DeepCopy\f013; +use DeepCopy\Filter\ChainableFilter; +use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; use DeepCopy\Filter\KeepFilter; use DeepCopy\Filter\SetNullFilter; +use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; use DeepCopy\Matcher\PropertyNameMatcher; use DeepCopy\Matcher\PropertyTypeMatcher; use DeepCopy\TypeFilter\ShallowCopyFilter; @@ -508,6 +512,36 @@ public function test_it_keeps_enums() $this->assertSame($enum, $copy); } + /** + * @ticket https://github.com/myclabs/DeepCopy/issues/98 + */ + public function test_it_can_apply_two_filters_with_chainable_filter() + { + $object = new f013\A(); + + $deepCopy = new DeepCopy(); + $deepCopy->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); + $deepCopy->addFilter(new SetNullFilter(), new PropertyNameMatcher('foo')); + + $copy = $deepCopy->copy($object); + + $this->assertNull($copy->foo); + } + + public function test_it_can_copy_property_after_applying_doctrine_proxy_filter_with_chainable_filter() + { + $object = new f013\B(); + $object->setFoo(new f013\C()); + + $deepCopy = new DeepCopy(); + $deepCopy->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); + + /** @var f013\B $copy */ + $copy = $deepCopy->copy($object); + + $this->assertNotEquals($copy->getFoo(), $object->getFoo()); + } + private function assertEqualButNotSame($expected, $val) { $this->assertEquals($expected, $val);