EmbeddableTrait::toArray()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 36
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 21
nc 4
nop 3
dl 0
loc 36
ccs 15
cts 15
cp 1
crap 6
rs 8.9617
c 0
b 0
f 0
1
<?php
2
3
namespace roaresearch\yii2\roa\hal;
4
5
use Closure;
6
use roaresearch\yii2\roa\ArrayHelper;
7
use yii\{base\Arrayable, web\Link, web\Linkable};
8
9
/**
10
 * Interface to get a the information of a file associated to a model.
11
 *
12
 * @author Angel (Faryshta) Guevara <[email protected]>
13
 */
14
trait EmbeddableTrait
15
{
16
    /**
17
     * @inheritdoc
18
     */
19 9
    public function toArray(
20
        array $fields = [],
21
        array $expand = [],
22
        $recursive = true
23
    ) {
24 9
        $processField = Closure::fromCallable([$this, 'processField']);
25
26 9
        $data = ArrayHelper::normalizeFilter(
27 9
            $this->fields() + ($this instanceof Linkable
0 ignored issues
show
Bug introduced by
It seems like fields() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

27
            $this->/** @scrutinizer ignore-call */ 
28
                   fields() + ($this instanceof Linkable
Loading history...
28 9
                ? ['_links' => fn () => Link::serialize($this->getLinks())]
0 ignored issues
show
Bug introduced by
It seems like getLinks() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

28
                ? ['_links' => fn () => Link::serialize($this->/** @scrutinizer ignore-call */ getLinks())]
Loading history...
29 9
                : []
30
            ),
31
            $fields,
32
            $processField
33
        );
34
35 9
        $expanded = ArrayHelper::normalizeStrict(
36 9
            $this->extraFields(),
0 ignored issues
show
Bug introduced by
It seems like extraFields() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

36
            $this->/** @scrutinizer ignore-call */ 
37
                   extraFields(),
Loading history...
37
            $expand,
38 9
            $recursive
39 9
                ? fn ($field, $definition) => $this->processRecursiveField(
40
                    $field,
41
                    $definition,
42
                    $fields,
43
                    $expand,
44
                )
45 9
                : $processField 
46
        );
47
48 9
        if (($envelope = $this->getExpandEnvelope()) && !empty($expanded)) {
49 4
            $data[$envelope] = $expanded;
50
        } else {
51 9
            $data += $expanded;
52
        }
53
54 9
        return $recursive ? ArrayHelper::toArray($data) : $data;
55
    }
56
57
    /**
58
     * @return string property which will contain all the expanded parameters.
59
     */
60 9
    public function getExpandEnvelope(): string
61
    {
62 9
        return Embeddable::EMBEDDED_PROPERTY;
63
    }
64
65
    /**
66
     * @param string $field name of the field to be resolved.
67
     * @param string|callable $definition the field definition, it its an string
68
     * it will be used as a property name, or a callable with signature.
69
     *
70
     * ```php
71
     * function ($model, string $field)
72
     * ```
73
     * @return mixed data obtained from the model.
74
     */
75 9
    protected function processField(string $field, $definition)
76
    {
77 9
        return is_string($definition)
78 9
            ? $this->$definition
79 9
            : $definition($this, $field);
80
    }
81
82
    /**
83
     * @param string $field name of the field to be resolved.
84
     * @param string|callable $definition the field definition, it its an string
85
     * it will be used as a property name, or a callable with signature.
86
     *
87
     * ```php
88
     * function ($model, string $field)
89
     * ```
90
     * @param array $fields
91
     * @param array $expand
92
     * @return mixed data obtained from the model.
93
     */
94 4
    protected function processRecursiveField(
95
        string $field,
96
        $definition,
97
        array $fields,
98
        array $expand
99
    ) {
100
        // notice that if this function is callled it means $expand is not empty
101
        // and the call is recursive
102 4
        $attribute = $this->processField($field, $definition);
103 4
        $nestedFields = ArrayHelper::fieldsFor($fields, $field);
104 4
        $nestedExpand = ArrayHelper::fieldsFor($expand, $field);
105
106 4
        if ($attribute instanceof Arrayable) {
107 2
            return $attribute->toArray(
108
                $nestedFields,
109
                $nestedExpand
110
            );
111 2
        } elseif (is_array($attribute)) {
112 2
            return array_map(
113 2
                fn ($item) => $item instanceof Arrayable 
114 2
                    ? $item->toArray(
115
                        $nestedFields,
116
                        $nestedExpand
117
                    )
118 2
                    : $item,
119
                $attribute
120
            );
121
        }
122
123
        return $attribute;
124
    }
125
}
126