      1: <?php
      2:
      3: /*
      4:  * This file is part of the CRUDlex package.
      5:  *
      6:  * (c) Philip Lehmann-Böhm <philip@philiplb.de>
      7:  *
      8:  * For the full copyright and license information, please view the LICENSE
      9:  * file that was distributed with this source code.
     10:  */
     11:
     12: namespace CRUDlex;
     13:
     14: use CRUDlex\CRUDEntityDefinition;
     15: use CRUDlex\CRUDData;
     16:
     17: /**
     18:  * Represents a single set of data in field value pairs like the row in a
     19:  * database. Depends of course on the {@see CRUDData} implementation being used.
     20:  * With this objects, the data is passed arround and validated.
     21:  */
     22: class CRUDEntity {
     23:
     24:     /**
     25:      * The {@see CRUDEntityDefinition} defining how this entity looks like.
     26:      */
     27:     protected $definition;
     28:
     29:     /**
     30:      * Holds the key value data of the entity.
     31:      */
     32:     protected $entity = array();
     33:
     34:     /**
     35:      * Constructor.
     36:      *
     37:      * @param CRUDEntityDefinition $definition
     38:      * the definition how this entity looks
     39:      */
     40:     public function __construct(CRUDEntityDefinition $definition) {
     41:         $this->definition = $definition;
     42:     }
     43:
     44:     /**
     45:      * Sets a field value pair of this entity.
     46:      *
     47:      * @param string $field
     48:      * the field
     49:      * @param mixed $value
     50:      * the value
     51:      */
     52:     public function set($field, $value) {
     53:         $this->entity[$field] = $value;
     54:     }
     55:
     56:     /**
     57:      * Gets the value of a field.
     58:      *
     59:      * @param string $field
     60:      * the field
     61:      *
     62:      * @return mixed
     63:      * null on invalid field, an int if the definition says that the
     64:      * type of the field is an int, a boolean if the field is a bool or
     65:      * else the raw value
     66:      */
     67:     public function get($field) {
     68:         if (!key_exists($field, $this->entity)) {
     69:             return null;
     70:         }
     71:         $value = $this->entity[$field];
     72:         switch ($this->definition->getType($field)) {
     73:             case 'int':
     74:                 $value = intval($value);
     75:                 break;
     76:             case 'float':
     77:                 $value = floatval($value);
     78:                 break;
     79:             case 'bool':
     80:                 $value = $value && $value !== '0';
     81:                 break;
     82:         }
     83:         return $value;
     84:     }
     85:
     86:     /**
     87:      * Gets the entity definition.
     88:      *
     89:      * @return CRUDEntityDefinition
     90:      * the definition
     91:      */
     92:     public function getDefinition() {
     93:         return $this->definition;
     94:     }
     95:
     96:     /**
     97:      * Validates the entity against the definition.
     98:      *
     99:      * @param CRUDData $data
    100:      * the data access instance used for counting things
    101:      *
    102:      * @return array
    103:      * an array with the fields "valid" and "errors"; valid provides a quick
    104:      * check whether the given entity passes the validation and errors is an
    105:      * array with all fields as keys and arrays as values; this field arrays
    106:      * contain three keys: required, unique and input; each of them represents
    107:      * with a boolean whether the input is ok in that way; if "required" is
    108:      * true, the field wasn't set, unique means the uniqueness of the field in
    109:      * the datasource and input is used to indicate whether the form of the
    110:      * value is correct (a valid int, date, depending on the type in the
    111:      * definition)
    112:      */
    113:     public function validate(CRUDData $data) {
    114:
    115:         $fields = $this->definition->getEditableFieldNames();
    116:         $errors = array();
    117:         $valid = true;
    118:         foreach ($fields as $field) {
    119:             $errors[$field] = array('required' => false, 'unique' => false, 'input' => false);
    120:
    121:             // Check for required
    122:             if ($this->definition->isRequired($field) && (!key_exists($field, $this->entity)
    123:                 || $this->entity[$field] === null
    124:                 || $this->entity[$field] === '')) {
    125:                 $errors[$field]['required'] = true;
    126:                 $valid = false;
    127:             }
    128:
    129:             // Check for uniqueness
    130:             if ($this->definition->isUnique($field) && key_exists($field, $this->entity) && $this->entity[$field]) {
    131:                 $params = array($field => $this->entity[$field]);
    132:                 $paramsOperators = array($field => '=');
    133:                 if ($this->entity['id'] !== null) {
    134:                     $params['id'] = $this->entity['id'];
    135:                     $paramsOperators['id'] = '!=';
    136:                 }
    137:                 $amount = intval($data->countBy($this->definition->getTable(), $params, $paramsOperators, true));
    138:                 if ($amount > 0) {
    139:                     $errors[$field]['unique'] = true;
    140:                     $valid = false;
    141:                 }
    142:             }
    143:
    144:             // Check for set type
    145:             $type = $this->definition->getType($field);
    146:             if ($type == 'set' && $this->entity[$field]) {
    147:                 $setItems = $this->definition->getSetItems($field);
    148:                 if (!in_array($this->entity[$field], $setItems)) {
    149:                     $errors[$field]['input'] = true;
    150:                     $valid = false;
    151:                 }
    152:             }
    153:
    154:             // Check for int type
    155:             $type = $this->definition->getType($field);
    156:             if ($type == 'int' && $this->entity[$field] !== '' && (string)(int)$this->entity[$field] != $this->entity[$field]) {
    157:                 $errors[$field]['input'] = true;
    158:                 $valid = false;
    159:             }
    160:
    161:             // Check for float type
    162:             $type = $this->definition->getType($field);
    163:             if ($type == 'float' && $this->entity[$field] !== '' && (string)(float)$this->entity[$field] != $this->entity[$field]) {
    164:                 $errors[$field]['input'] = true;
    165:                 $valid = false;
    166:             }
    167:
    168:             // Check for date type
    169:             if ($type == 'date' && $this->entity[$field] && \DateTime::createFromFormat('Y-m-d', $this->entity[$field]) === false) {
    170:                 $errors[$field]['input'] = true;
    171:                 $valid = false;
    172:             }
    173:
    174:             // Check for datetime type
    175:             if ($type == 'datetime' && $this->entity[$field] &&
    176:                 \DateTime::createFromFormat('Y-m-d H:i', $this->entity[$field]) === false &&
    177:                 \DateTime::createFromFormat('Y-m-d H:i:s', $this->entity[$field]) === false) {
    178:                 $errors[$field]['input'] = true;
    179:                 $valid = false;
    180:             }
    181:
    182:             // Check for reference type
    183:             if ($type == 'reference' && $this->entity[$field] !== '') {
    184:                 $params = array('id' => $this->entity[$field]);
    185:                 $paramsOperators = array('id' => '=');
    186:                 $amount = $data->countBy($this->definition->getReferenceTable($field), $params, $paramsOperators, false);
    187:                 if ($amount == 0) {
    188:                     $errors[$field]['input'] = true;
    189:                     $valid = false;
    190:                 }
    191:             }
    192:         }
    193:         return array('valid' => $valid, 'errors' => $errors);
    194:     }
    195:
    196: }
    197: