OrderCollectionTrait   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 153
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 34
dl 0
loc 153
rs 10
c 1
b 0
f 0
wmc 18

7 Methods

Rating   Name   Duplication   Size   Complexity  
A traverseOrders() 0 15 3
A setOrders() 0 5 1
A addOrder() 0 4 1
B processOrder() 0 29 7
A orders() 0 3 1
A hasOrders() 0 3 1
A addOrders() 0 13 4
1
<?php
2
3
namespace Charcoal\Source;
4
5
use InvalidArgumentException;
6
7
// From 'charcoal-core'
8
use Charcoal\Source\Order;
9
use Charcoal\Source\OrderInterface;
10
use Charcoal\Source\OrderCollectionInterface;
11
12
/**
13
 * Provides a order expression list.
14
 *
15
 * Satisfies {@see OrderCollectionInterface}.
16
 */
17
trait OrderCollectionTrait
18
{
19
    /**
20
     * The list of query sorting objects.
21
     *
22
     * For example: one key of the array might look like "RAND()"
23
     * or `{ "property": "col", "direction": "ASC" }`.
24
     *
25
     * @var OrderInterface[]
26
     */
27
    protected $orders = [];
28
29
    /**
30
     * Replace the query order(s) on this object.
31
     *
32
     * Note: Any existing orders are dropped.
33
     *
34
     * @param  mixed[] $orders One or more orders to set on this expression.
35
     * @return self
36
     */
37
    public function setOrders(array $orders)
38
    {
39
        $this->orders = [];
40
        $this->addOrders($orders);
41
        return $this;
42
    }
43
44
    /**
45
     * Append one or more query orders on this object.
46
     *
47
     * @uses   self::processOrder()
48
     * @param  mixed[] $orders One or more orders to add on this expression.
49
     * @return self
50
     */
51
    public function addOrders(array $orders)
52
    {
53
        foreach ($orders as $key => $order) {
54
            $this->addOrder($order);
55
56
            /** Name the expression if $key is a non-numeric string. */
57
            if (is_string($key) && !is_numeric($key)) {
58
                $order = end($this->orders);
59
                $order->setName($key);
60
            }
61
        }
62
63
        return $this;
64
    }
65
66
    /**
67
     * Append a query order on this object.
68
     *
69
     * @uses   self::processOrder()
70
     * @param  mixed $order The expression string, structure, object, or callable to be parsed.
71
     * @return self
72
     */
73
    public function addOrder($order)
74
    {
75
        $this->orders[] = $this->processOrder($order);
76
        return $this;
77
    }
78
79
    /**
80
     * Process a query order to build a tree of expressions.
81
     *
82
     * Implement in subclasses to dynamically parse orders before being appended.
83
     *
84
     * @param  mixed $order The expression string, structure, object, or callable to be parsed.
85
     * @throws InvalidArgumentException If a order is not a string, array, object, or callable.
86
     * @return OrderInterface
87
     */
88
    protected function processOrder($order)
89
    {
90
        if (!is_string($order) && is_callable($order)) {
91
            $expr  = $this->createOrder();
92
            /**
93
             * @param  OrderInterface           $expr The new order expression object.
94
             * @param  OrderCollectionInterface $this The context of the collection.
95
             * @return string|array|OrderInterface The prepared order expression
96
             *     string, structure, object.
97
             */
98
            $order = $order($expr, $this);
99
        }
100
101
        if (is_string($order)) {
102
            $expr  = $this->createOrder()->setCondition($order);
0 ignored issues
show
Bug introduced by
The method setCondition() does not exist on Charcoal\Source\OrderInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Charcoal\Source\OrderInterface. ( Ignorable by Annotation )

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

102
            $expr  = $this->createOrder()->/** @scrutinizer ignore-call */ setCondition($order);
Loading history...
103
            $order = $expr;
104
        } elseif (is_array($order)) {
105
            $expr  = $this->createOrder()->setData($order);
0 ignored issues
show
Bug introduced by
The method setData() does not exist on Charcoal\Source\OrderInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Charcoal\Source\OrderInterface. ( Ignorable by Annotation )

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

105
            $expr  = $this->createOrder()->/** @scrutinizer ignore-call */ setData($order);
Loading history...
106
            $order = $expr;
107
        }
108
109
        /** Append the order to the expression's stack. */
110
        if ($order instanceof OrderInterface) {
111
            return $order;
112
        }
113
114
        throw new InvalidArgumentException(sprintf(
115
            'Order must be a string, structure, or Expression object; received %s',
116
            is_object($order) ? get_class($order) : gettype($order)
117
        ));
118
    }
119
120
    /**
121
     * Determine if the object has any query orders.
122
     *
123
     * @return boolean
124
     */
125
    public function hasOrders()
126
    {
127
        return !empty($this->orders);
128
    }
129
130
    /**
131
     * Retrieve the query orders stored in this object.
132
     *
133
     * @return array
134
     */
135
    public function orders()
136
    {
137
        return $this->orders;
138
    }
139
140
    /**
141
     * Traverses the tree of query orders and applies a user function to every expression.
142
     *
143
     * @param  callable $callable The function to run for each expression.
144
     * @return self
145
     */
146
    public function traverseOrders(callable $callable)
147
    {
148
        foreach ($this->orders() as $expr) {
149
            /**
150
             * @param  OrderInterface           $expr The iterated order expression object.
151
             * @param  OrderCollectionInterface $this The context of the traversal.
152
             * @return void
153
             */
154
            $callable($expr, $this);
155
            if ($expr instanceof OrderCollectionInterface) {
156
                $expr->traverseOrders($callable);
0 ignored issues
show
Bug introduced by
The method traverseOrders() does not exist on Charcoal\Source\OrderInterface. It seems like you code against a sub-type of Charcoal\Source\OrderInterface such as Charcoal\Tests\Mock\OrderTree. ( Ignorable by Annotation )

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

156
                $expr->/** @scrutinizer ignore-call */ 
157
                       traverseOrders($callable);
Loading history...
Bug introduced by
The method traverseOrders() does not exist on Charcoal\Source\OrderCollectionInterface. It seems like you code against a sub-type of Charcoal\Source\OrderCollectionInterface such as Charcoal\Tests\Mock\OrderCollectionClass or Charcoal\Tests\Mock\OrderTree or Charcoal\Source\AbstractSource. ( Ignorable by Annotation )

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

156
                $expr->/** @scrutinizer ignore-call */ 
157
                       traverseOrders($callable);
Loading history...
157
            }
158
        }
159
160
        return $this;
161
    }
162
163
    /**
164
     * Create a new query sorting expression.
165
     *
166
     * @param  array $data Optional expression data.
167
     * @return OrderInterface A new order expression object.
168
     */
169
    abstract protected function createOrder(array $data = null);
170
}
171