Skip to content

Commit 793d01f

Browse files
committed
WIP towards stricter types
1 parent 7fa2a77 commit 793d01f

15 files changed

+580
-111
lines changed

phpstan.neon

+2-7
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,11 @@ includes:
33
- vendor/lychee-org/phpstan-lychee/phpstan.neon
44

55
parameters:
6-
level: 3
6+
level: 2
77
paths:
88
- src
99
excludePaths:
1010
stubFiles:
1111
ignoreErrors:
1212
# - identifier: missingType.generics
13-
- '#Interface must be located in "Contract" or "Contracts" namespace#'
14-
- '#Dynamic call to static method Kalnoy\\Nestedset\\QueryBuilder<.*>::select\(\).#'
15-
- '#Dynamic call to static method Kalnoy\\Nestedset\\QueryBuilder<.*>::from\(\).#'
16-
# - '#Dynamic call to static method Kalnoy\\Nestedset\\QueryBuilder<.*>::whereRaw\(\).#'
17-
- '#Dynamic call to static method Kalnoy\\Nestedset\\QueryBuilder<.*>::whereNested\(\).#'
18-
- '#Dynamic call to static method Kalnoy\\Nestedset\\QueryBuilder<.*>::whereIn\(\).#'
13+
- '#Dynamic call to static method Kalnoy\\Nestedset\\QueryBuilder<Tmodel of Illuminate\\Database\\Eloquent\\Model>::whereRaw\(\).#'

src/AncestorsRelation.php

+7-6
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
namespace Kalnoy\Nestedset;
44

55
use Illuminate\Database\Eloquent\Model;
6+
use Kalnoy\Nestedset\Contracts\Node;
7+
use Kalnoy\Nestedset\Contracts\NodeQueryBuilder;
68

79
/**
810
* @template Tmodel of Model
911
*
10-
* @phpstan-type NodeModel Node<Tmodel>&Tmodel
11-
*
12-
* @disregard P1037
12+
* @phpstan-type NodeModel \Kalnoy\Nestedset\Contracts\Node<Tmodel>&Tmodel
1313
*
1414
* @extends BaseRelation<Tmodel>
1515
*/
16-
class AncestorsRelation extends BaseRelation
16+
final class AncestorsRelation extends BaseRelation
1717
{
1818
/**
1919
* Set the base constraints on the relation query.
@@ -36,13 +36,13 @@ public function addConstraints()
3636
*
3737
* @return bool
3838
*/
39-
protected function matches(Model $model, $related): bool
39+
protected function matches(Node $model, Node $related): bool
4040
{
4141
return $related->isAncestorOf($model);
4242
}
4343

4444
/**
45-
* @param QueryBuilder<Tmodel> $query
45+
* @param NodeQueryBuilder<Tmodel> $query
4646
* @param NodeModel $model
4747
*
4848
* @return void
@@ -57,6 +57,7 @@ protected function addEagerConstraint($query, $model)
5757
*/
5858
protected function relationExistenceCondition(string $hash, string $table, string $lft, string $rgt): string
5959
{
60+
/** @disregard P1013 */
6061
$key = $this->getBaseQuery()->getGrammar()->wrap($this->parent->getKeyName());
6162

6263
return "{$table}.{$rgt} between {$hash}.{$lft} and {$hash}.{$rgt} and $table.$key <> $hash.$key";

src/BaseRelation.php

+17-14
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,23 @@
77
use Illuminate\Database\Eloquent\Model;
88
use Illuminate\Database\Eloquent\Relations\Relation;
99
use Illuminate\Database\Query\Builder;
10+
use Kalnoy\Nestedset\Contracts\Node;
11+
use Kalnoy\Nestedset\Contracts\NodeQueryBuilder;
12+
use Kalnoy\Nestedset\Contracts\NestedSetCollection;
1013

1114
/**
1215
* @template Tmodel of Model
1316
*
14-
* @phpstan-type NodeModel Node<Tmodel>&Tmodel
15-
*
16-
* @extends Relation<NodeModel,NodeModel,EloquentCollection<int,NodeModel>>
17+
* @phpstan-type NodeModel \Kalnoy\Nestedset\Contracts\Node<Tmodel>&Model
18+
* @extends Relation<NodeModel,NodeModel,EloquentCollection<int,Node<Tmodel>>>
1719
*
1820
* @property NodeModel $related
1921
* @property NodeModel $parent
20-
*
21-
* @method NodeModel getParent()
2222
*/
23-
abstract class BaseRelation extends Relation
23+
abstract class BaseRelation extends Relation // @phpstan-ignore generics.notSubtype (Phpstan does not recognise the require-extend on the interface)
2424
{
2525
/**
26-
* @var QueryBuilder<Tmodel>
26+
* @var NodeQueryBuilder<Tmodel>
2727
*/
2828
protected $query;
2929

@@ -60,10 +60,10 @@ public function __construct(QueryBuilder $builder, Model $model)
6060
*
6161
* @return bool
6262
*/
63-
abstract protected function matches(Model&Node $model, Node $related): bool;
63+
abstract protected function matches(Node $model, Node $related): bool;
6464

6565
/**
66-
* @param QueryBuilder<Tmodel> $query
66+
* @param NodeQueryBuilder<Tmodel> $query
6767
* @param NodeModel $model
6868
*
6969
* @return void
@@ -90,6 +90,7 @@ abstract protected function relationExistenceCondition(string $hash, string $tab
9090
public function getRelationExistenceQuery(EloquentBuilder $query, EloquentBuilder $parentQuery,
9191
$columns = ['*'],
9292
) {
93+
/** @disregard P1006 */
9394
$query = $this->getParent()->replicate()->newScopedQuery()->select($columns);
9495

9596
$table = $query->getModel()->getTable();
@@ -106,7 +107,7 @@ public function getRelationExistenceQuery(EloquentBuilder $query, EloquentBuilde
106107
$grammar->wrap($this->parent->getLftName()),
107108
$grammar->wrap($this->parent->getRgtName()));
108109

109-
return $query->whereRaw($condition); /** @phpstan-ignore-line */
110+
return $query->whereRaw($condition);
110111
}
111112

112113
/**
@@ -137,11 +138,11 @@ public function getRelationCountHash($incrementJoinCount = true)
137138
/**
138139
* Get the results of the relationship.
139140
*
140-
* @return Collection<NodeModel>
141+
* @return NestedSetCollection<NodeModel>
141142
*/
142143
public function getResults()
143144
{
144-
/** @var Collection<NodeModel> */
145+
/** @disregard P1013 */
145146
$result = $this->query->get();
146147

147148
return $result;
@@ -164,6 +165,7 @@ public function addEagerConstraints(array $models)
164165
$this->query->whereNested(function (Builder $inner) use ($models) {
165166
// We will use this query in order to apply constraints to the
166167
// base query builder
168+
/** @disregard P1013 */
167169
$outer = $this->parent->newQuery()->setQuery($inner);
168170

169171
foreach ($models as $model) {
@@ -187,6 +189,7 @@ public function match(array $models, EloquentCollection $results, $relation)
187189
/** @disregard P1006 */
188190
$related = $this->matchForModel($model, $results);
189191

192+
/** @disregard P1013 */
190193
$model->setRelation($relation, $related);
191194
}
192195

@@ -197,16 +200,16 @@ public function match(array $models, EloquentCollection $results, $relation)
197200
* @param NodeModel $model
198201
* @param EloquentCollection<int,NodeModel> $results
199202
*
200-
* @return Collection<Tmodel>
203+
* @return NestedSetCollection<Tmodel>
201204
*/
202205
protected function matchForModel(Model $model, EloquentCollection $results)
203206
{
204-
/** @var Collection<Tmodel> */
205207
$result = $this->related->newCollection();
206208

207209
foreach ($results as $related) {
208210
/** @disregard P1006 */
209211
if ($this->matches($model, $related)) {
212+
/** @disregard P1013 */
210213
$result->push($related);
211214
}
212215
}

src/Collection.php

+14-8
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@
44

55
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
66
use Illuminate\Database\Eloquent\Model;
7+
use Kalnoy\Nestedset\Contracts\NestedSetCollection;
8+
use Kalnoy\Nestedset\Exceptions\NestedSetException;
79

810
/**
11+
*
912
* @template Tmodel of Model
1013
*
11-
* @phpstan-type NodeModel Node<Tmodel>&Tmodel
14+
* @phpstan-type NodeModel \Kalnoy\Nestedset\Contracts\Node<Tmodel>
1215
*
1316
* @extends EloquentCollection<array-key,NodeModel>
1417
*/
15-
final class Collection extends EloquentCollection
18+
final class Collection extends EloquentCollection implements NestedSetCollection
1619
{
1720
/**
1821
* Fill `parent` and `children` relationships for every node in the collection.
@@ -34,16 +37,19 @@ public function linkNodes()
3437
/** @var NodeModel $node */
3538
foreach ($this->items as $node) {
3639
if ($node->getParentId() === null) {
40+
/** @disregard */
3741
$node->setRelation('parent', null);
3842
}
3943

4044
/** @var array<int,NodeModel> */
41-
$children = $groupedNodes->get($node->getKey(), []); /** @phpstan-ignore varTag.type */
45+
$children = $groupedNodes->get($node->getKey(), []);
4246

4347
foreach ($children as $child) {
48+
/** @disregard */
4449
$child->setRelation('parent', $node);
4550
}
4651

52+
/** @disregard */
4753
$node->setRelation('children', EloquentCollection::make($children));
4854
}
4955

@@ -61,7 +67,7 @@ public function linkNodes()
6167
*
6268
* @return Collection<Tmodel>
6369
*/
64-
public function toTree($root = false)
70+
public function toTree($root = false): Collection
6571
{
6672
if ($this->isEmpty()) {
6773
return new static();
@@ -131,15 +137,15 @@ public function toFlatTree($root = false): Collection
131137
$result = new Collection();
132138

133139
if ($this->isEmpty()) {
134-
return $result; /** @phpstan-ignore-line */
140+
return $result;
135141
}
136142

137143
/** @var NodeModel */
138144
$first = $this->first();
139145
/** @var Collection<NodeModel> */
140-
$groupedNodes = $this->groupBy($first->getParentIdName()); /** @phpstan-ignore varTag.type */
146+
$groupedNodes = $this->groupBy($first->getParentIdName());
141147

142-
return $result->flattenTree($groupedNodes, $this->getRootNodeId($root)); /** @phpstan-ignore-line */
148+
return $result->flattenTree($groupedNodes, $this->getRootNodeId($root));
143149
}
144150

145151
/**
@@ -153,7 +159,7 @@ public function toFlatTree($root = false): Collection
153159
protected function flattenTree(Collection $groupedNodes, $parentId): Collection
154160
{
155161
/** @var array<int,NodeModel> */
156-
$nodes = $groupedNodes->get($parentId, []); /** @phpstan-ignore varTag.type */
162+
$nodes = $groupedNodes->get($parentId, []);
157163
foreach ($nodes as $node) {
158164
$this->push($node);
159165

src/Contracts/NestedSetCollection.php

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
4+
namespace Kalnoy\Nestedset\Contracts;
5+
6+
/**
7+
* @template Tmodel of \Illuminate\Database\Eloquent\Model
8+
*
9+
* @phpstan-type NodeModel Node<Tmodel>
10+
*
11+
* @require-extends \Illuminate\Database\Eloquent\Collection
12+
*/
13+
interface NestedSetCollection
14+
{
15+
/**
16+
* Fill `parent` and `children` relationships for every node in the collection.
17+
*
18+
* This will overwrite any previously set relations.
19+
*
20+
* @return $this
21+
*/
22+
public function linkNodes();
23+
24+
25+
/**
26+
* Build a tree from a list of nodes. Each item will have set children relation.
27+
*
28+
* To successfully build tree "id", "_lft" and "parent_id" keys must present.
29+
*
30+
* If `$root` is provided, the tree will contain only descendants of that node.
31+
*
32+
* @param mixed $root
33+
*
34+
* @return Collection<NodeModel>
35+
*/
36+
public function toTree($root = false): NestedSetCollection;
37+
38+
/**
39+
* Build a list of nodes that retain the order that they were pulled from
40+
* the database.
41+
*
42+
* @param bool $root
43+
*
44+
* @return Collection<NodeModel>
45+
*/
46+
public function toFlatTree($root = false): NestedSetCollection;
47+
}

0 commit comments

Comments
 (0)