Completed
Branch CASC/initial-ui (c5e0e6)
by
unknown
32:13 queued 24:29
created

RelationNode::isComplete()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11

Duplication

Lines 5
Ratio 45.45 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 0
dl 5
loc 11
rs 9.9
c 0
b 0
f 0
1
<?php
2
3
namespace EventEspresso\core\services\orm\tree_traversal;
4
5
use EE_Base_Class;
6
use EE_Error;
7
use EE_Model_Relation_Base;
8
use EEM_Base;
9
use EventEspresso\core\exceptions\InvalidDataTypeException;
10
use EventEspresso\core\exceptions\InvalidInterfaceException;
11
use EventEspresso\core\services\payment_methods\forms\PayPalSettingsForm;
12
use InvalidArgumentException;
13
use ReflectionException;
14
15
/**
16
 * Class RelationNode
17
 *
18
 * Wraps a model object and one of its model's relations; stores how many related model objects exist across that
19
 * relation, and eventually createsa a ModelObjNode for each of its related model objects.
20
 *
21
 * @package     Event Espresso
22
 * @author         Mike Nelson
23
 * @since         $VID:$
24
 *
25
 */
26
class RelationNode extends BaseNode
27
{
28
    /**
29
     * @var EE_Base_Class
30
     */
31
    protected $main_model_obj;
32
33
    /**
34
     * @var int
35
     */
36
    protected $count;
37
38
    /**
39
     * @var EEM_Base
40
     */
41
    protected $related_model;
42
43
44
    protected $model_obj_nodes;
45
46
    public function __construct($main_model_obj, $related_model)
47
    {
48
        $this->main_model_obj = $main_model_obj;
49
        $this->related_model = $related_model;
50
        $this->model_obj_nodes = [];
51
    }
52
53
54
    /**
55
     * Here is where most of the work happens. We've counted how many related model objects exist, here we identify
56
     * them (ie, learn their IDs). But its recursive, so we'll also find their related dependent model objects etc.
57
     * @since $VID:$
58
     * @param int $model_objects_to_identify
59
     * @return int
60
     * @throws EE_Error
61
     * @throws InvalidArgumentException
62
     * @throws InvalidDataTypeException
63
     * @throws InvalidInterfaceException
64
     * @throws ReflectionException
65
     */
66
    protected function work($model_objects_to_identify)
67
    {
68
        $num_identified = $this->visitAlreadyDiscoveredNodes($this->model_obj_nodes, $model_objects_to_identify);
69
        if ($num_identified < $model_objects_to_identify) {
70
            $related_model_objs = $this->related_model->get_all(
71
                [
72
                    $this->whereQueryParams(),
73
                    'limit' => [
74
                        count($this->model_obj_nodes),
75
                        $model_objects_to_identify
76
                    ]
77
                ]
78
            );
79
            $new_item_nodes = [];
80
81
            // Add entity nodes for each of the model objects we fetched.
82
            foreach ($related_model_objs as $related_model_obj) {
83
                $entity_node = new ModelObjNode($related_model_obj);
84
                $this->model_obj_nodes[ $related_model_obj->ID() ] = $entity_node;
85
                $new_item_nodes[ $related_model_obj->ID() ] = $entity_node;
86
            }
87
            $num_identified += count($new_item_nodes);
88
            if ($num_identified < $model_objects_to_identify) {
89
                // And lastly do the work.
90
                $num_identified += $this->visitAlreadyDiscoveredNodes(
91
                    $new_item_nodes,
92
                    $model_objects_to_identify - $num_identified
93
                );
94
            }
95
        }
96
97 View Code Duplication
        if (count($this->model_obj_nodes) >= $this->count && $this->allChildrenComplete()) {
98
            $this->complete = true;
99
        }
100
        return $num_identified;
101
    }
102
103
    /**
104
     * Checks if all the identified child nodes are complete or not.
105
     * @since $VID:$
106
     * @return bool
107
     */
108
    protected function allChildrenComplete()
109
    {
110
        foreach ($this->model_obj_nodes as $model_obj_node) {
111
            if (! $model_obj_node->isComplete()) {
112
                return false;
113
            }
114
        }
115
        return true;
116
    }
117
118
    /**
119
     * Visits the provided nodes and keeps track of how much work was done, making sure to not go over budget.
120
     * @since $VID:$
121
     * @param ModelObjNode[] $model_obj_nodes
122
     * @param $work_budget
123
     * @return int
124
     */
125
    protected function visitAlreadyDiscoveredNodes($model_obj_nodes, $work_budget)
126
    {
127
        $work_done = 0;
128
        if (! $model_obj_nodes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $model_obj_nodes of type EventEspresso\core\servi...raversal\ModelObjNode[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
129
            return 0;
130
        }
131
        foreach ($model_obj_nodes as $model_obj_node) {
132
            if ($work_done >= $work_budget) {
133
                break;
134
            }
135
            $work_done += $model_obj_node->visit($work_budget - $work_done);
136
        }
137
        return $work_done;
138
    }
139
140
    /**
141
     * Whether this item has already been initialized
142
     */
143
    protected function isDiscovered()
144
    {
145
        return $this->count !== null;
146
    }
147
148
    /**
149
     * @since $VID:$
150
     * @return boolean
151
     */
152
    public function isComplete()
153
    {
154
        if ($this->complete === null) {
155 View Code Duplication
            if (count($this->model_obj_nodes) === $this->count) {
156
                $this->complete = true;
157
            } else {
158
                $this->complete = false;
159
            }
160
        }
161
        return $this->complete;
162
    }
163
164
    /**
165
     * Discovers how many related model objects exist.
166
     * @since $VID:$
167
     * @return mixed|void
168
     * @throws EE_Error
169
     * @throws InvalidArgumentException
170
     * @throws InvalidDataTypeException
171
     * @throws InvalidInterfaceException
172
     * @throws ReflectionException
173
     */
174
    protected function discover()
175
    {
176
        $this->count = $this->related_model->count([$this->whereQueryParams()]);
177
    }
178
179
    /**
180
     * @since $VID:$
181
     * @return array
182
     * @throws EE_Error
183
     * @throws InvalidDataTypeException
184
     * @throws InvalidInterfaceException
185
     * @throws InvalidArgumentException
186
     * @throws ReflectionException
187
     */
188
    protected function whereQueryParams()
189
    {
190
        return [
191
            $this->related_model->get_foreign_key_to(
192
                $this->main_model_obj->get_model()->get_this_model_name()
193
            )->get_name() => $this->main_model_obj->ID()
194
        ];
195
    }
196
    /**
197
     * @since $VID:$
198
     * @return array
199
     */
200
    public function toArray()
201
    {
202
        $tree = [
203
            'count' => $this->count,
204
            'complete' => $this->isComplete(),
205
            'objs' => []
206
        ];
207
        foreach ($this->model_obj_nodes as $id => $model_obj_node) {
208
            $tree['objs'][ $id ] = $model_obj_node->toArray();
209
        }
210
        return $tree;
211
    }
212
}
213
// End of file RelationNode.php
214
// Location: EventEspresso\core\services\orm\tree_traversal/RelationNode.php
215