Skip to content

Commit c9a43cf

Browse files
authored
Merge pull request #747 from DirectoryTree/BUG-746
Bug 746 - Infinite loop in LdapRecord\Models\Collection::contains function
2 parents a4af228 + 8be65b6 commit c9a43cf

File tree

4 files changed

+203
-6
lines changed

4 files changed

+203
-6
lines changed

src/Models/Collection.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ public function modelDns(): static
2121

2222
/**
2323
* Determine if the collection contains all the given models, or any models.
24+
*
25+
* @param QueryCollection|Model|array|string|null $models
2426
*/
25-
public function exists($models = null): bool
27+
public function exists(mixed $models = null): bool
2628
{
2729
$models = $this->getArrayableModels($models);
2830

@@ -56,10 +58,7 @@ public function exists($models = null): bool
5658
public function contains($key, $operator = null, $value = null): bool
5759
{
5860
if (func_num_args() > 1 || $key instanceof Closure) {
59-
// If we are supplied with more than one argument, or
60-
// we were passed a closure, we will utilize the
61-
// parents contains method, for compatibility.
62-
return parent::contains($key, $operator, $value);
61+
return parent::contains(...func_get_args());
6362
}
6463

6564
foreach ($this->getArrayableModels($key) as $model) {
@@ -78,7 +77,7 @@ public function contains($key, $operator = null, $value = null): bool
7877
/**
7978
* Get the provided models as an array.
8079
*/
81-
protected function getArrayableModels($models = null): array
80+
protected function getArrayableModels(mixed $models = null): array
8281
{
8382
if ($models instanceof QueryCollection) {
8483
return $models->all();

src/Models/Model.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,8 @@ public function fresh(): static|false
557557
public function is(?Model $model = null): bool
558558
{
559559
return ! is_null($model)
560+
&& ! empty($this->dn)
561+
&& ! empty($model->getDn())
560562
&& $this->dn == $model->getDn()
561563
&& $this->getConnectionName() == $model->getConnectionName();
562564
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
<?php
2+
3+
namespace LdapRecord\Tests\Unit\Models;
4+
5+
use LdapRecord\Models\ActiveDirectory\User;
6+
use LdapRecord\Models\Collection;
7+
use LdapRecord\Models\Model;
8+
use LdapRecord\Tests\TestCase;
9+
10+
class CollectionTest extends TestCase
11+
{
12+
public function test_exists_with_no_parameters()
13+
{
14+
$collection = new Collection;
15+
16+
$this->assertFalse(
17+
$collection->exists()
18+
);
19+
20+
$collection = new Collection([new User]);
21+
22+
$this->assertTrue(
23+
$collection->exists()
24+
);
25+
}
26+
27+
public function test_exists_with_dn()
28+
{
29+
$user = new User(['dn' => 'cn=John Doe']);
30+
31+
$collection = new Collection([$user]);
32+
33+
$this->assertTrue(
34+
$collection->exists('cn=John Doe')
35+
);
36+
37+
$this->assertFalse(
38+
$collection->exists('cn=Jane Doe')
39+
);
40+
}
41+
42+
public function test_exists_with_multiple_dns()
43+
{
44+
$user = new User(['dn' => 'cn=John Doe']);
45+
46+
$collection = new Collection([$user]);
47+
48+
$this->assertTrue(
49+
$collection->exists(['cn=John Doe'])
50+
);
51+
52+
$this->assertFalse(
53+
$collection->exists(['cn=Jane Doe', 'cn=Foo Bar'])
54+
);
55+
}
56+
57+
public function test_exists_with_model()
58+
{
59+
$user = new User(['dn' => 'cn=John Doe']);
60+
61+
$collection = new Collection([$user]);
62+
63+
$this->assertTrue(
64+
$collection->exists($user)
65+
);
66+
67+
$this->assertFalse(
68+
$collection->exists(new User(['dn' => 'cn=Jane Doe']))
69+
);
70+
}
71+
72+
public function test_exists_with_model_collection()
73+
{
74+
$user = new User(['dn' => 'cn=John Doe']);
75+
76+
$collection = new Collection([$user]);
77+
78+
$this->assertTrue(
79+
$collection->exists(new Collection([$user]))
80+
);
81+
82+
$this->assertFalse(
83+
$collection->exists(new Collection([
84+
new User(['dn' => 'cn=Jane Doe']),
85+
new User(['dn' => 'cn=Foo Bar']),
86+
]))
87+
);
88+
}
89+
90+
public function test_contains_with_closure()
91+
{
92+
$user = new User(['cn' => 'John Doe']);
93+
94+
$collection = new Collection([$user]);
95+
96+
$this->assertTrue(
97+
$collection->contains(function (Model $model) {
98+
return $model->getFirstAttribute('cn') === 'John Doe';
99+
})
100+
);
101+
102+
$this->assertFalse(
103+
$collection->contains(function (Model $model) {
104+
return $model->getFirstAttribute('cn') === 'Jane Doe';
105+
})
106+
);
107+
}
108+
109+
public function test_contains_with_key_operator_and_value()
110+
{
111+
$user = new User(['cn' => 'John Doe']);
112+
113+
$collection = new Collection([$user]);
114+
115+
$this->assertTrue(
116+
$collection->contains('cn', '=', ['John Doe'])
117+
);
118+
119+
$this->assertFalse(
120+
$collection->contains('cn', '=', ['Jane Doe'])
121+
);
122+
}
123+
124+
public function test_contains_with_model()
125+
{
126+
$user = new User(['dn' => 'cn=John Doe']);
127+
128+
$otherUser = new User(['dn' => 'cn=Jane Doe']);
129+
130+
$collection = new Collection([$user]);
131+
132+
$this->assertTrue(
133+
$collection->contains($user)
134+
);
135+
136+
$this->assertFalse(
137+
$collection->contains($otherUser)
138+
);
139+
}
140+
141+
public function test_contains_with_model_without_dn()
142+
{
143+
$user = new User(['cn' => 'John Doe']);
144+
145+
$collection = new Collection([$user]);
146+
147+
$this->assertFalse(
148+
$collection->contains(new User)
149+
);
150+
}
151+
152+
public function test_contains_with_multiple_models()
153+
{
154+
$user = new User(['dn' => 'cn=John Doe']);
155+
156+
$otherUser = new User(['dn' => 'cn=Jane Doe']);
157+
158+
$collection = new Collection([$user, $otherUser]);
159+
160+
$this->assertTrue(
161+
$collection->contains([
162+
$user,
163+
$otherUser,
164+
])
165+
);
166+
167+
$this->assertFalse(
168+
$collection->contains([
169+
new User(['dn' => 'cn=Foo Bar']),
170+
new User(['dn' => 'cn=Bar Baz']),
171+
])
172+
);
173+
}
174+
175+
public function test_contains_with_model_collection()
176+
{
177+
$user = new User(['dn' => 'cn=John Doe']);
178+
179+
$otherUser = new User(['dn' => 'cn=Jane Doe']);
180+
181+
$collection = new Collection([$user, $otherUser]);
182+
183+
$this->assertTrue(
184+
$collection->contains(new Collection([$user]))
185+
);
186+
187+
$this->assertFalse(
188+
$collection->contains(new Collection([
189+
new User(['dn' => 'cn=Foo Bar']),
190+
new User(['dn' => 'cn=Bar Baz']),
191+
]))
192+
);
193+
}
194+
}

tests/Unit/Models/ModelSerializationTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public function testModelWithTimestampsCanBeSerializedAndEncoded()
1919

2020
$model = (new User)->setRawAttributes([
2121
'cn' => 'René',
22+
'dn' => 'cn=René',
2223
'whenchanged' => [(string) $whenchanged],
2324
'lastlogon' => [(string) $lastlogon],
2425
]);
@@ -48,6 +49,7 @@ public function testModelWithBinaryGuidAndSidCanBeSerializedAndEncoded()
4849
$sid = new Sid('S-1-5-21-1004336348-1177238915-682003330-512');
4950

5051
$model = (new Entry)->setRawAttributes([
52+
'dn' => 'cn=Foo Bar',
5153
'objectguid' => [$guid->getBinary()],
5254
'objectsid' => [$sid->getBinary()],
5355
]);

0 commit comments

Comments
 (0)