Completed
Push — tmp-dev ( 70449b...91d361 )
by Romain
02:16
created

ParentsTrait::attachParents()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
/*
3
 * 2017 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\Core\Core;
17
use Romm\ConfigurationObject\Exceptions\DuplicateEntryException;
18
use Romm\ConfigurationObject\Exceptions\EntryNotFoundException;
19
use Romm\ConfigurationObject\Exceptions\InvalidTypeException;
20
use TYPO3\CMS\Core\Utility\GeneralUtility;
21
22
/**
23
 * Use this trait in your configuration objects (it will work only if they do
24
 * use the service `ParentsService`).
25
 *
26
 * It will store the parent objects of the current object.
27
 */
28
trait ParentsTrait
29
{
30
31
    /**
32
     * Note: must be private, or the TYPO3 reflection services will go in an
33
     * infinite loop.
34
     *
35
     * @var object[]
36
     */
37
    private $_parents = [];
38
39
    /**
40
     * @param object[] $parents
41
     *
42
     * @deprecated This function is deprecated and will be removed in v2!
43
     *             Use function `addParents()` instead.
44
     */
45
    public function setParents(array $parents)
46
    {
47
        GeneralUtility::logDeprecatedFunction();
48
49
        $this->_parents = $parents;
50
    }
51
52
    /**
53
     * @param object $parent
54
     * @param bool   $direct If true, the parent will be added as the direct (closest) parent of this object.
55
     * @return $this
56
     * @throws DuplicateEntryException
57
     * @throws InvalidTypeException
58
     */
59
    public function attachParent($parent, $direct = true)
60
    {
61
        if (false === is_object($parent)) {
62
            throw new InvalidTypeException(
63
                'The parent must be an object, "' . gettype($parent) . '" was given.',
64
                1493804124
65
            );
66
        }
67
68
        foreach ($this->_parents as $parentItem) {
69
            if ($parent === $parentItem) {
70
                throw new DuplicateEntryException(
71
                    'The given parent (' . get_class($parent) . ') was already attached to this object (' . get_class($this) . ').',
72
                    1493804518
73
                );
74
            }
75
        }
76
77
        if (true === $direct) {
78
            array_unshift($this->_parents, $parent);
79
        } else {
80
            array_push($this->_parents, $parent);
81
        }
82
83
        return $this;
84
    }
85
86
    /**
87
     * Loops on each given parent and attach it to this object.
88
     *
89
     * The order matters: the first item will be added as a direct parent
90
     * whereas the last one will be the remote parent.
91
     *
92
     * Note that this function will also reset
93
     *
94
     * @param object[] $parents
95
     */
96
    public function attachParents(array $parents)
97
    {
98
        $this->_parents = [];
99
100
        foreach ($parents as $parent) {
101
            $this->attachParent($parent, false);
102
        }
103
    }
104
105
    /**
106
     * Will fetch the first parent which matches the given class name.
107
     *
108
     * If a parent is found, then `$callback` is called, and its returned value
109
     * is returned by this function.
110
     *
111
     * If no parent is found, then `$notFoundCallBack` is called if it was
112
     * defined.
113
     *
114
     * @param string   $parentClassName  Name of the class name of the wanted parent.
115
     * @param callable $callBack         A closure which will be called if the parent is found.
116
     * @param callable $notFoundCallBack A closure which is called if the parent is not found.
117
     * @return mixed|null
118
     */
119
    public function withFirstParent($parentClassName, callable $callBack, callable $notFoundCallBack = null)
120
    {
121
        // We first check if the registered parents do match the wanted parent.
122
        foreach ($this->_parents as $parent) {
123
            if ($parent instanceof $parentClassName) {
124
                return $callBack($parent);
125
            }
126
        }
127
128
        // Then, we check each parent's parents.
129
        foreach ($this->_parents as $parent) {
130
            if (Core::get()->getParentsUtility()->classUsesParentsTrait($parent)) {
131
                /** @var ParentsTrait $parent */
132
                return $parent->withFirstParent($parentClassName, $callBack, $notFoundCallBack);
133
            }
134
        }
135
136
        return (null !== $notFoundCallBack)
137
            ? $notFoundCallBack()
138
            : null;
139
    }
140
141
    /**
142
     * Returns true if the class has a given parent.
143
     *
144
     * @param string $parentClassName Name of the parent class.
145
     * @return bool
146
     */
147
    public function hasParent($parentClassName)
148
    {
149
        foreach ($this->_parents as $parent) {
150
            if ($parent instanceof $parentClassName) {
151
                return true;
152
            }
153
        }
154
155
        return false;
156
    }
157
158
    /**
159
     * Returns the first found instance of the desired parent.
160
     *
161
     * An exception is thrown if the parent is not found. It is advised to use
162
     * the function `hasParent()` before using this function.
163
     *
164
     * @param string $parentClassName Name of the parent class.
165
     * @return object
166
     * @throws EntryNotFoundException
167
     */
168
    public function getFirstParent($parentClassName)
169
    {
170
        foreach ($this->_parents as $parent) {
171
            if ($parent instanceof $parentClassName) {
172
                return $parent;
173
            }
174
        }
175
176
        throw new EntryNotFoundException(
177
            'The parent "' . $parentClassName . '" was not found in this object (class "' . get_class($this) . '"). Use the function "hasParent()" before your call to this function!',
178
            1471379635
179
        );
180
    }
181
}
182