1: <?php
2:
3: namespace Chromabits\Nucleus\Foundation;
4:
5: use Chromabits\Nucleus\Data\ArrayList;
6: use Chromabits\Nucleus\Data\ArrayMap;
7: use Chromabits\Nucleus\Exceptions\LackOfCoffeeException;
8: use Chromabits\Nucleus\Foundation\Interfaces\ArrayableInterface;
9: use Chromabits\Nucleus\Foundation\Interfaces\FillableInterface;
10: use Chromabits\Nucleus\Support\Str;
11:
12: /**
13: * Class Entity
14: *
15: * @author Eduardo Trujillo <ed@chromabits.com>
16: * @package Chromabits\Nucleus\Foundation
17: */
18: abstract class Entity extends BaseObject implements
19: ArrayableInterface,
20: FillableInterface
21: {
22: /**
23: * Define which properties can be "filled" using an input array.
24: *
25: * When set to `null`, the entity is considered to not declare any fillable
26: * fields, which will cause an exception to be thrown if a fill operation
27: * is attempted on the entity.
28: *
29: * To declare that there are no fields that can be filled, use an empty
30: * array ([]).
31: *
32: * @var null|string[]
33: */
34: protected $fillable = null;
35:
36: /**
37: * Get which fields should be hidden from serialization, such as toArray().
38: *
39: * @var array
40: */
41: protected $hidden = [];
42:
43: /**
44: * Get which fields should be included in serialization.
45: *
46: * @var array
47: */
48: protected $visible = [];
49:
50: /**
51: * Fill properties in this object using an input array.
52: *
53: * - Only fields that are mentioned in the fillable array can be set.
54: * - Other keys will just be ignored completely.
55: * - If a setter is present, it will be automatically called.
56: *
57: * @param array $input
58: *
59: * @return $this
60: * @throws LackOfCoffeeException
61: */
62: public function fill(array $input)
63: {
64: $this->assertIsFillable();
65:
66: ArrayMap::of($input)
67: ->only($this->getFillable())
68: ->each(function ($value, $key) {
69: $setter = vsprintf('set%s', [Str::studly($key)]);
70:
71: if (method_exists($this, $setter)) {
72: $this->$setter($value);
73:
74: return;
75: }
76:
77: $camel = Str::camel($key);
78: $this->$camel = $value;
79: });
80:
81: return $this;
82: }
83:
84: /**
85: * Assert that this entity can be filled.
86: *
87: * @throws LackOfCoffeeException
88: */
89: protected function assertIsFillable()
90: {
91: if ($this->getFillable() === null) {
92: throw new LackOfCoffeeException(
93: 'Unable to fill an entity that has not declared which'
94: . ' properties are fillable.'
95: );
96: }
97: }
98:
99: /**
100: * Get which fields should be allowed to be filled.
101: *
102: * @return null|string[]
103: */
104: public function getFillable()
105: {
106: return $this->fillable;
107: }
108:
109: /**
110: * Get which fields should be included in serialization.
111: *
112: * @return array
113: */
114: public function getVisible()
115: {
116: return $this->visible;
117: }
118:
119: /**
120: * Get an array representation of this entity.
121: *
122: * @return array
123: */
124: public function toArray()
125: {
126: $result = [];
127:
128: ArrayList::of($this->getFillable())
129: ->append(ArrayList::of($this->getVisible()))
130: ->unique(SORT_STRING)
131: ->exceptValues($this->getHidden())
132: ->each(function ($key) use (&$result) {
133: $getter = vsprintf('get%s', [Str::studly($key)]);
134:
135: if (method_exists($this, $getter)) {
136: $result[$key] = $this->$getter();
137:
138: return;
139: }
140:
141: $camel = Str::camel($key);
142: $result[$key] = $this->$camel;
143: });
144:
145: return $result;
146: }
147:
148: /**
149: * Get which fields should not be included during serialization.
150: *
151: * @return array
152: */
153: public function getHidden()
154: {
155: return $this->hidden;
156: }
157: }
158: