Passed
Push — master ( c2b947...93db86 )
by Carlos
02:53
created

EmbeddableTrait   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 153
Duplicated Lines 0 %

Test Coverage

Coverage 95.92%

Importance

Changes 0
Metric Value
eloc 52
dl 0
loc 153
ccs 47
cts 49
cp 0.9592
rs 10
c 0
b 0
f 0
wmc 23

5 Methods

Rating   Name   Duplication   Size   Complexity  
A resolveExpandList() 0 20 5
A getExpandEnvelope() 0 3 1
A processField() 0 5 2
B toArray() 0 49 10
A resolveFieldList() 0 16 5
1
<?php
2
3
namespace roaresearch\yii2\roa\hal;
4
5
use yii\base\Arrayable;
6
use yii\base\ArrayableTrait;
7
use yii\helpers\ArrayHelper;
8
use yii\web\Link;
9
use yii\web\Linkable;
10
11
/**
12
 * Interface to get a the information of a file associated to a model.
13
 *
14
 * @author Angel (Faryshta) Guevara <[email protected]>
15
 */
16
trait EmbeddableTrait
17
{
18
    use ArrayableTrait;
19
20
    /**
21
     * @inheritdoc
22
     */
23
    public abstract function fields();
24
25
    /**
26
     * @inheritdoc
27
     */
28
    public abstract function extraFields();
29
30
    /**
31
     * @inheritdoc
32
     */
33 9
    public function toArray(
34
        array $fields = [],
35
        array $expand = [],
36
        $recursive = true
37
    ) {
38 9
        $data = [];
39 9
        foreach ($this->resolveFieldList($fields) as $field => $definition) {
40 9
            $data[$field] = $this->processField($field, $definition);
41
        }
42
43 9
        foreach ($this->resolveExpandList($expand) as $field => $definition) {
44 4
            $attribute = $this->processField($field, $definition);
45
46 4
            if ($recursive) {
47 4
                $nestedFields = $this->extractFieldsFor($fields, $field);
48 4
                $nestedExpand = $this->extractFieldsFor($expand, $field);
49 4
                if ($attribute instanceof Arrayable) {
50 2
                    $attribute = $attribute->toArray(
51
                        $nestedFields,
52
                        $nestedExpand
53
                    );
54 2
                } elseif (is_array($attribute)) {
55 2
                    $attribute = array_map(
56 2
                        function ($item) use ($nestedFields, $nestedExpand) {
57 2
                            if ($item instanceof Arrayable) {
58 2
                                return $item->toArray(
59
                                    $nestedFields,
60
                                    $nestedExpand
61
                                );
62
                            }
63
                            return $item;
64
                        },
65
                        $attribute
66
                    );
67
                }
68
            }
69
70 4
            if ($envelope = $this->getExpandEnvelope()) {
71 4
                $data[$envelope][$field] = $attribute;
72
            } else {
73
                $data[$field] = $attribute;
74
            }
75
        }
76
77 9
        if ($this instanceof Linkable) {
78 9
            $data['_links'] = Link::serialize($this->getLinks());
79
        }
80
81 9
        return $recursive ? ArrayHelper::toArray($data) : $data;
82
    }
83
84
    /**
85
     * @return string property which will contain all the expanded parameters.
86
     */
87 4
    public function getExpandEnvelope(): string
88
    {
89 4
        return Embeddable::EMBEDDED_PROPERTY;
90
    }
91
92
    /**
93
     * Determines which fields can be returned by [[toArray()]].
94
     * This method will first extract the root fields from the given fields.
95
     * Then it will check the requested root fields against those declared in
96
     * [[fields()]] to determine which fields can be returned.
97
     *
98
     * @param array $fields the fields being requested for exporting
99
     * @return array the list of fields to be exported. The array keys are the
100
     * field names, and the array values are the corresponding object property
101
     * names or PHP callables returning the field values.
102
     */
103 9
    protected function resolveFieldList($fields): array
104
    {
105 9
        $fields = $this->extractRootFields($fields);
106 9
        $result = [];
107
108 9
        foreach ($this->fields() as $field => $definition) {
109 9
                if (is_int($field)) {
110 7
                    $field = $definition;
111
                }
112
113 9
                if (empty($fields) || in_array($field, $fields, true)) {
114 9
                    $result[$field] = $definition;
115
                }
116
        }
117
118 9
        return $result;
119
    }
120
121
    /**
122
     * Determines which expand fields can be returned by [[toArray()]].
123
     * This method will first extract the root fields from the given expand.
124
     * Then it will check the requested root fields against those declared in
125
     * [[extraFields()]] to determine which fields can be returned.
126
     *
127
     * @param array $expand the expand fields being requested for exporting
128
     * @return array the list of fields to be exported. The array keys are the
129
     * field names, and the array values are the corresponding object property
130
     * names or PHP callables returning the field values.
131
     */
132 9
    protected function resolveExpandList($expand): array
133
    {
134 9
        if (empty($expand)) {
135 9
            return [];
136
        }
137
138 4
        $fields = $this->extractRootFields($expand);
139 4
        $result = [];
140
141 4
        foreach ($this->extraFields() as $field => $definition) {
142 4
                if (is_int($field)) {
143 4
                    $field = $definition;
144
                }
145
146 4
                if (in_array($field, $fields, true)) {
147 4
                    $result[$field] = $definition;
148
                }
149
        }
150
151 4
        return $result;
152
    }
153
154
    /**
155
     * @param string $field name of the field to be resolved.
156
     * @param string|callable $definition the field definition, it its an string
157
     * it will be used as a property name, or a callable with signature.
158
     *
159
     * ```php
160
     * function ($model, string $field)
161
     * ```
162
     * @return mixed data obtained from the model.
163
     */
164 9
    protected function processField($field, $definition)
165
    {
166 9
        return is_string($definition)
167 9
            ? $this->$definition
168 9
            : $definition($this, $field);
169
    }
170
}
171