Passed
Push — main ( 3cafac...84621c )
by Gabriel
01:57
created

AccessorsTrait   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 178
Duplicated Lines 0 %

Test Coverage

Coverage 61.82%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 61
dl 0
loc 178
rs 10
c 1
b 0
f 0
ccs 34
cts 55
cp 0.6182
wmc 26

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getMutated() 0 4 1
A setMutated() 0 4 1
B callAccessors() 0 36 9
A hasSetMutator() 0 3 1
A getMutator() 0 21 5
A hasMutator() 0 3 1
A hasGetMutator() 0 3 1
A compileAccessorsMethod() 0 11 1
A compileMutators() 0 19 6
1
<?php
2
3
namespace ByTIC\DataObjects\Behaviors\Accessors;
4
5
use ByTIC\DataObjects\Utility\Constants;
6
use Exception;
7
use Nip\Inflector\Inflector;
8
use Nip\Utility\Str;
9
10
/**
11
 * Trait AccessorsTrait
12
 * @package ByTIC\DataObjects\Behaviors\Accessors
13
 */
14
trait AccessorsTrait
15
{
16
    /**
17
     * The attributes that should use mutators.
18
     *
19
     * @var array
20
     */
21
    protected static $accessors = [
22
        'get' => [],
23
        'set' => [],
24
    ];
25
26
    /**
27
     * @param $key
28
     * @return mixed
29
     * @noinspection PhpDocMissingThrowsInspection
30
     */
31
    public function getMutated($key)
32
    {
33
        /** @noinspection PhpUnhandledExceptionInspection */
34
        return $this->callAccessors('get', $key);
35
    }
36
37
    /**
38
     * @param $key
39
     * @param $value
40
     * @return mixed
41
     * @noinspection PhpDocMissingThrowsInspection
42
     */
43
    public function setMutated($key, $value)
44
    {
45
        /** @noinspection PhpUnhandledExceptionInspection */
46
        return $this->callAccessors('set', $key, [$value]);
47
    }
48
49 13
    /**
50
     * @param string $type
51 13
     * @param string $key
52 13
     * @param array $params
53 7
     * @return mixed
54
     * @throws Exception
55
     */
56 7
    protected function callAccessors(string $type, string $key, $params = [])
57
    {
58
        $method = static::getMutator($type, $key);
59
        if (!$method) {
60
            return Constants::NO_ACCESSORS_FOUND;
61
        }
62
        if ($type !== 'get') {
63
            return $this->{$method}(...$params);
64
        }
65
66
        static $inAccess = [];
67
        if (isset($inAccess[$type])) {
68
            return $this->getPropertyRaw($key);
0 ignored issues
show
Bug introduced by
It seems like getPropertyRaw() 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

68
            return $this->/** @scrutinizer ignore-call */ getPropertyRaw($key);
Loading history...
69
        }
70
71
        try {
72
            set_error_handler(
73
                function ($errno, $errstr, $errfile, $errline) use ($type, $key) {
0 ignored issues
show
Unused Code introduced by
The import $type is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
74
                    if (Str::startsWith($errstr, 'Undefined property:')
75
                        && Str::endsWith($errstr, '::$' . $key)) {
76
                        return $this->getPropertyRaw($key);
77
                    }
78
                    return;
79
                },
80
                E_NOTICE
81
            );
82
            $return = $this->{$method}(...$params);
83
            restore_error_handler();
84
            return $return;
85
        } catch (Exception $exception) {
86
            $message = $exception->getMessage();
87
            if (Str::startsWith($message, 'Undefined property:')
88
                && Str::endsWith($message, '::$' . $key)) {
89
                return $this->getPropertyRaw($key);
90
            }
91
            throw $exception;
92
        }
93
    }
94
95
    /**
96
     * Determine if a set mutator exists for an attribute.
97
     *
98
     * @param string $key
99
     * @return bool
100
     */
101
    protected function hasSetMutator(string $key): bool
102
    {
103
        return static::hasMutator('set', $key);
104
    }
105 13
106
107 13
    /**
108
     * Determine if a get mutator exists for an attribute.
109 13
     *
110 3
     * @param string $key
111
     * @return bool
112
     */
113 13
    protected function hasGetMutator(string $key): bool
114 12
    {
115
        return static::hasMutator('get', $key);
116
    }
117 4
118 4
    /**
119
     * Determine if a set mutator exists for an attribute.
120
     *
121
     * @param string $type
122
     * @param string $key
123
     * @return bool
124
     */
125
    protected static function hasMutator(string $type, string $key): bool
126
    {
127
        return !empty(static::getMutator($type, $key));
128 3
    }
129
130 3
    protected static function getMutator(string $type, string $key): string
131
    {
132 3
        $class = static::class;
133 3
134 3
        if (empty(static::$accessors[$class])) {
135
            static::compileMutators();
136 3
        }
137 3
138 3
        if (isset(static::$accessors[$class][$type][$key])) {
139
            return static::$accessors[$class][$type][$key];
140
        }
141 3
142 3
        if (!empty(static::$accessors[$class])) {
143 3
            return static::$accessors[$class][$type][$key] = '';
144
        }
145
146 3
        if (!isset(static::$accessors[$class][$type][$key])) {
147
            static::$accessors[$class][$type][$key] = '';
148 3
        }
149
150
        return static::$accessors[$class][$type][$key];
151
    }
152
153
    protected static function compileMutators()
154
    {
155
        $class = static::class;
156 3
157
        foreach (get_class_methods($class) as $method) {
158 3
            if (in_array($method, ['get','set'])) {
159 3
                continue;
160
            }
161
            $prefix = substr($method, 0, 3);
162 3
            if ($prefix !== 'get' && $prefix !== 'set') {
163 3
                continue;
164
            }
165 3
166 3
            $field = substr($method, 3);
167 3
            if (Str::endsWith($field, 'Attribute')) {
168
                $field = substr($field, 0, -9);
169
            }
170
171
            static::compileAccessorsMethod($class, $prefix, $method, $field);
172
        }
173
    }
174
175
    /**
176
     * @param $class
177
     * @param $prefix
178
     * @param $method
179
     * @param $field
180
     */
181
    protected static function compileAccessorsMethod($class, $prefix, $method, $field)
182
    {
183
        $field = lcfirst($field);
184
        static::$accessors[$class][$prefix][$field] = $method;
185
186
        /** @noinspection PhpDynamicAsStaticMethodCallInspection */
187
        $snakeField = Inflector::underscore($field);
0 ignored issues
show
Bug Best Practice introduced by
The method Nip\Inflector\Inflector::underscore() is not static, but was called statically. ( Ignorable by Annotation )

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

187
        /** @scrutinizer ignore-call */ 
188
        $snakeField = Inflector::underscore($field);
Loading history...
188
        static::$accessors[$class][$prefix][$snakeField] = $method;
189
190
        $titleField = ucfirst($field);
191
        static::$accessors[$class][$prefix][$titleField] = $method;
192
    }
193
}
194