/** * Migrate create schema * * @return \Doctrine\DBAL\Schema\Schema */ public function migrateCreateSchema() { $entityName = $this->mapper->entity(); $table = $entityName::table(); $fields = $this->mapper->entityManager()->fields(); $fieldIndexes = $this->mapper->entityManager()->fieldKeys(); $schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable($this->escapeIdentifier($table)); foreach ($fields as $field => $fieldInfo) { $fieldType = $fieldInfo['type']; unset($fieldInfo['type']); $table->addColumn($field, $fieldType, $fieldInfo); } // PRIMARY if ($fieldIndexes['primary']) { $table->setPrimaryKey($fieldIndexes['primary']); } // UNIQUE foreach ($fieldIndexes['unique'] as $keyName => $keyFields) { $table->addUniqueIndex($keyFields, $keyName); } // INDEX foreach ($fieldIndexes['index'] as $keyName => $keyFields) { $table->addIndex($keyFields, $keyName); } return $schema; }
/** * Migrate create schema * * @return \Doctrine\DBAL\Schema\Schema */ public function migrateCreateSchema() { $entityName = $this->mapper->entity(); $table = $entityName::table(); $fields = $this->mapper->entityManager()->fields(); $fieldIndexes = $this->mapper->entityManager()->fieldKeys(); $schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable($this->escapeIdentifier($table)); foreach ($fields as $field) { $fieldType = $field['type']; unset($field['type']); $table->addColumn($this->escapeIdentifier($field['column']), $fieldType, $field); } // PRIMARY if ($fieldIndexes['primary']) { $resolver = $this; $primaryKeys = array_map(function ($value) use($resolver) { return $resolver->escapeIdentifier($value); }, $fieldIndexes['primary']); $table->setPrimaryKey($primaryKeys); } // UNIQUE foreach ($fieldIndexes['unique'] as $keyName => $keyFields) { $table->addUniqueIndex($keyFields, $this->escapeIdentifier($this->trimSchemaName($keyName))); } // INDEX foreach ($fieldIndexes['index'] as $keyName => $keyFields) { $table->addIndex($keyFields, $this->escapeIdentifier($this->trimSchemaName($keyName))); } return $schema; }
/** * Constructor Method * * @param Spot_Mapper * @param string $entityName Name of the entity to query on/for */ public function __construct(\Spot\Mapper $mapper) { $this->_mapper = $mapper; $this->_entityName = $mapper->entity(); $this->_tableName = $mapper->table(); // Create Doctrine DBAL query builder from Doctrine\DBAL\Connection $this->_queryBuilder = $mapper->connection()->createQueryBuilder(); }
/** * @param Generator $generator * @return array */ public function guessColumnFormatters(Generator $generator) { $formatters = array(); $nameGuesser = new Name($generator); $columnTypeGuesser = new ColumnTypeGuesser($generator); $fields = $this->mapper->fields(); foreach ($fields as $fieldName => $field) { if ($field['primary'] === true) { continue; } if ($formatter = $nameGuesser->guessFormat($fieldName)) { $formatters[$fieldName] = $formatter; continue; } if ($formatter = $columnTypeGuesser->guessFormat($field)) { $formatters[$fieldName] = $formatter; continue; } } $entityName = $this->mapper->entity(); $entity = $this->mapper->build([]); $relations = $entityName::relations($this->mapper, $entity); foreach ($relations as $relation) { // We don't need any other relation here. if ($relation instanceof BelongsTo) { $fieldName = $relation->localKey(); $entityName = $relation->entityName(); $field = $fields[$fieldName]; $required = $field['required']; $locator = $this->locator; $formatters[$fieldName] = function ($inserted) use($required, $entityName, $locator) { if (!empty($inserted[$entityName])) { return $inserted[$entityName][mt_rand(0, count($inserted[$entityName]) - 1)]->getId(); } else { if ($required && $this->useExistingData) { // We did not add anything like this, but it's required, // So let's find something existing in DB. $mapper = $this->locator->mapper($entityName); $records = $mapper->all()->limit(self::RELATED_FETCH_COUNT)->toArray(); if (empty($records)) { return null; } $id = $records[mt_rand(0, count($records) - 1)]['id']; return $id; } else { return null; } } }; } } return $formatters; }
/** * Add foreign keys from BelongsTo relations to the table schema * @param Table $table * @return Table */ protected function addForeignKeys(Table $table) { $entityName = $this->mapper->entity(); $entity = new $entityName(); $relations = $entityName::relations($this->mapper, $entity); $fields = $this->mapper->entityManager()->fields(); foreach ($relations as $relationName => $relation) { if ($relation instanceof BelongsTo) { $fieldInfo = $fields[$relation->localKey()]; if ($fieldInfo['foreignkey'] === false) { continue; } $foreignTableMapper = $relation->mapper()->getMapper($relation->entityName()); $foreignTable = $foreignTableMapper->table(); $foreignSchemaManager = $foreignTableMapper->connection()->getSchemaManager(); $foreignTableObject = $foreignSchemaManager->listTableDetails($foreignTable); $foreignTableColumns = $foreignTableObject->getColumns(); $foreignTableNotExists = empty($foreignTableColumns); $foreignKeyNotExists = !array_key_exists($relation->foreignKey(), $foreignTableColumns); // We need to use the is_a() function because the there is some inconsistency in entity names (leading slash) $notRecursiveForeignKey = !is_a($entity, $relation->entityName()); /* Migrate foreign table if: * - the foreign table not exists * - the foreign key not exists * - the foreign table is not the same as the current table (recursion check) * This migration eliminates the 'Integrity constraint violation' error */ if (($foreignTableNotExists || $foreignKeyNotExists) && $notRecursiveForeignKey) { $foreignTableMapper->migrate(); } $onUpdate = !is_null($fieldInfo['onUpdate']) ? $fieldInfo['onUpdate'] : "CASCADE"; if (!is_null($fieldInfo['onDelete'])) { $onDelete = $fieldInfo['onDelete']; } else { if ($fieldInfo['notnull']) { $onDelete = "CASCADE"; } else { $onDelete = "SET NULL"; } } // Field alias support $fieldAliasMappings = $this->mapper->entityManager()->fieldAliasMappings(); if (isset($fieldAliasMappings[$relation->localKey()])) { $localKey = $fieldAliasMappings[$relation->localKey()]; } else { $localKey = $relation->localKey(); } $fkName = $this->mapper->table() . '_fk_' . $relationName; $table->addForeignKeyConstraint($foreignTable, [$localKey], [$relation->foreignKey()], ["onDelete" => $onDelete, "onUpdate" => $onUpdate], $fkName); } } return $table; }
/** * Migrate create schema * * @return \Doctrine\DBAL\Schema\Schema */ public function migrateCreateSchema() { $entityName = $this->mapper->entity(); $table = $entityName::table(); $fields = $this->mapper->entityManager()->fields(); $fieldIndexes = $this->mapper->entityManager()->fieldKeys(); $schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable($table); foreach ($fields as $field => $fieldInfo) { $fieldType = $fieldInfo['type']; unset($fieldInfo['type']); $table->addColumn($field, $fieldType, $fieldInfo); } // PRIMARY if ($fieldIndexes['primary']) { $table->setPrimaryKey($fieldIndexes['primary']); } // UNIQUE foreach ($fieldIndexes['unique'] as $keyName => $keyFields) { $table->addUniqueIndex($keyFields, $keyName); } // INDEX foreach ($fieldIndexes['index'] as $keyName => $keyFields) { $table->addIndex($keyFields, $keyName); } // Add foreign key constraints if necessary. $relations = call_user_func(array($entityName, 'relations'), $this->mapper, new $entityName()); // Skip, if there are no relations added. if (count($relations)) { foreach ($relations as $name => $relation) { /** * Since OneToMany and ManyToMany are at the inverse side * of the relations, their purpose is to return a collection * of entities/objects and there are no foreign keys on this side. * * So, we skip those entities, and expect a ManyToOne relation to be * defined on the owning side. */ if ($relation instanceof Relation\HasMany || $relation instanceof Relation\HasManyThrough) { continue; } $parentEntity = $relation->entityName(); $foreignTable = call_user_func([$parentEntity, 'table']); $localKey = $relation->localKey(); $foreignKey = $relation->foreignKey(); /** * Create an empty array that would hold our constraint options. * By default we can create a foreign key without having to * passing onDelete/onUpdate clauses, so at the very least, * an empty array is required. * * This array structure should be pairs of "column" => "option" * <code> * array("onDelete" => "CASCADE", "onUpdate" => "CASCADE") * </code> */ $constrains = []; /** * Check if onUpdate clause is been added. * If there is, add it to $constraints array. */ if (isset($fieldIndexes['constraints']['onUpdate'])) { if (array_key_exists($localKey, $fieldIndexes['constraints']['onUpdate'])) { $constrains['onUpdate'] = $fieldIndexes['constraints']['onUpdate'][$localKey]; } } /** * Check if onDelete clause is been added. * If there is, add it to $constraints array. */ if (isset($fieldIndexes['constraints']['onDelete'])) { if (array_key_exists($localKey, $fieldIndexes['constraints']['onDelete'])) { $constrains['onDelete'] = $fieldIndexes['constraints']['onDelete'][$localKey]; } } // Create the foreign key. $table->addForeignKeyConstraint($foreignTable, [$localKey], [$foreignKey], $constrains); } } return $schema; }