Completed
Branch CASC/dont-traverse-models (6dd8d8)
by
unknown
19:31 queued 10:56
created

ModelObjNode   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 0
loc 200
rs 10
c 0
b 0
f 0
wmc 25
lcom 1
cbo 6
1
<?php
2
3
namespace EventEspresso\core\services\orm\tree_traversal;
4
5
use EE_HABTM_Relation;
6
use EE_Has_Many_Relation;
7
use EE_Registry;
8
use EEM_Base;
9
use EventEspresso\core\exceptions\InvalidDataTypeException;
10
use EventEspresso\core\exceptions\InvalidInterfaceException;
11
use InvalidArgumentException;
12
use ReflectionException;
13
14
/**
15
 * Class ModelObjNode
16
 * Wraps a model object and stores which of its model's relations have already been traversed and which haven't.
17
 *
18
 * @package     Event Espresso
19
 * @author         Mike Nelson
20
 * @since         $VID:$
21
 *
22
 */
23
class ModelObjNode extends BaseNode
24
{
25
    /**
26
     * @var int|string
27
     */
28
    protected $id;
29
30
    /**
31
     * @var EEM_Base
32
     */
33
    protected $model;
34
35
    /**
36
     * @var RelationNode[]
37
     */
38
    protected $nodes;
39
40
    /**
41
     * We don't pass the model objects because this needs to serialize to something tiny for effiency.
42
     * @param $model_obj_id
43
     * @param EEM_Base $model
44
     */
45
    public function __construct($model_obj_id, EEM_Base $model, array $dont_traverse_models = []])
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ']', expecting ')'
Loading history...
46
    {
47
        $this->id = $model_obj_id;
48
        $this->model = $model;
49
        $this->dont_traverse_models = $dont_traverse_models;
50
    }
51
52
    /**
53
     * Creates a relation node for each relation of this model's relations.
54
     * Does NOT call `discover` on them yet though.
55
     * @since $VID:$
56
     * @throws \EE_Error
57
     * @throws InvalidDataTypeException
58
     * @throws InvalidInterfaceException
59
     * @throws InvalidArgumentException
60
     * @throws ReflectionException
61
     */
62
    protected function discover()
63
    {
64
        $this->nodes = [];
65
        foreach ($this->model->relation_settings() as $relationName => $relation) {
66
            // Make sure this isn't one of the models we were told to not traverse into.
67
            if (in_array($relationName, $this->dont_traverse_models)) {
68
                continue;
69
            }
70
            if ($relation instanceof EE_Has_Many_Relation) {
71
                $this->nodes[ $relationName ] = new RelationNode(
72
                    $this->id,
73
                    $this->model,
74
                    $relation->get_other_model(),
75
                    $this->dont_traverse_models
76
                );
77
            } elseif ($relation instanceof EE_HABTM_Relation &&
78
                ! in_array(
79
                    $relation->get_join_model()->get_this_model_name(),
80
                    $this->dont_traverse_models
81
                )) {
82
                $this->nodes[ $relation->get_join_model()->get_this_model_name() ] = new RelationNode(
83
                    $this->id,
84
                    $this->model,
85
                    $relation->get_join_model(),
86
                    $this->dont_traverse_models
87
                );
88
            }
89
        }
90
        ksort($this->nodes);
91
    }
92
93
94
    /**
95
     * Whether this item has already been initialized
96
     */
97
    protected function isDiscovered()
98
    {
99
        return $this->nodes !== null && is_array($this->nodes);
100
    }
101
102
    /**
103
     * @since $VID:$
104
     * @return boolean
105
     */
106
    public function isComplete()
107
    {
108
        if ($this->complete === null) {
109
            $this->complete = false;
110
        }
111
        return $this->complete;
112
    }
113
114
    /**
115
     * Triggers working on each child relation node that has work to do.
116
     * @since $VID:$
117
     * @param $model_objects_to_identify
118
     * @return int units of work done
119
     */
120
    protected function work($model_objects_to_identify)
121
    {
122
        $num_identified = 0;
123
        // Begin assuming we'll finish all the work on this node and its children...
124
        $this->complete = true;
125
        foreach ($this->nodes as $model_name => $relation_node) {
126
            $num_identified += $relation_node->visit($model_objects_to_identify - $num_identified);
127
            // To save on space when serializing, only bother keeping a record of relation nodes that actually found
128
            // related model objects.
129
            if ($relation_node->isComplete() && $relation_node->countSubNodes() === 0) {
130
                unset($this->nodes[ $model_name ]);
131
            }
132
            if ($num_identified >= $model_objects_to_identify) {
133
                // ...but admit we're wrong if the work exceeded the budget.
134
                $this->complete = false;
135
                break;
136
            }
137
        }
138
        return $num_identified;
139
    }
140
141
    /**
142
     * @since $VID:$
143
     * @return array
144
     * @throws \EE_Error
145
     * @throws InvalidDataTypeException
146
     * @throws InvalidInterfaceException
147
     * @throws InvalidArgumentException
148
     * @throws ReflectionException
149
     */
150
    public function toArray()
151
    {
152
        $tree = [
153
            'id' => $this->id,
154
            'complete' => $this->isComplete(),
155
            'rels' => []
156
        ];
157
        if ($this->nodes === null) {
158
            $tree['rels'] = null;
159
        } else {
160
            foreach ($this->nodes as $relation_name => $relation_node) {
161
                $tree['rels'][ $relation_name ] = $relation_node->toArray();
162
            }
163
        }
164
        return $tree;
165
    }
166
167
    /**
168
     * @since $VID:$
169
     * @return array|mixed
170
     * @throws InvalidArgumentException
171
     * @throws InvalidDataTypeException
172
     * @throws InvalidInterfaceException
173
     * @throws ReflectionException
174
     * @throws \EE_Error
175
     */
176
    public function getIds()
177
    {
178
        $ids = [
179
            $this->model->get_this_model_name() => [
180
                $this->id => $this->id
181
            ]
182
        ];
183
        if ($this->nodes && is_array($this->nodes)) {
184
            foreach ($this->nodes as $relation_node) {
185
                $ids = array_replace_recursive($ids, $relation_node->getIds());
186
            }
187
        }
188
        return $ids;
189
    }
190
191
    /**
192
     * Don't serialize the models. Just record their names on some dynamic properties.
193
     * @since $VID:$
194
     */
195
    public function __sleep()
196
    {
197
        $this->m = $this->model->get_this_model_name();
198
        return array_merge(
199
            [
200
                'm',
201
                'id',
202
                'nodes',
203
            ],
204
            parent::__sleep()
205
        );
206
    }
207
208
    /**
209
     * Use the dynamic properties to instantiate the models we use.
210
     * @since $VID:$
211
     * @throws EE_Error
212
     * @throws InvalidArgumentException
213
     * @throws InvalidDataTypeException
214
     * @throws InvalidInterfaceException
215
     * @throws ReflectionException
216
     */
217
    public function __wakeup()
218
    {
219
        $this->model = EE_Registry::instance()->load_model($this->m);
220
        parent::__wakeup();
221
    }
222
}
223
// End of file Visitor.php
224
// Location: EventEspresso\core\services\orm\tree_traversal/Visitor.php
225