Test Failed
Pull Request — master (#48)
by
unknown
03:03
created

src/Helpers/LTreeNode.php (4 issues)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Umbrellio\LTree\Helpers;
6
7
use Illuminate\Database\Eloquent\Collection;
8
use Illuminate\Database\Eloquent\Model;
9
use InvalidArgumentException;
10
use Umbrellio\Common\Contracts\AbstractPresenter;
11
use Umbrellio\LTree\Collections\LTreeCollection;
12
use Umbrellio\LTree\Interfaces\LTreeInterface;
13
use Umbrellio\LTree\Interfaces\ModelInterface;
14
15
/**
16
 * @property LTreeInterface|ModelInterface|Model $model
17
 */
18
class LTreeNode extends AbstractPresenter
19
{
20
    protected $parent;
21
    protected $children;
22
23
    public function __construct($model = null)
24
    {
25
        parent::__construct($model);
26
    }
27
28
    public function isRoot(): bool
29
    {
30
        return $this->model === null;
31
    }
32
33
    public function getParent(): ?self
34
    {
35
        return $this->parent;
36
    }
37
38
    public function setParent(?self $parent): void
39
    {
40
        $this->parent = $parent;
41
    }
42
43
    public function addChild(self $node): void
44
    {
45
        $this
46
            ->getChildren()
47
            ->add($node);
48
        $node->setParent($this);
49
    }
50
51
    public function getChildren(): Collection
52
    {
53
        if (!$this->children) {
54
            $this->children = new Collection();
55
        }
56
        return $this->children;
57
    }
58
59
    public function countDescendants(): int
60
    {
61
        return $this
62
            ->getChildren()
63
            ->reduce(
64
                static function (int $count, self $node) {
65
                    return $count + $node->countDescendants();
66
                },
67
                $this
68
                    ->getChildren()
69
                    ->count()
70
            );
71
    }
72
73
    public function findInTree(int $id): ?self
74
    {
75
        if (!$this->isRoot() && $this->model->getKey() === $id) {
0 ignored issues
show
The method getKey() does not exist on Illuminate\Database\Eloquent\Model. It seems like you code against a sub-type of Illuminate\Database\Eloquent\Model such as Umbrellio\LTree\tests\_data\Models\CategoryStub or Umbrellio\LTree\tests\_data\Models\ProductStub. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
        if (!$this->isRoot() && $this->model->/** @scrutinizer ignore-call */ getKey() === $id) {
Loading history...
The method getKey() does not exist on Umbrellio\LTree\Interfaces\LTreeInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Umbrellio\LTree\Interfaces\LTreeInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
        if (!$this->isRoot() && $this->model->/** @scrutinizer ignore-call */ getKey() === $id) {
Loading history...
76
            return $this;
77
        }
78
        foreach ($this->getChildren() as $child) {
79
            $result = $child->findInTree($id);
80
            if ($result !== null) {
81
                return $result;
82
            }
83
        }
84
        return null;
85
    }
86
87
    public function each(callable $callback): void
88
    {
89
        if (!$this->isRoot()) {
90
            $callback($this);
91
        }
92
        $this
93
            ->getChildren()
94
            ->each(static function (self $node) use ($callback) {
95
                $node->each($callback);
96
            });
97
    }
98
99
    public function toCollection(): LTreeCollection
100
    {
101
        $collection = new LTreeCollection();
102
        $this->each(static function (self $item) use ($collection) {
103
            $collection->add($item->model);
104
        });
105
        return $collection;
106
    }
107
108
    public function pathAsString()
109
    {
110
        return $this->model ? $this->model->getLtreePath(LTreeInterface::AS_STRING) : null;
0 ignored issues
show
The method getLtreePath() does not exist on Illuminate\Database\Eloquent\Model. It seems like you code against a sub-type of Illuminate\Database\Eloquent\Model such as Umbrellio\LTree\tests\_data\Models\CategoryStub or Umbrellio\LTree\tests\_data\Models\ProductStub. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

110
        return $this->model ? $this->model->/** @scrutinizer ignore-call */ getLtreePath(LTreeInterface::AS_STRING) : null;
Loading history...
The method getLtreePath() does not exist on Umbrellio\LTree\Interfaces\ModelInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Umbrellio\LTree\Interfaces\ModelInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

110
        return $this->model ? $this->model->/** @scrutinizer ignore-call */ getLtreePath(LTreeInterface::AS_STRING) : null;
Loading history...
111
    }
112
113
    public function toTreeArray(callable $callback)
114
    {
115
        return $this->fillTreeArray($this->getChildren(), $callback);
116
    }
117
118
    /**
119
     * Usage sortTree(['name' =>'asc', 'category'=>'desc'])
120
     * or callback with arguments ($a, $b) and return -1 | 0 | 1
121
     * @param array|callable $options
122
     */
123
    public function sortTree($options)
124
    {
125
        $children = $this->getChildren();
126
        $callback = $options;
127
        if (!is_callable($options)) {
128
            $callback = $this->optionsToCallback($options);
129
        }
130
        $children->each(static function ($child) use ($callback) {
131
            /** @var LTreeNode $child */
132
            $child->sortTree($callback);
133
        });
134
        $this->children = $children
135
            ->sort($callback)
136
            ->values();
137
    }
138
139
    private function fillTreeArray(iterable $nodes, callable $callback)
140
    {
141
        $data = [];
142
        foreach ($nodes as $node) {
143
            $item = $callback($node);
144
            $children = $this->fillTreeArray($node->getChildren(), $callback);
145
            $item['children'] = $children;
146
            $data[] = $item;
147
        }
148
        return $data;
149
    }
150
151
    private function optionsToCallback(array $options): callable
152
    {
153
        return function ($a, $b) use ($options) {
154
            foreach ($options as $property => $sort) {
155
                if (!in_array(strtolower($sort), ['asc', 'desc'], true)) {
156
                    throw new InvalidArgumentException("Order '${sort}'' must be asc or desc");
157
                }
158
                $order = strtolower($sort) === 'desc' ? -1 : 1;
159
                $result = $a->{$property} <=> $b->{$property};
160
                if ($result !== 0) {
161
                    return $result * $order;
162
                }
163
            }
164
            return 0;
165
        };
166
    }
167
}
168