/** * Assign data to mapper * * @param array $data * @return object $this */ public function assign(array $data) { foreach ($this->mapper ? $data : [] as $key => $value) { $this->mapper->set($key, $value); } return $this; }
/** * Resolve default filter and assign default value if field not changed */ public function resolveDefaultFilter() { $app = Base::instance(); foreach ($this->map ? $this->map->schema() : [] as $field => $schema) { if ($schema['pkey'] && PDO::PARAM_INT === $schema['pdo_type']) { continue; } $filters = []; $filters['required'] = [!$schema['nullable']]; if (preg_match('/^(?<type>\\w+)(?:\\((?<length>.+)\\))?/', $schema['type'], $match)) { $length = isset($match['length']) ? $match['length'] : null; switch ($match['type']) { case 'int': case 'bigint': case 'smallint': case 'tinyint': case 'integer': $filters['maxInt'] = [null, $length]; break; case 'decimal': case 'double': case 'float': case 'real': $x = $app->split($length); $base = pow(10, $x[0] - $x[1]) - 1; $precision = (pow(10, $x[1]) - 1) * 1 / pow(10, $x[1]); $max = $base + $precision; $filters['maxFloat'] = [$max, $length]; break; case 'enum': case 'set': $filters['choices'] = [$app->split(str_replace(['"', "'"], '', $length)), $schema['nullable']]; break; case 'date': $filters['date'] = [$schema['nullable']]; break; default: $filters['maxLength'] = [$length, $schema['nullable']]; break; } } $this->filters[$field] = $filters; if (!$schema['changed'] && (is_null($schema['value']) || '' === $schema['value']) && !(is_null($schema['default']) || '' === $schema['default'])) { $this->map->set($field, $schema['default']); } } return $this; }
/** * Bind value to key * @return mixed * @param $key string * @param $val mixed */ function set($key, $val) { $fields = $this->fieldConf; unset($this->fieldsCache[$key]); // pre-process if field config available if (!empty($fields) && isset($fields[$key]) && is_array($fields[$key])) { // handle relations if (isset($fields[$key]['belongs-to-one'])) { // one-to-many, one-to-one if (is_null($val)) { $val = NULL; } elseif (is_object($val) && !($this->dbsType == 'mongo' && $val instanceof \MongoId)) { // fetch fkey from mapper if (!$val instanceof Cortex || $val->dry()) { trigger_error(self::E_INVALID_RELATION_OBJECT); } else { $relConf = $fields[$key]['belongs-to-one']; $rel_field = is_array($relConf) ? $relConf[1] : '_id'; $val = $val->get($rel_field, true); } } elseif ($this->dbsType == 'mongo' && !$val instanceof \MongoId) { $val = new \MongoId($val); } } elseif (isset($fields[$key]['has-one'])) { $relConf = $fields[$key]['has-one']; if (is_null($val)) { $val = $this->get($key); $val->set($relConf[1], NULL); } else { if (!$val instanceof Cortex) { $rel = $this->getRelInstance($relConf[0], null, $key); $rel->load(array('_id = ?', $val)); $val = $rel; } $val->set($relConf[1], $this->_id); } $this->saveCsd[$key] = $val; return $val; } elseif (isset($fields[$key]['belongs-to-many'])) { // many-to-many, unidirectional $fields[$key]['type'] = self::DT_JSON; $relConf = $fields[$key]['belongs-to-many']; $rel_field = is_array($relConf) ? $relConf[1] : '_id'; $val = $this->getForeignKeysArray($val, $rel_field, $key); } elseif (isset($fields[$key]['has-many'])) { // many-to-many, bidirectional $relConf = $fields[$key]['has-many']; if ($relConf['hasRel'] == 'has-many') { // custom setter $val = $this->emit('set_' . $key, $val); $val = $this->getForeignKeysArray($val, '_id', $key); $this->saveCsd[$key] = $val; // array of keys return $val; } elseif ($relConf['hasRel'] == 'belongs-to-one') { // TODO: many-to-one, bidirectional, inverse way trigger_error("not implemented"); } } // convert array content if (is_array($val) && $this->dbsType == 'sql') { if ($fields[$key]['type'] == self::DT_SERIALIZED) { $val = serialize($val); } elseif ($fields[$key]['type'] == self::DT_JSON) { $val = json_encode($val); } else { trigger_error(sprintf(self::E_ARRAY_DATATYPE, $key)); } } // add nullable polyfill if ($val === NULL && ($this->dbsType == 'jig' || $this->dbsType == 'mongo') && array_key_exists('nullable', $fields[$key]) && $fields[$key]['nullable'] === false) { trigger_error(sprintf(self::E_NULLABLE_COLLISION, $key)); } // MongoId shorthand if ($this->dbsType == 'mongo' && !$val instanceof \MongoId) { if ($key == '_id') { $val = new \MongoId($val); } elseif (preg_match('/INT/i', $fields[$key]['type']) && !isset($fields[$key]['relType'])) { $val = (int) $val; } } if (preg_match('/BOOL/i', $fields[$key]['type'])) { $val = !$val || $val === 'false' ? false : (bool) $val; if ($this->dbsType == 'sql') { $val = (int) $val; } } } // fluid SQL if ($this->fluid && $this->dbsType == 'sql') { $schema = new Schema($this->db); $table = $schema->alterTable($this->table); // add missing field if (!in_array($key, $table->getCols())) { // determine data type if (isset($this->fieldConf[$key]) && isset($this->fieldConf[$key]['type'])) { $type = $this->fieldConf[$key]['type']; } elseif (is_int($val)) { $type = $schema::DT_INT; } elseif (is_double($val)) { $type = $schema::DT_DOUBLE; } elseif (is_float($val)) { $type = $schema::DT_FLOAT; } elseif (is_bool($val)) { $type = $schema::DT_BOOLEAN; } elseif (date('Y-m-d H:i:s', strtotime($val)) == $val) { $type = $schema::DT_DATETIME; } elseif (date('Y-m-d', strtotime($val)) == $val) { $type = $schema::DT_DATE; } elseif (\UTF::instance()->strlen($val) <= 255) { $type = $schema::DT_VARCHAR256; } else { $type = $schema::DT_TEXT; } $table->addColumn($key)->type($type); $table->build(); // update mapper fields $newField = $table->getCols(true); $newField = $newField[$key]; $refl = new \ReflectionObject($this->mapper); $prop = $refl->getProperty('fields'); $prop->setAccessible(true); $fields = $prop->getValue($this->mapper); $fields[$key] = $newField + array('value' => NULL, 'changed' => NULL); $prop->setValue($this->mapper, $fields); } } // custom setter $val = $this->emit('set_' . $key, $val); return $this->mapper->set($key, $val); }