Overview

Namespaces

  • Charcoal
    • Loader
    • Model
      • Service
      • ServiceProvider
    • Source
      • Database
    • Validator

Classes

  • Charcoal\Loader\CollectionLoader
  • Charcoal\Loader\FileLoader
  • Charcoal\Model\AbstractMetadata
  • Charcoal\Model\AbstractModel
  • Charcoal\Model\Collection
  • Charcoal\Model\Model
  • Charcoal\Model\ModelMetadata
  • Charcoal\Model\ModelValidator
  • Charcoal\Model\Service\MetadataLoader
  • Charcoal\Model\Service\ModelBuilder
  • Charcoal\Model\Service\ModelLoader
  • Charcoal\Model\Service\ModelLoaderBuilder
  • Charcoal\Model\ServiceProvider\ModelServiceProvider
  • Charcoal\Source\AbstractSource
  • Charcoal\Source\Database\DatabaseFilter
  • Charcoal\Source\Database\DatabaseOrder
  • Charcoal\Source\Database\DatabasePagination
  • Charcoal\Source\DatabaseSource
  • Charcoal\Source\DatabaseSourceConfig
  • Charcoal\Source\Filter
  • Charcoal\Source\Order
  • Charcoal\Source\Pagination
  • Charcoal\Source\SourceConfig
  • Charcoal\Validator\AbstractValidator
  • Charcoal\Validator\ValidatorResult

Interfaces

  • Charcoal\Model\CollectionInterface
  • Charcoal\Model\DescribableInterface
  • Charcoal\Model\MetadataInterface
  • Charcoal\Model\ModelInterface
  • Charcoal\Source\DatabaseSourceInterface
  • Charcoal\Source\FilterInterface
  • Charcoal\Source\OrderInterface
  • Charcoal\Source\PaginationInterface
  • Charcoal\Source\SourceInterface
  • Charcoal\Source\StorableInterface
  • Charcoal\Validator\ValidatableInterface
  • Charcoal\Validator\ValidatorInterface

Traits

  • Charcoal\Model\DescribableTrait
  • Charcoal\Source\StorableTrait
  • Charcoal\Validator\ValidatableTrait
  • Overview
  • Namespace
  • Class
  1: <?php
  2: 
  3: namespace Charcoal\Source;
  4: 
  5: use \Exception;
  6: use \InvalidArgumentException;
  7: 
  8: // Module `charcoal-factory` dependencies
  9: use \Charcoal\Factory\FactoryInterface;
 10: 
 11: // Local namespace dependencies
 12: use \Charcoal\Source\SourceInterface;
 13: 
 14: /**
 15: * Full implementation, as trait, of the StorableInterface
 16: */
 17: trait StorableTrait
 18: {
 19:     /**
 20:      * @var mixed $id The object (unique) identifier
 21:      */
 22:     protected $id;
 23: 
 24:     /**
 25:      * @var string $key The object key
 26:      */
 27:     protected $key = 'id';
 28: 
 29:     /**
 30:      * @var FactoryInterface $sourceFactory
 31:      */
 32:     protected $sourceFactory;
 33: 
 34:     /**
 35:      * @var SourceInterface $source
 36:      */
 37:     private $source;
 38: 
 39:     /**
 40:      * Set the object's ID. The actual property set depends on `key()`
 41:      *
 42:      * @param mixed $id The object id (identifier / primary key value).
 43:      * @throws InvalidArgumentException If the argument is not scalar.
 44:      * @return StorableInterface Chainable
 45:      */
 46:     public function setId($id)
 47:     {
 48:         if (!is_scalar($id)) {
 49:             throw new InvalidArgumentException(
 50:                 sprintf(
 51:                     'ID for "%s" must be a scalar (integer, float, string, or boolean); received %s',
 52:                     get_class($this),
 53:                     (is_object($id) ? get_class($id) : gettype($id))
 54:                 )
 55:             );
 56:         }
 57: 
 58:         $key = $this->key();
 59:         if ($key == 'id') {
 60:             $this->id = $id;
 61:         } else {
 62:             $this[$key] = $id;
 63:         }
 64: 
 65:         return $this;
 66:     }
 67: 
 68:     /**
 69:      * Get the object's (unique) ID. The actualy property get depends on `key()`
 70:      *
 71:      * @throws Exception If the set key is invalid.
 72:      * @return mixed
 73:      */
 74:     public function id()
 75:     {
 76:         $key = $this->key();
 77:         if ($key == 'id') {
 78:             return $this->id;
 79:         } else {
 80:             return $this[$key];
 81:         }
 82:     }
 83: 
 84:     /**
 85:      * Set the key property.
 86:      *
 87:      * @param string $key The object key, or identifier "name".
 88:      * @throws InvalidArgumentException If the argument is not scalar.
 89:      * @return StorableInterface Chainable
 90:      */
 91:     public function setKey($key)
 92:     {
 93:         if (!is_string($key)) {
 94:             throw new InvalidArgumentException(
 95:                 sprintf(
 96:                     'Key must be a string; received %s',
 97:                     (is_object($key) ? get_class($key) : gettype($key))
 98:                 )
 99:             );
100:         }
101:         // For security reason, only alphanumeric characters (+ underscores) are valid key names.
102:         // Although SQL can support more, there's really no reason to.
103:         if (!preg_match_all('/^[A-Za-z0-9_]+$/', $key)) {
104:             throw new InvalidArgumentException(
105:                 sprintf('Key "%s" is invalid: must be alphanumeric / underscore.', $key)
106:             );
107:         }
108:         $this->key = $key;
109: 
110:         return $this;
111:     }
112: 
113:     /**
114:      * Get the key property.
115:      *
116:      * @return string
117:      */
118:     public function key()
119:     {
120:         return $this->key;
121:     }
122: 
123:     /**
124:      * @param FactoryInterface $factory The source factory, which is useful to create source.
125:      * @return StorableInterface Chainable
126:      */
127:     protected function setSourceFactory(FactoryInterface $factory)
128:     {
129:         $this->sourceFactory = $factory;
130:         return $this;
131:     }
132: 
133:     /**
134:      * @throws Exception If the source factory was not previously set.
135:      * @return FactoryInterface
136:      */
137:     protected function sourceFactory()
138:     {
139:         if (!isset($this->sourceFactory)) {
140:             throw new Exception(
141:                 sprintf('Source factory is not set for "%s"', get_class($this))
142:             );
143:         }
144:         return $this->sourceFactory;
145:     }
146: 
147:     /**
148:      * Set the object's source.
149:      *
150:      * @param SourceInterface $source The storable object's source.
151:      * @return StorableInterface Chainable
152:      * @todo This method needs to go protected.
153:      */
154:     public function setSource(SourceInterface $source)
155:     {
156:         $this->source = $source;
157:         return $this;
158:     }
159: 
160:     /**
161:      * Get the object's source.
162:      *
163:      * @return SourceInterface
164:      */
165:     public function source()
166:     {
167:         if ($this->source === null) {
168:             $this->source = $this->createSource();
169:         }
170:         return $this->source;
171:     }
172: 
173:     /**
174:      * Create the model's source, with the Source Factory.
175:      *
176:      * @return SourceInterface
177:      */
178:     abstract protected function createSource();
179: 
180:     /**
181:      * Load an object from the database from its ID.
182:      *
183:      * @param mixed $id The identifier to load.
184:      * @return StorableInterface Chainable
185:      */
186:     public function load($id = null)
187:     {
188:         if ($id === null) {
189:             $id = $this->id();
190:         }
191:         $this->source()->loadItem($id, $this);
192:         return $this;
193:     }
194: 
195:     /**
196:      * Load an object from the database from its key $key.
197:      *
198:      * @param string $key   Key pointing a column's name.
199:      * @param mixed  $value Value of said column.
200:      * @return StorableInterface Chainable.
201:      */
202:     public function loadFrom($key = null, $value = null)
203:     {
204:         $this->source()->loadItemFromKey($key, $value, $this);
205:         return $this;
206:     }
207: 
208:     /**
209:      * Load an object from the database from a custom SQL query.
210:      *
211:      * @param string $query The SQL query.
212:      * @param array  $binds Optional. The SQL query parameters.
213:      * @return StorableInterface Chainable.
214:      */
215:     public function loadFromQuery($query, array $binds = [])
216:     {
217:         $this->source()->loadItemFromQuery($query, $binds, $this);
218:         return $this;
219:     }
220: 
221:     /**
222:      * Save an object current state to storage
223:      *
224:      * @return boolean
225:      */
226:     public function save()
227:     {
228:         $pre = $this->preSave();
229:         if ($pre === false) {
230:             return false;
231:         }
232:         $ret = $this->source()->saveItem($this);
233:         if ($ret === false) {
234:             return false;
235:         }
236:         $post = $this->postSave();
237:         if ($post === false) {
238:             return false;
239:         }
240:         return true;
241:     }
242: 
243:     /**
244:      * Update the object in storage to the current object state.
245:      *
246:      * @param array $properties If set, only update the properties specified in this array.
247:      * @return boolean
248:      */
249:     public function update(array $properties = null)
250:     {
251:         $pre = $this->preUpdate($properties);
252:         if ($pre === false) {
253:             return false;
254:         }
255:         $ret = $this->source()->updateItem($this, $properties);
256:         if ($ret === false) {
257:             return false;
258:         }
259:         $post = $this->postUpdate($properties);
260:         if ($post === false) {
261:             return false;
262:         }
263:         return true;
264:     }
265: 
266:     /**
267:      * Delete an object from storage.
268:      *
269:      * @return boolean
270:      */
271:     public function delete()
272:     {
273:         $pre = $this->preDelete();
274:         if ($pre === false) {
275:             return false;
276:         }
277:         $ret = $this->source()->deleteItem($this);
278:         $this->postDelete();
279:         return $ret;
280:     }
281: 
282:     /**
283:      * @return boolean
284:      */
285:     protected function preSave()
286:     {
287:         return true;
288:     }
289: 
290:     /**
291:      * @return boolean
292:      */
293:     protected function postSave()
294:     {
295:         return true;
296:     }
297: 
298:     /**
299:      * @param string[] $keys Optional. The list of keys to update.
300:      * @return boolean
301:      */
302:     protected function preUpdate(array $keys = null)
303:     {
304:         return true;
305:     }
306: 
307:     /**
308:      * @param string[] $keys Optional. The list of keys to update.
309:      * @return boolean
310:      */
311:     protected function postUpdate(array $keys = null)
312:     {
313:         return true;
314:     }
315: 
316:     /**
317:      * @return boolean
318:      */
319:     protected function preDelete()
320:     {
321:         return true;
322:     }
323: 
324:     /**
325:      * @return boolean
326:      */
327:     protected function postDelete()
328:     {
329:         return true;
330:     }
331: }
332: 
API documentation generated by ApiGen