ParentsTrait::attachParent()   A
last analyzed

Complexity

Conditions 5
Paths 6

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 9.1928
c 0
b 0
f 0
cc 5
nc 6
nop 2
1
<?php
2
/*
3
 * 2018 Romain CANON <[email protected]>
4
 *
5
 * This file is part of the TYPO3 Configuration Object project.
6
 * It is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License, either
8
 * version 3 of the License, or any later version.
9
 *
10
 * For the full copyright and license information, see:
11
 * http://www.gnu.org/licenses/gpl-3.0.html
12
 */
13
14
namespace Romm\ConfigurationObject\Service\Items\Parents;
15
16
use Romm\ConfigurationObject\Exceptions\DuplicateEntryException;
17
use Romm\ConfigurationObject\Exceptions\EntryNotFoundException;
18
use Romm\ConfigurationObject\Exceptions\InvalidTypeException;
19
20
/**
21
 * Use this trait in your configuration objects (it will work only if they do
22
 * use the service `ParentsService`).
23
 *
24
 * It will store the parent objects of the current object.
25
 */
26
trait ParentsTrait
27
{
28
29
    /**
30
     * Note: must be private, or the TYPO3 reflection services will go in an
31
     * infinite loop.
32
     *
33
     * @var object[]
34
     */
35
    private $_parents = [];
36
37
    /**
38
     * @param object[] $parents
39
     *
40
     * @deprecated This function is deprecated and will be removed in v2!
41
     *             Use function `addParents()` instead.
42
     */
43
    public function setParents(array $parents)
44
    {
45
        trigger_error('\Romm\ConfigurationObject\Service\Items\Parents\ParentsTrait->setParents() - This function is deprecated and will be removed in v2!', E_USER_DEPRECATED);
46
47
        $this->_parents = $parents;
48
    }
49
50
    /**
51
     * @param object $parent
52
     * @param bool   $direct If true, the parent will be added as the direct (closest) parent of this object.
53
     * @return $this
54
     * @throws DuplicateEntryException
55
     * @throws InvalidTypeException
56
     */
57
    public function attachParent($parent, $direct = true)
58
    {
59
        if (false === is_object($parent)) {
60
            throw new InvalidTypeException(
61
                'The parent must be an object, "' . gettype($parent) . '" was given.',
62
                1493804124
63
            );
64
        }
65
66
        foreach ($this->_parents as $parentItem) {
67
            if ($parent === $parentItem) {
68
                throw new DuplicateEntryException(
69
                    'The given parent (' . get_class($parent) . ') was already attached to this object (' . get_class($this) . ').',
70
                    1493804518
71
                );
72
            }
73
        }
74
75
        if (true === $direct) {
76
            array_unshift($this->_parents, $parent);
77
        } else {
78
            array_push($this->_parents, $parent);
79
        }
80
81
        return $this;
82
    }
83
84
    /**
85
     * Loops on each given parent and attach it to this object.
86
     *
87
     * The order matters: the first item will be added as a direct parent
88
     * whereas the last one will be the remote parent.
89
     *
90
     * Note that this function will also reset
91
     *
92
     * @param object[] $parents
93
     */
94
    public function attachParents(array $parents)
95
    {
96
        $this->_parents = [];
97
98
        foreach ($parents as $parent) {
99
            $this->attachParent($parent, false);
100
        }
101
    }
102
103
    /**
104
     * Will loop along each parent of this object, and every parent of the
105
     * parents: the given callback is called with a single parameter which is
106
     * the current parent.
107
     *
108
     * When the callback returns `false`, the loop breaks.
109
     *
110
     * @param callable $callback
111
     */
112
    public function alongParents(callable $callback)
113
    {
114
        ParentsRecursiveService::get()->alongParents($callback, $this, $this->_parents);
115
    }
116
117
    /**
118
     * Returns true if the class has a given parent.
119
     *
120
     * @param string $parentClassName Name of the parent class.
121
     * @return bool
122
     */
123
    public function hasParent($parentClassName)
124
    {
125
        $found = false;
126
127
        $this->alongParents(function ($parent) use ($parentClassName, &$found) {
128
            if ($parent instanceof $parentClassName) {
129
                $found = true;
130
131
                return false;
132
            }
133
134
            return true;
135
        });
136
137
        return $found;
138
    }
139
140
    /**
141
     * Will fetch the first parent which matches the given class name.
142
     *
143
     * If a parent is found, then `$callback` is called, and its returned value
144
     * is returned by this function.
145
     *
146
     * If no parent is found, then `$notFoundCallBack` is called if it was
147
     * defined.
148
     *
149
     * @param string   $parentClassName  Name of the class name of the wanted parent.
150
     * @param callable $callback         A closure which will be called if the parent is found.
151
     * @param callable $notFoundCallback A closure which is called if the parent is not found.
152
     * @return mixed|null
153
     */
154
    public function withFirstParent($parentClassName, callable $callback, callable $notFoundCallback = null)
155
    {
156
        $result = null;
157
158
        if ($this->hasParent($parentClassName)) {
159
            $parent = $this->getFirstParent($parentClassName);
160
            $result = call_user_func($callback, $parent);
161
        } elseif (null !== $notFoundCallback) {
162
            $result = call_user_func($notFoundCallback);
163
        }
164
165
        return $result;
166
    }
167
168
    /**
169
     * Returns the first found instance of the desired parent.
170
     *
171
     * An exception is thrown if the parent is not found. It is advised to use
172
     * the function `hasParent()` before using this function.
173
     *
174
     * @param string $parentClassName Name of the parent class.
175
     * @return object
176
     * @throws EntryNotFoundException
177
     */
178
    public function getFirstParent($parentClassName)
179
    {
180
        $foundParent = null;
181
182
        $this->alongParents(function ($parent) use ($parentClassName, &$foundParent) {
183
            if ($parent instanceof $parentClassName) {
184
                $foundParent = $parent;
185
186
                return false;
187
            }
188
189
            return true;
190
        });
191
192
        if (null === $foundParent) {
193
            throw new EntryNotFoundException(
194
                'The parent "' . $parentClassName . '" was not found in this object (class "' . get_class($this) . '"). Use the function "hasParent()" before your call to this function!',
195
                1471379635
196
            );
197
        }
198
199
        return $foundParent;
200
    }
201
}
202