예제 #1
0
 /**
  * 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);
 }
예제 #2
0
 /**
  * get database connection information
  * @param $f3
  * @param bool|false $exec
  * @return array
  */
 protected function checkDatabase($f3, $exec = false)
 {
     foreach ($this->databases as $dbKey => $dbData) {
         $dbLabel = '';
         $dbName = '';
         $dbUser = '';
         $dbConfig = [];
         // DB connection status
         $dbConnected = false;
         // DB type (e.g. MySql,..)
         $dbDriver = 'unknown';
         // enable database ::setup() function in UI
         $dbSetupEnable = false;
         // check  of everything is OK (connection, tables, columns, indexes,..)
         $dbStatusCheckCount = 0;
         // db queries for column fixes (types, indexes, unique)
         $dbColumnQueries = [];
         // tables that should exist in this DB
         $requiredTables = [];
         // check DB for valid connection
         $db = DB\Database::instance()->getDB($dbKey);
         switch ($dbKey) {
             case 'PF':
                 $dbLabel = 'Pathfinder';
                 $dbName = Controller::getEnvironmentData('DB_NAME');
                 $dbUser = Controller::getEnvironmentData('DB_USER');
                 // enable (table) setup for this DB
                 $dbSetupEnable = true;
                 // get table data from model
                 foreach ($dbData['models'] as $model) {
                     $tableConfig = call_user_func($model . '::resolveConfiguration');
                     $requiredTables[$tableConfig['table']] = ['model' => $model, 'name' => $tableConfig['table'], 'fieldConf' => $tableConfig['fieldConf'], 'exists' => false, 'empty' => true, 'foreignKeys' => []];
                 }
                 break;
             case 'CCP':
                 $dbLabel = 'EVE-Online [SDE]';
                 $dbName = Controller::getEnvironmentData('DB_CCP_NAME');
                 $dbUser = Controller::getEnvironmentData('DB_CCP_USER');
                 // get table model from static table array
                 foreach ($dbData['tables'] as $tableName) {
                     $requiredTables[$tableName] = ['exists' => false, 'empty' => true];
                 }
                 break;
         }
         if ($db) {
             // db connect was successful
             $dbConnected = true;
             $dbDriver = $db->driver();
             $dbConfig = $this->checkDBConfig($f3, $db);
             // get tables
             $schema = new SQL\Schema($db);
             $currentTables = $schema->getTables();
             // check each table for changes
             foreach ($requiredTables as $requiredTableName => $data) {
                 $tableExists = false;
                 $tableEmpty = true;
                 // Check if table status is OK (no errors/warnings,..)
                 $tableStatusCheckCount = 0;
                 $currentColumns = [];
                 if (in_array($requiredTableName, $currentTables)) {
                     // Table exists
                     $tableExists = true;
                     // get existing table columns and column related constraints (if exists)
                     $tableModifierTemp = new MySQL\TableModifier($requiredTableName, $schema);
                     $currentColumns = $tableModifierTemp->getCols(true);
                     // get row count
                     $countRes = $db->exec("SELECT COUNT(*) `num` FROM " . $db->quotekey($requiredTableName));
                     $tableEmpty = $countRes[0]['num'] > 0 ? false : true;
                 } else {
                     // table missing
                     $dbStatusCheckCount++;
                     $tableStatusCheckCount++;
                 }
                 foreach ((array) $data['fieldConf'] as $columnName => $fieldConf) {
                     $columnStatusCheck = true;
                     $foreignKeyStatusCheck = true;
                     $requiredTables[$requiredTableName]['fieldConf'][$columnName]['requiredType'] = $fieldConf['type'];
                     $requiredTables[$requiredTableName]['fieldConf'][$columnName]['requiredIndex'] = $fieldConf['index'] ? '1' : '0';
                     $requiredTables[$requiredTableName]['fieldConf'][$columnName]['requiredUnique'] = $fieldConf['unique'] ? '1' : '0';
                     if (array_key_exists($columnName, $currentColumns)) {
                         // column exists
                         // get tableModifier -> possible column update
                         $tableModifier = new MySQL\TableModifier($requiredTableName, $schema);
                         // get new column and copy Schema from existing column
                         $col = new MySQL\Column($columnName, $tableModifier);
                         $col->copyfrom($currentColumns[$columnName]);
                         $currentColType = $currentColumns[$columnName]['type'];
                         $currentColIndexData = call_user_func($data['model'] . '::indexExists', [$columnName]);
                         $currentColIndex = is_array($currentColIndexData);
                         $hasIndex = $currentColIndex ? '1' : '0';
                         $hasUnique = $currentColIndexData['unique'] ? '1' : '0';
                         $changedType = false;
                         $changedUnique = false;
                         $changedIndex = false;
                         // set (new) column information -------------------------------------------------------
                         $requiredTables[$requiredTableName]['fieldConf'][$columnName]['exists'] = true;
                         $requiredTables[$requiredTableName]['fieldConf'][$columnName]['currentType'] = $currentColType;
                         $requiredTables[$requiredTableName]['fieldConf'][$columnName]['currentIndex'] = $hasIndex;
                         $requiredTables[$requiredTableName]['fieldConf'][$columnName]['currentUnique'] = $hasUnique;
                         // check constraint -------------------------------------------------------------------
                         if (isset($fieldConf['constraint'])) {
                             // add or update constraints
                             foreach ((array) $fieldConf['constraint'] as $constraintData) {
                                 $constraint = $col->newConstraint($constraintData);
                                 $foreignKeyExists = $col->constraintExists($constraint);
                                 $requiredTables[$requiredTableName]['foreignKeys'][] = ['exists' => $foreignKeyExists, 'keyName' => $constraint->getConstraintName()];
                                 $col->addConstraint($constraint);
                                 if (!$foreignKeyExists) {
                                     $tableStatusCheckCount++;
                                     $foreignKeyStatusCheck = false;
                                 }
                             }
                         }
                         // check type changed -----------------------------------------------------------------
                         if ($fieldConf['type'] !== 'JSON' && !$schema->isCompatible($fieldConf['type'], $currentColType)) {
                             // column type has changed
                             $changedType = true;
                             $columnStatusCheck = false;
                             $tableStatusCheckCount++;
                         }
                         // check if column unique changed -----------------------------------------------------
                         $indexUpdate = false;
                         $indexKey = (bool) $hasIndex;
                         $indexUnique = (bool) $hasUnique;
                         if ($currentColIndexData['unique'] != $fieldConf['unique']) {
                             $changedUnique = true;
                             $columnStatusCheck = false;
                             $tableStatusCheckCount++;
                             $indexUpdate = true;
                             $indexUnique = (bool) $fieldConf['unique'];
                         }
                         // check if column index changed ------------------------------------------------------
                         if ($currentColIndex != $fieldConf['index']) {
                             $changedIndex = true;
                             $columnStatusCheck = false;
                             $tableStatusCheckCount++;
                             $indexUpdate = true;
                             $indexKey = (bool) $fieldConf['index'];
                         }
                         // build table with changed columns ---------------------------------------------------
                         if (!$columnStatusCheck || !$foreignKeyStatusCheck) {
                             if (!$columnStatusCheck) {
                                 // IMPORTANT: setType is always required! Even if type has not changed
                                 $col->type($fieldConf['type']);
                                 // update/change/delete index/unique keys
                                 if ($indexUpdate) {
                                     if ($hasIndex) {
                                         $tableModifier->dropIndex($columnName);
                                     }
                                     if ($indexKey) {
                                         $tableModifier->addIndex($columnName, $indexUnique);
                                     }
                                 }
                                 $tableModifier->updateColumn($columnName, $col);
                             }
                             $buildStatus = $tableModifier->build($exec);
                             if (is_array($buildStatus) || is_string($buildStatus)) {
                                 // query strings for change available
                                 $dbColumnQueries = array_merge($dbColumnQueries, (array) $buildStatus);
                             }
                         }
                         // set (new) column information -------------------------------------------------------
                         $requiredTables[$requiredTableName]['fieldConf'][$columnName]['changedType'] = $changedType;
                         $requiredTables[$requiredTableName]['fieldConf'][$columnName]['changedUnique'] = $changedUnique;
                         $requiredTables[$requiredTableName]['fieldConf'][$columnName]['changedIndex'] = $changedIndex;
                     } elseif (!isset($fieldConf['has-manny']) && isset($fieldConf['type'])) {
                         // column not exists but it is required!
                         // columns that do not match this criteria ("mas-manny") are "virtual" fields
                         // and can be ignored
                         $requiredTables[$requiredTableName]['fieldConf'][$columnName]['currentType'] = '';
                         $columnStatusCheck = false;
                         $tableStatusCheckCount++;
                     }
                     $requiredTables[$requiredTableName]['fieldConf'][$columnName]['statusCheck'] = $columnStatusCheck;
                 }
                 $dbStatusCheckCount += $tableStatusCheckCount;
                 $requiredTables[$requiredTableName]['empty'] = $tableEmpty;
                 $requiredTables[$requiredTableName]['exists'] = $tableExists;
                 $requiredTables[$requiredTableName]['statusCheckCount'] = $tableStatusCheckCount;
             }
         } else {
             // DB connection failed
             $dbStatusCheckCount++;
         }
         if ($exec) {
             $f3->reroute('@setup');
         }
         $this->databases[$dbKey]['info'] = ['db' => $db, 'label' => $dbLabel, 'driver' => $dbDriver, 'name' => $dbName, 'user' => $dbUser, 'dbConfig' => $dbConfig, 'setupEnable' => $dbSetupEnable, 'connected' => $dbConnected, 'statusCheckCount' => $dbStatusCheckCount, 'columnQueries' => $dbColumnQueries, 'tableData' => $requiredTables];
     }
     return $this->databases;
 }
예제 #3
0
 /**
  * get tableModifier class for this table
  * @return bool|DB\SQL\TableModifier
  */
 public static function getTableModifier()
 {
     $df = parent::resolveConfiguration();
     $schema = new Schema($df['db']);
     $tableModifier = $schema->alterTable($df['table']);
     return $tableModifier;
 }
예제 #4
0
 /**
  * get all table names from a DB
  * @param string $database
  * @return array|bool
  */
 public function getTables($database = 'PF')
 {
     $schema = new SQL\Schema($this->getDB($database));
     return $schema->getTables();
 }