/** * Generates a string representation of a schema. * * @param \Cake\Database\Schema\Table $table Table schema * @return string fields definitions */ protected function _generateSchema(Table $table) { $cols = $indexes = $constraints = []; foreach ($table->columns() as $field) { $fieldData = $table->column($field); $properties = implode(', ', $this->_values($fieldData)); $cols[] = " '{$field}' => [{$properties}],"; } foreach ($table->indexes() as $index) { $fieldData = $table->index($index); $properties = implode(', ', $this->_values($fieldData)); $indexes[] = " '{$index}' => [{$properties}],"; } foreach ($table->constraints() as $index) { $fieldData = $table->constraint($index); $properties = implode(', ', $this->_values($fieldData)); $constraints[] = " '{$index}' => [{$properties}],"; } $options = $this->_values($table->options()); $content = implode("\n", $cols) . "\n"; if (!empty($indexes)) { $content .= " '_indexes' => [\n" . implode("\n", $indexes) . "\n ],\n"; } if (!empty($constraints)) { $content .= " '_constraints' => [\n" . implode("\n", $constraints) . "\n ],\n"; } if (!empty($options)) { foreach ($options as &$option) { $option = ' ' . $option; } $content .= " '_options' => [\n" . implode(",\n", $options) . "\n ],\n"; } return "[\n{$content} ]"; }
/** * Does individual field validation handling. * * @param \Cake\Database\Schema\Table $schema The table schema for the current field. * @param string $fieldName Name of field to be validated. * @param array $metaData metadata for field * @param string $primaryKey The primary key field * @return array Array of validation for the field. */ public function fieldValidation($schema, $fieldName, array $metaData, $primaryKey) { $ignoreFields = ['created', 'modified', 'updated']; if (in_array($fieldName, $ignoreFields)) { return false; } $rule = false; if ($fieldName === 'email') { $rule = 'email'; } elseif ($metaData['type'] === 'uuid') { $rule = 'uuid'; } elseif ($metaData['type'] === 'integer') { $rule = 'numeric'; } elseif ($metaData['type'] === 'float') { $rule = 'numeric'; } elseif ($metaData['type'] === 'decimal') { $rule = 'decimal'; } elseif ($metaData['type'] === 'boolean') { $rule = 'boolean'; } elseif ($metaData['type'] === 'date') { $rule = 'date'; } elseif ($metaData['type'] === 'time') { $rule = 'time'; } elseif ($metaData['type'] === 'datetime') { $rule = 'datetime'; } elseif ($metaData['type'] === 'inet') { $rule = 'ip'; } $allowEmpty = false; if (in_array($fieldName, $primaryKey)) { $allowEmpty = 'create'; } elseif ($metaData['null'] === true) { $allowEmpty = true; } $validation = ['valid' => ['rule' => $rule, 'allowEmpty' => $allowEmpty]]; foreach ($schema->constraints() as $constraint) { $constraint = $schema->constraint($constraint); if (!in_array($fieldName, $constraint['columns']) || count($constraint['columns']) > 1) { continue; } if ($constraint['type'] === SchemaTable::CONSTRAINT_UNIQUE) { $validation['unique'] = ['rule' => 'validateUnique', 'provider' => 'table']; } } return $validation; }
/** * {@inheritDoc} */ public function dropConstraintSql(Table $table) { $sqlPattern = 'ALTER TABLE %s DROP CONSTRAINT %s;'; $sql = []; foreach ($table->constraints() as $name) { $constraint = $table->constraint($name); if ($constraint['type'] === Table::CONSTRAINT_FOREIGN) { $tableName = $this->_driver->quoteIdentifier($table->name()); $constraintName = $this->_driver->quoteIdentifier($name); $sql[] = sprintf($sqlPattern, $tableName, $constraintName); } } return $sql; }
/** * Returns table primary key. * * @param Table $table Table schema object. * @return array|null */ protected function _getPrimaryKey(Table $table) { $constraints = $table->constraints(); foreach ($constraints as $name) { $constraint = $table->constraint($name); if ($this->_isSingleKey($table, [$constraint])) { return $constraint; } } return null; }
/** * find the table, if any, actually referenced by the passed key field. * Search tables in db for keyField; if found search key constraints * for the table to which it refers. * * @param \Cake\Database\Schema\Table $schema The table schema to find a constraint for. * @param string $keyField The field to check for a constraint. * @return string|null Either the referenced table or null if the field has no constraints. */ public function findTableReferencedBy($schema, $keyField) { if (!$schema->column($keyField)) { return null; } foreach ($schema->constraints() as $constraint) { $constraintInfo = $schema->constraint($constraint); if (in_array($keyField, $constraintInfo['columns'])) { if (!isset($constraintInfo['references'])) { continue; } return $constraintInfo['references'][0]; } } return null; }
/** * Add a basic foreign key constraint. * * @return void */ public function testAddConstraintForeignKey() { $table = new Table('articles'); $table->addColumn('author_id', 'integer')->addConstraint('author_id_idx', ['type' => Table::CONSTRAINT_FOREIGN, 'columns' => ['author_id'], 'references' => ['authors', 'id'], 'update' => 'cascade', 'delete' => 'cascade']); $this->assertEquals(['author_id_idx'], $table->constraints()); }
/** * Generates SQL statements dropping foreign keys for the table. * * @param \Cake\Database\Connection $db Connection to run the SQL queries on. * @param \Cake\Database\Schema\Table $table Drop foreign keys for this table. * @return array List of SQL statements dropping foreign keys. */ protected function _generateDropForeignKeys($db, Schema $table) { $type = 'other'; if ($db->driver() instanceof Mysql) { $type = 'mysql'; } $queries = []; foreach ($table->constraints() as $constraintName) { $constraint = $table->constraint($constraintName); if ($constraint['type'] === Schema::CONSTRAINT_FOREIGN) { // TODO: Move this into the driver if ($type === 'mysql') { $template = 'ALTER TABLE %s DROP FOREIGN KEY %s'; } else { $template = 'ALTER TABLE %s DROP CONSTRAINT %s'; } $queries[] = sprintf($template, $table->name(), $constraintName); } } return $queries; }