Skip to content

Commit d7234c3

Browse files
add BaseModelFrozenAttributes (#8)
* add BaseModelFrozenAttributes * add BaseModelFrozenAttributes * add BaseModelFrozenAttributes * add BaseModelFrozenAttributes replace toArray with __toString and return json to ease the @mixin usage * add BaseModelFrozenAttributes replace toArray with __toString and return json to ease the @mixin usage * add BaseModelFrozenAttributes add getFrozen to BaseModel * add BaseModelFrozenAttributes update README.md * add BaseModelFrozenAttributes update README.md * add BaseModelFrozenAttributes handle return type for json_decode * Make the stdClass read only also for its content and update README.md * README.md mention that Model is retrievable form db for frozen attributes ---------
1 parent 64c1dd1 commit d7234c3

File tree

3 files changed

+120
-0
lines changed

3 files changed

+120
-0
lines changed

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,55 @@ For model properties autocomplete:
7575
- add in its class dock block using **@property** all the models properties/attributes/columns
7676
- add in the model's class dock block **@property ChildBaseModelAttributes $a** and **@mixin ChildBaseModelAttributes**
7777
- use **$model->a->** instead of **$model->**
78+
- BaseModelFrozenAttributes can be also extended on the same logic and used for model read only situations - DTO without setters (Reflection or Closure binding usage will retrieve/set private stdClass not Model - but the model can be retrieved from DB by its primary key that is readable in this frozen model):
79+
```php
80+
#OperationModel example for BaseModelFrozenAttributes
81+
public function getFrozen(): OperationFrozenAttributes
82+
{
83+
return parent::getFrozen(); // this is needed for autocompletion and will include also the loaded relations
84+
// or
85+
return new OperationFrozenAttributes((clone $this)->forceFill($this->toArray()));
86+
// or just attributes without loaded relations
87+
return new OperationFrozenAttributes((clone $this)->forceFill($this->attributesToArray()));
88+
}
89+
```
90+
91+
```php
92+
#OperationService example for BaseModelAttributes and BaseModelFrozenAttributes
93+
public function someFunction(): void
94+
{
95+
// BaseModelAttributes
96+
echo $this->model-a->value; // has autocomplete - will print for example 1
97+
echo $this->model-a->value = 10; // has autocomplete - will print 10
98+
echo $this->model->value; // has autocomplete - will print 10
99+
100+
// BaseModelFrozenAttributes
101+
$dto = $this->model->getFrozen();
102+
echo $dto->client_id; // has autocomplete - will print for example 1
103+
$dto->client_id = 4; // Exception: Dynamic properties are forbidden.
104+
105+
if (isset($dto->client)) {
106+
/** @var ClientFrozenAttributes $client */
107+
// $client will be an stdClass that has autocomplete like a ClientFrozenAttributes
108+
$client = $dto->client;
109+
echo $client->name; // has autocomplete - will print for example 'name'
110+
$client->name = 'text'; // NO Exception
111+
echo $client->name; // will print 'text'
112+
// $client changes can happen, but they will not be persisted in the $dto ($client is a stdClass clone)
113+
echo $dto->client->name; // will print 'name'
114+
}
115+
116+
foreach (($dto->products ?? []) as $k => $product) {
117+
/** @var ProductFrozenAttributes $product */
118+
// $product will be an stdClass that has autocompletes like a ProductFrozenAttributes
119+
echo $product->value; // has autocomplete - will print for example 1
120+
$product->value = 2; // NO Exception
121+
echo $product->value; // will print 2
122+
// $product changes can happen, but they will not be persisted in the $dto ($product is a stdClass clone)
123+
echo $dto->products[$k]->name; // will print 1
124+
}
125+
}
126+
```
78127

79128
Add this new resource to the above map.
80129

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace MacropaySolutions\LaravelCrudWizard\Models\Attributes;
4+
5+
use MacropaySolutions\LaravelCrudWizard\Models\BaseModel;
6+
7+
/**
8+
* For properties autocompletion declare in the children classes (with @ property) all the model's parameters (columns)
9+
*
10+
* To avoid declaring them twice, put @ mixin ChildBaseModelFrozenAttributes in ChildBaseModelAttributes
11+
*/
12+
class BaseModelFrozenAttributes implements \Stringable
13+
{
14+
private \stdClass $mirror;
15+
16+
public function __construct(BaseModel $ownerBaseModel) {
17+
$this->mirror = (object)\json_decode(\json_encode($ownerBaseModel->attributesToArray()));
18+
}
19+
20+
public function __get(string $key): mixed
21+
{
22+
if (!$this->__isset($key)) {
23+
return null;
24+
}
25+
26+
if ($this->mirror->{$key} instanceof \stdClass) {
27+
return (object)\json_decode(\json_encode($this->mirror->{$key}));
28+
}
29+
30+
if (\is_array($this->mirror->{$key})) {
31+
return (array)\json_decode(\json_encode($this->mirror->{$key}));
32+
}
33+
34+
return $this->mirror->{$key};
35+
}
36+
37+
/**
38+
* @throws \Exception
39+
*/
40+
public function __set(string $key, mixed $value): void
41+
{
42+
throw new \Exception('Dynamic properties are forbidden.');
43+
}
44+
45+
public function __isset(string $key): bool
46+
{
47+
return isset($this->mirror->{$key});
48+
}
49+
50+
public function __toString(): string
51+
{
52+
return (string)\json_encode($this->mirror);
53+
}
54+
}

src/Models/BaseModel.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use MacropaySolutions\LaravelCrudWizard\Eloquent\CustomRelations\HasCleverRelationships;
1313
use MacropaySolutions\LaravelCrudWizard\Helpers\GeneralHelper;
1414
use MacropaySolutions\LaravelCrudWizard\Models\Attributes\BaseModelAttributes;
15+
use MacropaySolutions\LaravelCrudWizard\Models\Attributes\BaseModelFrozenAttributes;
1516

1617
/**
1718
* For properties autocompletion declare in the children classes (with @ property) ChildBaseModelAttributes $a
@@ -318,6 +319,22 @@ public function getAttribute($key)
318319
return parent::getAttribute($key);
319320
}
320321

322+
/**
323+
* @throws \Exception
324+
*/
325+
public function getFrozen(): BaseModelFrozenAttributes
326+
{
327+
$frozenAttributes =
328+
\substr($class = static::class, 0, $l = (-1 * (\strlen($class) - \strrpos($class, '\\') - 1))) .
329+
'Attributes\\' . \substr($class, $l) . 'FrozenAttributes';
330+
331+
if (\class_exists($frozenAttributes)) {
332+
return new $frozenAttributes((clone $this)->forceFill($this->toArray()));
333+
}
334+
335+
throw new \Exception('Class not found: ' . $frozenAttributes);
336+
}
337+
321338
/**
322339
* This will mass update the whole table if the model does not exist!
323340
* @inheritDoc

0 commit comments

Comments
 (0)