Skip to content

Commit

Permalink
has castables
Browse files Browse the repository at this point in the history
  • Loading branch information
halaei committed Nov 16, 2018
1 parent 1d09d16 commit 29de3e9
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 79 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ php:
- 7.0
- 7.1
- 7.2
- 7.3

services:
- redis-server
Expand Down
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class Order extends DataObject
return [
'items' => [Item::class], // items is a collection of objects of type Item.
'destination' => Location::class, //delivered_to is an object of type Location
'customer_mobile' => [Mobile::class, 'decode'], // customer mobile is an string that can be casted to a Mobile object via 'decode' static function.
'customer_mobile' => [Mobile::class, 'decode'], // customer mobile is a string that can be casted to a Mobile object via 'decode' static function.
];
}
}
Expand Down Expand Up @@ -134,6 +134,22 @@ echo $order->items[0]->quantity;// 5
var_dump($order->toArray()['mobile_number']); // ['code' => '+98', 'number' => '9131231212']
var_dump($order->toRaw()['mobile_number']); // +98-9131231212
```
#### Cast model attributes to data objects and collections
To cast model attributes to objects, use `HasCastables` trait and define the casts via `static $castables` like the way
relations are defined in `DataObject` classes. This trait is designed for document-oriented databases like mongodb -
works great with `jenssegers/laravel-mongodb` package. To work with SQL databases, `$casts` attributes should also be
used to handle json encoding/decoding.

```php
class Order extends DataObject
{
protected static $castables = [
'items' => [Item::class],
'destination' => Location::class,
'customer_mobile' => [Mobile::class, 'decode'],
];
}
```

### Eloquent Cache
The `EloquentCache` class is a key-value repository for your eloquent models with caching features.
Expand Down
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Change Log

#v0.4.6
- New feature: HasCastables trait.

#v0.4.5

- New feature: Random worker terminator.
Expand Down
5 changes: 5 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,10 @@
"psr-4": {
"Halaei\\Helpers\\": "src/"
}
},
"autoload-dev": {
"files": [
"tests/TestAssets.php"
]
}
}
84 changes: 84 additions & 0 deletions src/Eloquent/HasCastables.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace Halaei\Helpers\Eloquent;

use Halaei\Helpers\Objects\Casting;
use Halaei\Helpers\Objects\DataCollection;
use Halaei\Helpers\Objects\DataObject;
use Halaei\Helpers\Objects\Rawable;

trait HasCastables
{
/**
* @var DataCollection[]|DataObject[]
*/
protected $castedAttributes = [];

/**
* Boots HasCustomAttributes Trait. By addi
*/
public static function bootHasCastables()
{
static::saving(function ($model) {
$model->prepareSaving();
});
}

protected function getCastedAttribute($key, $value, $cast)
{
if (! array_key_exists($key, $this->castedAttributes)) {
$this->castedAttributes[$key] = is_null($value) ? null : Casting::cast($value, $cast, $key);
}
return $this->castedAttributes[$key];
}

/*
* Overrides
*/

public function attributesToArray()
{
$attributes = parent::attributesToArray();

foreach ($this->castedAttributes as $key => $value) {
if ($value instanceof Rawable) {
$attributes[$key] = $value->toArray();
}
}

return $attributes;
}

public function getAttribute($key)
{
if (array_key_exists($key, static::$castables)) {
return $this->getCastedAttribute($key, parent::getAttribute($key), static::$castables[$key]);
}

return parent::getAttribute($key);
}

public function setAttribute($key, $value)
{
if ($value instanceof Rawable) {
$this->castedAttributes[$key] = $value;
return $this;
}
unset($this->castedAttributes[$key]);
return parent::setAttribute($key, $value);
}

public function prepareSaving()
{
foreach ($this->castedAttributes as $key => $value) {
$this->attributes[$key] = $value instanceof Rawable ? $value->toRaw() : $value;
}
}

public function offsetUnset($offset)
{
unset($this->castedAttributes[$offset]);

parent::offsetUnset($offset);
}
}
78 changes: 0 additions & 78 deletions tests/DataObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace HalaeiTests;

use Halaei\Helpers\Objects\DataCollection;
use Halaei\Helpers\Objects\DataObject;

class DataObjectTest extends \PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -186,80 +185,3 @@ public function test_union_by()

}
}

/**
* @property int $id
* @property string $name
* @property Mobile $mobile
* @property Order[] $orders
* @property
*/
class User extends DataObject
{
public static function relations()
{
return [
'mobile' => [Mobile::class, 'decode'],
'orders' => [Order::class],
];
}
}

/**
* @property string $code
* @property string $number
*/
class Mobile extends DataObject
{
public static function decode($str)
{
if (preg_match('/^\+(\d+)-(\d+)$/', $str, $parts)) {
return new self(['code' => $parts[1], 'number' => $parts[2]]);
}
}

public function toRaw()
{
return '+'.$this->code.'-'.$this->number;
}
}

/**
* @property string $id
* @property Item[] $items
*/
class Order extends DataObject
{
public static function relations()
{
return [
'items' => [Item::class],
];
}
}

/**
* @property string $code
* @property int $quantity
*/
class Item extends DataObject
{
}

/**
* @property Cell[][] $cells
*/
class Matrix extends DataObject
{
public static function relations()
{
return ['cells' => [[Cell::class]]];
}
}

/**
* @property $v
*/
class Cell extends DataObject
{
}
58 changes: 58 additions & 0 deletions tests/HasCastablesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace HalaeiTests;

use Halaei\Helpers\Objects\DataCollection;

class HasCastablesTest extends \PHPUnit_Framework_TestCase
{
public function test_user_model()
{
// assign raw value
$user = new UserModel();
$this->assertNull($user->mobile);
$user->mobile = '+98-9121231212';
$this->assertInstanceOf(Mobile::class, $user->mobile);
$this->assertEquals('98', $user->mobile->code);
$this->assertEquals('9121231212', $user->mobile->number);
$this->assertEquals(['code' => '98', 'number' => '9121231212'], $user->toArray()['mobile']);

// assign data object
$user = new UserModel();
$user->mobile = new Mobile([
'code' => '98',
'number' => '9121231212',
]);
$this->assertInstanceOf(Mobile::class, $user->mobile);
$this->assertEquals('98', $user->mobile->code);
$this->assertEquals('9121231212', $user->mobile->number);

// assign in constructor
$user = new UserModel([
'mobile' => '+98-9121231212',
]);
$this->assertInstanceOf(Mobile::class, $user->mobile);
$this->assertEquals('98', $user->mobile->code);
$this->assertEquals('9121231212', $user->mobile->number);

}

public function test_order()
{
$order = new OrderModel([
'items' => [
[
'code' => '#123',
'quantity' => 10,
],
[
'code' => '#124',
'quantity' => 1,
],
]
]);
$this->assertInstanceOf(DataCollection::class, $order->items);
$this->assertInstanceOf(Item::class, $order->items[0]);
$this->assertEquals('#124', $order->items[1]->code);
}
}
106 changes: 106 additions & 0 deletions tests/TestAssets.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

namespace HalaeiTests;

use Halaei\Helpers\Eloquent\HasCastables;
use Halaei\Helpers\Objects\DataObject;
use Illuminate\Database\Eloquent\Model;

/**
* @property int $id
* @property string $name
* @property Mobile $mobile
* @property Order[] $orders
* @property
*/
class User extends DataObject
{
public static function relations()
{
return [
'mobile' => [Mobile::class, 'decode'],
'orders' => [Order::class],
];
}
}

/**
* @property string $code
* @property string $number
*/
class Mobile extends DataObject
{
public static function decode($str)
{
if (preg_match('/^\+(\d+)-(\d+)$/', $str, $parts)) {
return new self(['code' => $parts[1], 'number' => $parts[2]]);
}
}

public function toRaw()
{
return '+'.$this->code.'-'.$this->number;
}
}

/**
* @property string $id
* @property Item[] $items
*/
class Order extends DataObject
{
public static function relations()
{
return [
'items' => [Item::class],
];
}
}

/**
* @property string $code
* @property int $quantity
*/
class Item extends DataObject
{
}

/**
* @property Cell[][] $cells
*/
class Matrix extends DataObject
{
public static function relations()
{
return ['cells' => [[Cell::class]]];
}
}

/**
* @property $v
*/
class Cell extends DataObject
{
}

class UserModel extends Model
{
use HasCastables;

protected $fillable = ['mobile'];

protected static $castables = [
'mobile' => [Mobile::class, 'decode'],
];
}

class OrderModel extends Model
{
use HasCastables;

protected $fillable = ['items'];

protected static $castables = [
'items' => [Item::class],
];
}

0 comments on commit 29de3e9

Please sign in to comment.