bristol-su /
control
| 1 | <?php |
||||||
| 2 | |||||||
|
0 ignored issues
–
show
Coding Style
introduced
by
Loading history...
|
|||||||
| 3 | namespace BristolSU\ControlDB\AdditionalProperties; |
||||||
| 4 | |||||||
| 5 | use Exception; |
||||||
| 6 | use Illuminate\Database\Eloquent\Model; |
||||||
| 7 | use Illuminate\Support\Str; |
||||||
| 8 | |||||||
| 9 | /** |
||||||
| 10 | * Allow a model to have any arbitrary properties, set at runtime |
||||||
| 11 | */ |
||||||
|
0 ignored issues
–
show
|
|||||||
| 12 | trait HasAdditionalProperties |
||||||
| 13 | { |
||||||
| 14 | |||||||
| 15 | /** |
||||||
| 16 | * Initialise the trait |
||||||
| 17 | * |
||||||
| 18 | * - Add all additional properties to the appends array |
||||||
| 19 | * - Add additional_properties column to hidden |
||||||
| 20 | * - Cast the additional_properties column to an array |
||||||
| 21 | */ |
||||||
|
0 ignored issues
–
show
|
|||||||
| 22 | 442 | public function initializeHasAdditionalProperties() |
|||||
| 23 | { |
||||||
| 24 | 442 | if (is_subclass_of($this, Model::class)) { |
|||||
| 25 | 441 | $this->append(static::getAdditionalAttributes()); |
|||||
|
0 ignored issues
–
show
The method
append() does not exist on BristolSU\ControlDB\Addi...HasAdditionalProperties. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 26 | 441 | $this->addHidden($this->getColumnName()); |
|||||
|
0 ignored issues
–
show
The method
addHidden() does not exist on BristolSU\ControlDB\Addi...HasAdditionalProperties. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 27 | 441 | $this->casts[] = $this->getColumnName(); |
|||||
|
0 ignored issues
–
show
|
|||||||
| 28 | } else { |
||||||
| 29 | 1 | throw new Exception('The HasAdditionalProperties trait must only be used in an Eloquent model'); |
|||||
| 30 | } |
||||||
| 31 | 441 | } |
|||||
| 32 | |||||||
| 33 | /** |
||||||
| 34 | * Add an additional property |
||||||
| 35 | * |
||||||
| 36 | * @param $key |
||||||
|
0 ignored issues
–
show
|
|||||||
| 37 | */ |
||||||
|
0 ignored issues
–
show
|
|||||||
| 38 | 44 | public static function addProperty(string $key): void |
|||||
| 39 | { |
||||||
| 40 | 44 | app(AdditionalPropertyStore::class)->addProperty(static::class, $key); |
|||||
| 41 | 44 | } |
|||||
| 42 | |||||||
| 43 | /** |
||||||
| 44 | * Get all additional attributes the model is using |
||||||
| 45 | * |
||||||
| 46 | * @return array |
||||||
| 47 | */ |
||||||
| 48 | 442 | public static function getAdditionalAttributes(): array |
|||||
| 49 | { |
||||||
| 50 | 442 | return (app(AdditionalPropertyStore::class)->getProperties(static::class) ?? []); |
|||||
| 51 | } |
||||||
| 52 | |||||||
| 53 | /** |
||||||
| 54 | * Retrieve an additional attribute value |
||||||
| 55 | * |
||||||
| 56 | * @param string $key Key of the attribute |
||||||
| 57 | * @return mixed Value of the attribute |
||||||
|
0 ignored issues
–
show
|
|||||||
| 58 | */ |
||||||
| 59 | 29 | public function getAdditionalAttribute(string $key) |
|||||
| 60 | { |
||||||
| 61 | 29 | return (array_key_exists($key, ($this->{$this->getColumnName()}??[])) |
|||||
| 62 | 29 | ? $this->{$this->getColumnName()}[$key] : null); |
|||||
| 63 | } |
||||||
| 64 | |||||||
| 65 | /** |
||||||
| 66 | * Set an additional attribute value |
||||||
| 67 | * |
||||||
| 68 | * @param string $key Key of the attribute |
||||||
|
0 ignored issues
–
show
|
|||||||
| 69 | * @param mixed $value Value of the attribute |
||||||
|
0 ignored issues
–
show
|
|||||||
| 70 | */ |
||||||
|
0 ignored issues
–
show
|
|||||||
| 71 | 31 | public function setAdditionalAttribute(string $key, $value) |
|||||
| 72 | { |
||||||
| 73 | 31 | $this->attributes[$this->getColumnName()] = array_merge(($this->{$this->getColumnName()}??[]), [$key => $value]); |
|||||
|
0 ignored issues
–
show
|
|||||||
| 74 | 31 | } |
|||||
| 75 | |||||||
| 76 | /** |
||||||
| 77 | * Save an additional attribute value |
||||||
| 78 | * |
||||||
| 79 | * @param string $key Key of the attribute |
||||||
|
0 ignored issues
–
show
|
|||||||
| 80 | * @param mixed $value Value of the attribute |
||||||
|
0 ignored issues
–
show
|
|||||||
| 81 | */ |
||||||
|
0 ignored issues
–
show
|
|||||||
| 82 | 13 | public function saveAdditionalAttribute(string $key, $value) |
|||||
| 83 | { |
||||||
| 84 | 13 | $this->setAdditionalAttribute($key, $value); |
|||||
| 85 | 13 | $this->save(); |
|||||
|
0 ignored issues
–
show
The method
save() does not exist on BristolSU\ControlDB\Addi...HasAdditionalProperties. Since you implemented __call, consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 86 | 13 | } |
|||||
| 87 | |||||||
| 88 | /** |
||||||
| 89 | * Override the default getAttribute function |
||||||
| 90 | * |
||||||
| 91 | * Any time an attribute is retrieved, we will check if it's an additional property and return it if so |
||||||
| 92 | * |
||||||
| 93 | * @param string $key Key of the property to retrieve |
||||||
| 94 | * @return mixed Value of the property |
||||||
|
0 ignored issues
–
show
|
|||||||
| 95 | */ |
||||||
| 96 | 412 | public function getAttribute($key) |
|||||
| 97 | { |
||||||
| 98 | 412 | if (in_array($key, static::getAdditionalAttributes())) { |
|||||
| 99 | 5 | return $this->getAdditionalAttribute($key); |
|||||
| 100 | } |
||||||
| 101 | 412 | return parent::getAttribute($key); |
|||||
| 102 | } |
||||||
| 103 | |||||||
| 104 | /** |
||||||
| 105 | * Override the default getAttribute function |
||||||
| 106 | * |
||||||
| 107 | * Any time an attribute is set, we will check if it's an additional property and set it correspondingly if so |
||||||
| 108 | * |
||||||
| 109 | * @param string $key Key of the property to retrieve |
||||||
|
0 ignored issues
–
show
|
|||||||
| 110 | * @param mixed $value Value of the attribute |
||||||
|
0 ignored issues
–
show
|
|||||||
| 111 | * @return mixed Value of the property |
||||||
|
0 ignored issues
–
show
|
|||||||
| 112 | */ |
||||||
| 113 | 427 | public function setAttribute($key, $value) |
|||||
| 114 | { |
||||||
| 115 | 427 | if (in_array($key, static::getAdditionalAttributes())) { |
|||||
| 116 | 14 | $this->setAdditionalAttribute($key, $value); |
|||||
| 117 | } else { |
||||||
| 118 | 427 | parent::setAttribute($key, $value); |
|||||
| 119 | } |
||||||
| 120 | 427 | } |
|||||
| 121 | |||||||
| 122 | /** |
||||||
| 123 | * Cast the additional attributes column to an array, or return an empty array by default. |
||||||
| 124 | * |
||||||
| 125 | * @return array|mixed |
||||||
| 126 | */ |
||||||
| 127 | 38 | public function getAdditionalAttributesAttribute() |
|||||
| 128 | { |
||||||
| 129 | 38 | if(!array_key_exists($this->getColumnName(), $this->attributes)) { |
|||||
|
0 ignored issues
–
show
|
|||||||
| 130 | 28 | return []; |
|||||
| 131 | } |
||||||
| 132 | 33 | if(is_string($this->attributes[$this->getColumnName()])) { |
|||||
|
0 ignored issues
–
show
|
|||||||
| 133 | 18 | return (json_decode($this->attributes[$this->getColumnName()], true) ?? []); |
|||||
| 134 | } |
||||||
| 135 | 15 | return $this->attributes[$this->getColumnName()]; |
|||||
| 136 | } |
||||||
| 137 | |||||||
| 138 | /** |
||||||
| 139 | * Get the name of the additional attributes column |
||||||
| 140 | * |
||||||
| 141 | * @return string Name of the additional attributes column |
||||||
| 142 | */ |
||||||
| 143 | 441 | private function getColumnName() |
|||||
|
0 ignored issues
–
show
|
|||||||
| 144 | { |
||||||
| 145 | 441 | return 'additional_attributes'; |
|||||
| 146 | } |
||||||
| 147 | |||||||
| 148 | /** |
||||||
| 149 | * Dynamically define accessors for the appended properties. |
||||||
| 150 | * |
||||||
| 151 | * By catching all method calls, we can check if they are calls for an accessor or mutator to an attribute and |
||||||
| 152 | * carry out the corresponding action. |
||||||
| 153 | * |
||||||
| 154 | * @param string $method Method of the call |
||||||
| 155 | * @param array $args Arguments for the call |
||||||
|
0 ignored issues
–
show
|
|||||||
| 156 | * @return mixed |
||||||
|
0 ignored issues
–
show
|
|||||||
| 157 | */ |
||||||
| 158 | 134 | public function __call($method, $args) |
|||||
| 159 | { |
||||||
| 160 | // Check if the call was an accessor |
||||||
| 161 | $additionalAccessors = array_map(function($propertyKey) { |
||||||
|
0 ignored issues
–
show
|
|||||||
| 162 | 22 | return 'get'.Str::studly($propertyKey).'Attribute'; |
|||||
| 163 | 134 | }, static::getAdditionalAttributes()); |
|||||
|
0 ignored issues
–
show
For multi-line function calls, the closing parenthesis should be on a new line.
If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line: someFunctionCall(
$firstArgument,
$secondArgument,
$thirdArgument
); // Closing parenthesis on a new line.
Loading history...
|
|||||||
| 164 | 134 | if(in_array($method, $additionalAccessors)) { |
|||||
|
0 ignored issues
–
show
|
|||||||
| 165 | 14 | return $this->getAdditionalAttribute( |
|||||
| 166 | 14 | Str::snake(Str::substr(Str::substr($method, 3), 0, -9)) |
|||||
| 167 | ); |
||||||
| 168 | } |
||||||
| 169 | |||||||
| 170 | // Check if the call was a mutator |
||||||
| 171 | $additionalAccessors = array_map(function($propertyKey) { |
||||||
|
0 ignored issues
–
show
|
|||||||
| 172 | 18 | return 'set'.Str::studly($propertyKey).'Attribute'; |
|||||
| 173 | 130 | }, static::getAdditionalAttributes()); |
|||||
|
0 ignored issues
–
show
For multi-line function calls, the closing parenthesis should be on a new line.
If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line: someFunctionCall(
$firstArgument,
$secondArgument,
$thirdArgument
); // Closing parenthesis on a new line.
Loading history...
|
|||||||
| 174 | 130 | if(in_array($method, $additionalAccessors)) { |
|||||
|
0 ignored issues
–
show
|
|||||||
| 175 | 1 | $this->setAdditionalAttribute( |
|||||
| 176 | 1 | Str::snake(Str::substr(Str::substr($method, 3), 0, -9)), $args[0] |
|||||
| 177 | ); |
||||||
| 178 | } else { |
||||||
| 179 | 129 | return parent::__call($method, |
|||||
|
0 ignored issues
–
show
|
|||||||
| 180 | $args); |
||||||
|
0 ignored issues
–
show
For multi-line function calls, the closing parenthesis should be on a new line.
If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line: someFunctionCall(
$firstArgument,
$secondArgument,
$thirdArgument
); // Closing parenthesis on a new line.
Loading history...
|
|||||||
| 181 | } |
||||||
| 182 | |||||||
| 183 | |||||||
| 184 | 1 | } |
|||||
| 185 | } |
||||||
| 186 |