Skip to content

Commit f0391a5

Browse files
committed
Add more tests
1 parent 1012e4d commit f0391a5

File tree

13 files changed

+499
-302
lines changed

13 files changed

+499
-302
lines changed

.travis.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ language: php
33
sudo: false
44

55
php:
6-
- '5.5'
76
- '5.6'
87
- '7.0'
98
- '7.1'
@@ -12,7 +11,7 @@ php:
1211
matrix:
1312
fast_finish: true
1413
include:
15-
- php: '5.4'
14+
- php: '5.6'
1615
env: COMPOSER_FLAGS="--prefer-lowest"
1716
allow_failures:
1817
- php: nightly
@@ -23,7 +22,7 @@ cache:
2322

2423
before_install:
2524
- |
26-
if [ "$TRAVIS_PHP_VERSION" = "nightly" ] || "$TRAVIS_PHP_VERSION" = "7.1" ]; then
25+
if [ "$TRAVIS_PHP_VERSION" = "nightly" ]; then
2726
COMPOSER_FLAGS="$COMPOSER_FLAGS --ignore-platform-reqs"
2827
fi;
2928

README.md

Lines changed: 72 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ DeepCopy helps you create deep copies (clones) of your objects. It is designed t
2929
1. [Contributing](#contributing)
3030
1. [Tests](#tests)
3131

32+
3233
## How?
3334

3435
Install with Composer:
@@ -65,22 +66,27 @@ Now you're in for a big mess :(
6566

6667
![association graph](doc/graph.png)
6768

69+
6870
### Using simply `clone`
6971

7072
![Using clone](doc/clone.png)
7173

74+
7275
### Overridding `__clone()`
7376

7477
![Overridding __clone](doc/deep-clone.png)
7578

79+
7680
### With `DeepCopy`
7781

7882
![With DeepCopy](doc/deep-copy.png)
7983

84+
8085
## How it works
8186

8287
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.
8388

89+
8490
## Going further
8591

8692
You can add filters to customize the copy process.
@@ -91,11 +97,13 @@ and `$matcher` implementing `DeepCopy\Matcher\Matcher`.
9197

9298
We provide some generic filters and matchers.
9399

100+
94101
### Matchers
95102

96103
- `DeepCopy\Matcher` applies on a object attribute.
97104
- `DeepCopy\TypeMatcher` applies on any element found in graph, including array elements.
98105

106+
99107
#### Property name
100108

101109
The `PropertyNameMatcher` will match a property by its name:
@@ -107,6 +115,7 @@ $matcher = new PropertyNameMatcher('id');
107115
// will apply a filter to any property of any objects named "id"
108116
```
109117

118+
110119
#### Specific property
111120

112121
The `PropertyMatcher` will match a specific property of a specific class:
@@ -118,6 +127,7 @@ $matcher = new PropertyMatcher('MyClass', 'id');
118127
// will apply a filter to the property "id" of any objects of the class "MyClass"
119128
```
120129

130+
121131
#### Type
122132

123133
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):
@@ -129,12 +139,14 @@ $matcher = new TypeMatcher('Doctrine\Common\Collections\Collection');
129139
// will apply a filter to any object that is an instance of Doctrine\Common\Collections\Collection
130140
```
131141

142+
132143
### Filters
133144

134145
- `DeepCopy\Filter` applies a transformation to the object attribute matched by `DeepCopy\Matcher`.
135146
- `DeepCopy\TypeFilter` applies a transformation to any element matched by `DeepCopy\TypeMatcher`.
136147

137-
#### `SetNullFilter`
148+
149+
#### `SetNullFilter` (filter)
138150

139151
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:
140152

@@ -153,7 +165,8 @@ $myCopy = $deepCopy->copy($myObject);
153165
echo $myCopy->id; // null
154166
```
155167

156-
#### `KeepFilter`
168+
169+
#### `KeepFilter` (filter)
157170

158171
If you want a property to remain untouched (for example, an association to an object):
159172

@@ -169,7 +182,60 @@ $myCopy = $deepCopy->copy($myObject);
169182
// $myCopy->category has not been touched
170183
```
171184

172-
#### `ReplaceFilter`
185+
186+
#### `DoctrineCollectionFilter` (filter)
187+
188+
If you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`:
189+
190+
```php
191+
use DeepCopy\DeepCopy;
192+
use DeepCopy\Filter\Doctrine\DoctrineCollectionFilter;
193+
use DeepCopy\Matcher\PropertyTypeMatcher;
194+
195+
$deepCopy = new DeepCopy();
196+
$deepCopy->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection'));
197+
$myCopy = $deepCopy->copy($myObject);
198+
```
199+
200+
201+
#### `DoctrineEmptyCollectionFilter` (filter)
202+
203+
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`
204+
205+
```php
206+
use DeepCopy\DeepCopy;
207+
use DeepCopy\Filter\Doctrine\DoctrineEmptyCollectionFilter;
208+
use DeepCopy\Matcher\PropertyMatcher;
209+
210+
$deepCopy = new DeepCopy();
211+
$deepCopy->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty'));
212+
$myCopy = $deepCopy->copy($myObject);
213+
214+
// $myCopy->myProperty will return an empty collection
215+
```
216+
217+
218+
#### `DoctrineProxyFilter` (filter)
219+
220+
If you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a
221+
Doctrine proxy class (...\\\_\_CG\_\_\Proxy).
222+
You can use the `DoctrineProxyFilter` to load the actual entity behind the Doctrine proxy class.
223+
**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!**
224+
225+
```php
226+
use DeepCopy\DeepCopy;
227+
use DeepCopy\Filter\Doctrine\DoctrineProxyFilter;
228+
use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher;
229+
230+
$deepCopy = new DeepCopy();
231+
$deepCopy->addFilter(new DoctrineProxyFilter(), new DoctrineProxyMatcher());
232+
$myCopy = $deepCopy->copy($myObject);
233+
234+
// $myCopy should now contain a clone of all entities, including those that were not yet fully loaded.
235+
```
236+
237+
238+
#### `ReplaceFilter` (type filter)
173239

174240
1. If you want to replace the value of a property:
175241

@@ -208,7 +274,8 @@ $myCopy = $deepCopy->copy($myObject);
208274

209275
The `$callback` parameter of the `ReplaceFilter` constructor accepts any PHP callable.
210276

211-
#### `ShallowCopyFilter`
277+
278+
#### `ShallowCopyFilter` (type filter)
212279

213280
Stop *DeepCopy* from recursively copying element, using standard `clone` instead:
214281

@@ -228,59 +295,12 @@ $myServiceWithMocks = new MyService(m::mock(MyDependency1::class), m::mock(MyDep
228295
// all mocks will be just cloned, not deep-copied
229296
```
230297

231-
#### `DoctrineCollectionFilter`
232-
233-
If you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`:
234-
235-
```php
236-
use DeepCopy\DeepCopy;
237-
use DeepCopy\Filter\Doctrine\DoctrineCollectionFilter;
238-
use DeepCopy\Matcher\PropertyTypeMatcher;
239-
240-
$deepCopy = new DeepCopy();
241-
$deepCopy->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection'));
242-
$myCopy = $deepCopy->copy($myObject);
243-
```
244-
245-
#### `DoctrineEmptyCollectionFilter`
246-
247-
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`
248-
249-
```php
250-
use DeepCopy\DeepCopy;
251-
use DeepCopy\Filter\Doctrine\DoctrineEmptyCollectionFilter;
252-
use DeepCopy\Matcher\PropertyMatcher;
253-
254-
$deepCopy = new DeepCopy();
255-
$deepCopy->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty'));
256-
$myCopy = $deepCopy->copy($myObject);
257-
258-
// $myCopy->myProperty will return an empty collection
259-
```
260-
261-
#### `DoctrineProxyFilter`
262-
263-
If you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a
264-
Doctrine proxy class (...\\\_\_CG\_\_\Proxy).
265-
You can use the `DoctrineProxyFilter` to load the actual entity behind the Doctrine proxy class.
266-
**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!**
267-
268-
```php
269-
use DeepCopy\DeepCopy;
270-
use DeepCopy\Filter\Doctrine\DoctrineProxyFilter;
271-
use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher;
272-
273-
$deepCopy = new DeepCopy();
274-
$deepCopy->addFilter(new DoctrineProxyFilter(), new DoctrineProxyMatcher());
275-
$myCopy = $deepCopy->copy($myObject);
276-
277-
// $myCopy should now contain a clone of all entities, including those that were not yet fully loaded.
278-
```
279298

280299
## Contributing
281300

282301
DeepCopy is distributed under the MIT license.
283302

303+
284304
### Tests
285305

286306
Running the tests is simple:

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
},
1616
"autoload-dev": {
1717
"psr-4": {
18+
"DeepCopy\\": "fixtures/",
1819
"DeepCopyTest\\": "tests/DeepCopyTest/"
1920
}
2021
},
2122

2223
"require": {
23-
"php": ">=5.4.0"
24+
"php": "^5.6.0"
2425
},
2526
"require-dev": {
2627
"doctrine/collections": "^1.0",

fixtures/f001/A.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace DeepCopy\f001;
4+
5+
class A
6+
{
7+
private $aProp;
8+
9+
public function getAProp()
10+
{
11+
return $this->aProp;
12+
}
13+
14+
public function setAProp($prop)
15+
{
16+
$this->aProp = $prop;
17+
18+
return $this;
19+
}
20+
}

fixtures/f001/B.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace DeepCopy\f001;
4+
5+
class B extends A
6+
{
7+
private $bProp;
8+
9+
public function getBProp()
10+
{
11+
return $this->bProp;
12+
}
13+
14+
public function setBProp($prop)
15+
{
16+
$this->bProp = $prop;
17+
18+
return $this;
19+
}
20+
}

fixtures/f002/A.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace DeepCopy\f002;
4+
5+
class A
6+
{
7+
private $prop1;
8+
private $prop2;
9+
10+
public function getProp1()
11+
{
12+
return $this->prop1;
13+
}
14+
15+
public function setProp1($prop)
16+
{
17+
$this->prop1 = $prop;
18+
19+
return $this;
20+
}
21+
22+
public function getProp2()
23+
{
24+
return $this->prop2;
25+
}
26+
27+
public function setProp2($prop)
28+
{
29+
$this->prop2 = $prop;
30+
31+
return $this;
32+
}
33+
}

fixtures/f003/Foo.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace DeepCopy\f003;
4+
5+
class Foo
6+
{
7+
private $name;
8+
private $prop;
9+
10+
public function __construct($name)
11+
{
12+
$this->name = $name;
13+
}
14+
15+
public function getProp()
16+
{
17+
return $this->prop;
18+
}
19+
20+
public function setProp($prop)
21+
{
22+
$this->prop = $prop;
23+
24+
return $this;
25+
}
26+
}

fixtures/f004/UnclonableItem.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace DeepCopy\f004;
4+
5+
use BadMethodCallException;
6+
7+
class UnclonableItem
8+
{
9+
private function __clone()
10+
{
11+
throw new BadMethodCallException('Unsupported call.');
12+
}
13+
}

0 commit comments

Comments
 (0)