@noinspection PhpTooManyParametersInspection
@param string   $localKey
@param string   $foreignTable
@param string   $foreignKey
@param string   $type
@param int|null $length
@param bool     $notNullable
@param bool     $cascadeDelete

@return Closure
190298
private function foreignColumnImpl(
        string $localKey,
        string $foreignTable,
        string $foreignKey,
        string $type,
        ?int $length,
        bool $notNullable,
        bool $cascadeDelete
    ): Closure {
        return function (Table $table) use (
            $localKey,
            $foreignTable,
            $foreignKey,
            $notNullable,
            $cascadeDelete,
            $type,
            $length
        ) {
            $options = $cascadeDelete === true ? ['onDelete' => 'CASCADE'] : [];
            $column  = $table->addColumn($localKey, $type)->setNotnull($notNullable);
            $length === null ? $column->setUnsigned(true) : $column->setLength($length);
            $table->addForeignKeyConstraint($foreignTable, [$localKey], [$foreignKey], $options);
        };
    }
597615
protected function getForeignKeySqlDefinition(ForeignKey $foreignKey)
    {
        $def = '';
        if ($foreignKey->getConstraint()) {
            $def .= ' CONSTRAINT ' . $this->quoteColumnName($foreignKey->getConstraint());
        } else {
            $columnNames = [];
            foreach ($foreignKey->getColumns() as $column) {
                $columnNames[] = $this->quoteColumnName($column);
            }
            $def .= ' FOREIGN KEY (' . implode(',', $columnNames) . ')';
            $refColumnNames = [];
            foreach ($foreignKey->getReferencedColumns() as $column) {
                $refColumnNames[] = $this->quoteColumnName($column);
            }
            $def .= ' REFERENCES ' . $this->quoteTableName($foreignKey->getReferencedTable()->getName()) . ' (' . implode(',', $refColumnNames) . ')';
            if ($foreignKey->getOnDelete()) {
                $def .= ' ON DELETE ' . $foreignKey->getOnDelete();
            }
            if ($foreignKey->getOnUpdate()) {
                $def .= ' ON UPDATE ' . $foreignKey->getOnUpdate();
            }
        }

        return $def;
    }
892397
public function _cascadeUpdate($parentTableClassname, array $oldPrimaryKey, array $newPrimaryKey)
    {
        $this->_setupMetadata();
        $rowsAffected = 0;
        foreach ($this->_getReferenceMapNormalized() as $map) {
            if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_UPDATE])) {
                switch ($map[self::ON_UPDATE]) {
                    case self::CASCADE:
                        $newRefs = array();
                        $where = array();
                        for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
                            $col = $this->_db->foldCase($map[self::COLUMNS][$i]);
                            $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
                            if (array_key_exists($refCol, $newPrimaryKey)) {
                                $newRefs[$col] = $newPrimaryKey[$refCol];
                            }
                            $type = $this->_metadata[$col]['DATA_TYPE'];
                            $where[] = $this->_db->quoteInto(
                                $this->_db->quoteIdentifier($col, true) . ' = ?',
                                $oldPrimaryKey[$refCol], $type);
                        }
                        $rowsAffected += $this->update($newRefs, $where);
                        break;
                    default:
                        // no action
                        break;
                }
            }
        }
        return $rowsAffected;
    }
1226458
public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
    {
        $sql = '';
        if (strlen($foreignKey->getName())) {
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
        }
        $sql .= 'FOREIGN KEY (';

        if (count($foreignKey->getLocalColumns()) === 0) {
            throw new InvalidArgumentException("Incomplete definition. 'local' required.");
        }
        if (count($foreignKey->getForeignColumns()) === 0) {
            throw new InvalidArgumentException("Incomplete definition. 'foreign' required.");
        }
        if (strlen($foreignKey->getForeignTableName()) === 0) {
            throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
        }

        return $sql . implode(', ', $foreignKey->getQuotedLocalColumns($this))
            . ') REFERENCES '
            . $foreignKey->getQuotedForeignTableName($this) . ' ('
            . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')';
    }
1143708
public function hasMany($entity, string $related, string $foreignKey = null, string $localKey = null): HasMany
    {
        $foreignKey = $foreignKey ?: $this->getForeignKey();

        $relatedMapper = Manager::getInstance()->mapper($related);

        $localKey = $localKey ?: $this->getKeyName();

        // Add the relation to the definition in map
        list(, $caller) = debug_backtrace(false);
        $relation = $caller['function'];
        $this->relatedClasses[$relation] = $related;

        $this->addManyRelation($relation);
        $this->addForeignRelation($relation);

        return new HasMany($relatedMapper, $entity, $foreignKey, $localKey);
    }
341681
public function hasOne($related, $foreignKey = null, $localKey = null)
    {
        $args = func_get_args();
        $args['type'] = 'hasOne';
        return $this->setRelationship(json_encode($args));
    }
1118908
public function addColumnMapping(ColumnMap $local, ColumnMap $foreign)
    {
        $this->localColumns[] = $local;
        $this->foreignColumns[] = $foreign;
    }
218341
public function createForeignKey($foreignKey, $table)
    {
        $changeSetElt = $this->createChangeSet('create-foreign-keys-' . $table->getName());
        $addForeignKeyConstraintElt = $this->document->createElement('addForeignKeyConstraint');

        $this->fillForeignKeyAttributes($addForeignKeyConstraintElt, $foreignKey, $table);

        $changeSetElt->appendChild($addForeignKeyConstraintElt);
        $this->root->appendChild($changeSetElt);
    }
706894
protected function getForeignKeySqlDefinition(ForeignKey $foreignKey, $tableName)
    {
        $constraintName = $foreignKey->getConstraint() ?: $tableName . '_' . implode('_', $foreignKey->getColumns());
        $def = ' CONSTRAINT ' . $this->quoteColumnName($constraintName);
        $def .= ' FOREIGN KEY ("' . implode('", "', $foreignKey->getColumns()) . '")';
        $def .= " REFERENCES {$this->quoteTableName($foreignKey->getReferencedTable()->getName())} (\"" . implode('", "', $foreignKey->getReferencedColumns()) . '")';
        if ($foreignKey->getOnDelete()) {
            $def .= " ON DELETE {$foreignKey->getOnDelete()}";
        }
        if ($foreignKey->getOnUpdate()) {
            $def .= " ON UPDATE {$foreignKey->getOnUpdate()}";
        }

        return $def;
    }
228763
public function foreignKey(string $foreignKeyName): ForeignKeyLocalColumnsDefiner
    {
        return new ForeignKeyLocalColumnsDefiner(function (
            array $localColumnNames,
            $referencedTable,
            array $referencedColumns,
            $onUpdateMode,
            $onDeleteMode
        ) use ($foreignKeyName) {
            $this->foreignKeys[] = new ForeignKey(
                $this->orm->getNamespace() . $foreignKeyName,
                $localColumnNames,
                $referencedTable,
                $referencedColumns,
                $onUpdateMode,
                $onDeleteMode
            );
        });
    }
599680
public function morphMany(
        $entity,
        string $related,
        string $name,
        string $type = null,
        string $id = null,
        string $localKey = null
    ): MorphMany {
        // Here we will gather up the morph type and ID for the relationship so that we
        // can properly query the intermediate table of a relation. Finally, we will
        // get the table and create the relationship instances for the developers.
        list($type, $id) = $this->getMorphs($name, $type, $id);

        $relatedMapper = Manager::getInstance()->mapper($related);

        $table = $relatedMapper->getEntityMap()->getTable();

        $localKey = $localKey ?: $this->getKeyName();

        // Add the relation to the definition in map
        list(, $caller) = debug_backtrace(false);
        $relation = $caller['function'];
        $this->relatedClasses[$relation] = $related;

        $this->addManyRelation($relation);
        $this->addForeignRelation($relation);

        return new MorphMany($relatedMapper, $entity, /*$table.'.'.*/$type, /*$table.'.'.*/$id, $localKey);
    }
873794
public static function normalizeLocaleAsParameter(Scope $scope, string $routeKey, $locale)
    {
        if (!is_array($locale)) {

            // You should provide the actual locale but in case the segment value is passed
            // we allow for this as well and normalize it to the expected locale value.
            if (!$scope->validateLocale($locale) && $scope->validateSegment($locale)) {
                $locale = $scope->findLocale($locale);
            }

            // Locale should be passed as second parameter but in case it is passed as array
            // alongside other parameters, we will try to extract it
            if ($scope->validateLocale($locale)) {
                $locale = [$routeKey => $scope->segment($locale)];
            }
        }

        return (array) $locale;
    }
739238
public function cascadeDelete(EntityInterface $entity, array $options = [])
    {
        if (!$this->getDependent()) {
            return true;
        }
        $foreignKey = (array)$this->getForeignKey();
        $bindingKey = (array)$this->getBindingKey();
        $conditions = [];

        if (!empty($bindingKey)) {
            $conditions = array_combine($foreignKey, $entity->extract($bindingKey));
        }

        $table = $this->junction();
        $hasMany = $this->getSource()->getAssociation($table->getAlias());
        if ($this->_cascadeCallbacks) {
            foreach ($hasMany->find('all')->where($conditions)->all()->toList() as $related) {
                $table->delete($related, $options);
            }

            return true;
        }

        $conditions = array_merge($conditions, $hasMany->getConditions());

        $table->deleteAll($conditions);

        return true;
    }
511693
protected function _morphTable($tableName, $definition, $foreignKeys, $dbAdapter)
    {
        $ignoreDropForeignKeys = array();
        /** @var \Phalcon\Db\Adapter $connection */
        $connection = $this->getDI()->get($dbAdapter);
        if ($dbAdapter === 'dbCassandra') {
            $schema = $connection->getDescriptor()['keyspace'];
        } elseif ($dbAdapter === 'dbPostgresql') {
            $schema = $connection->getDescriptor()['schema'];
        } else {
            $schema = $connection->getDescriptor()['dbname'];
        }

        $sql = array();
        $tableExists = $connection->tableExists($tableName, $schema);
        if (isset($definition['columns'])) {

            if (count($definition['columns']) == 0) {
                throw new Exception('Table must have at least one column');
            }

            $fields = array();
            foreach ($definition['columns'] as $tableColumn) {
                if (!is_object($tableColumn)) {
                    throw new Exception('Table must have at least one column');
                }
                $fields[$tableColumn->getName()] = $tableColumn;
            }

            if ($tableExists) {

                $localFields = array();
                $description = $connection->describeColumns($tableName, $schema);
                foreach ($description as $field) {
                    $localFields[$field->getName()] = $field;
                }

                foreach ($fields as $fieldName => $tableColumn) {
                    if ($dbAdapter === 'dbPostgresql') {
                        $schema = $connection->getDescriptor()['schema'];
                    }


                    if (!isset($localFields[$fieldName])) {
                        /**
                         * ADD COLUMN
                         */
                        $rawSql = $connection->getDialect()->addColumn($tableName, $tableColumn->getSchemaName(), $tableColumn);
                        $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                    } else {

                        /**
                         * ALTER TABLE
                         */
                        $changed = false;

                        if ($localFields[$fieldName]->getType() != $tableColumn->getType()) {
                            // If we are on MySQL DB, and the current column in DB is INT(1)
                            // and current annotation is "boolean", we don't notify change
                            // because when we save a boolean column in MySQL it's converted to INT(1)
                            // It prevents executing useless DB updates on each run
                            if ($dbAdapter !== 'dbMysql' || $localFields[$fieldName]->getType() !== \Phalcon\Db\Column::TYPE_INTEGER
                                || $localFields[$fieldName]->getSize() !== 1 || $tableColumn->getType() !== \Phalcon\Db\Column::TYPE_BOOLEAN
                            ) {
                                $changed = true;
                            }
                        }

                        if ($tableColumn->isNotNull() != $localFields[$fieldName]->isNotNull()) {
                            $changed = true;
                        }

                        if ($tableColumn->getSize() && $tableColumn->getSize() != $localFields[$fieldName]->getSize()) {
                            $changed = true;
                        }

                        if ($changed == true) {
                            $existingForeignKeys = [];

                            // We check if there is a foreign key constraint
                            if ($dbAdapter === 'dbMysql') {
                                $results = $connection->query("SELECT TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_SCHEMA,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA = '" . $connection->getDescriptor()['dbname'] . "' AND REFERENCED_TABLE_NAME = '" . $tableName . "' AND REFERENCED_COLUMN_NAME = '" . $tableColumn->getName() . "'");
                                foreach ($results->fetchAll() as $r) {
                                    $rules = $connection->query('SELECT UPDATE_RULE, DELETE_RULE FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_NAME="' . $r['CONSTRAINT_NAME'] . '" AND CONSTRAINT_SCHEMA ="' . $r['TABLE_SCHEMA'] . '"');
                                    $rules = $rules->fetch();
                                    $r['UPDATE_RULE'] = $rules['UPDATE_RULE'];
                                    $r['DELETE_RULE'] = $rules['DELETE_RULE'];

                                    /**
                                     * DROP FOREIGN KEY BECAUSE WE CHANGE THE CURRENT COLUMN
                                     */
                                    $rawSql = $connection->getDialect()->dropForeignKey($r['TABLE_NAME'], $r['TABLE_SCHEMA'], $r['CONSTRAINT_NAME']);
                                    $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                                    $existingForeignKeys[] = $r;
                                }
                            } elseif ($dbAdapter === 'dbPostgresql') {
                                $sqlconstraint = $this->getPGSQLConstraint($tableName, $tableColumn->getName());
                                $results = $connection->query($sqlconstraint);
                                foreach ($results->fetchAll() as $r) {

                                    $r['UPDATE_RULE'] = $r['on_update'];
                                    $r['DELETE_RULE'] = $r['on_delete'];
                                    $r['TABLE_NAME'] = $r['table_name'];
                                    $r['TABLE_SCHEMA'] = $r['constraint_schema'];
                                    $r['CONSTRAINT_NAME'] = $r['constraint_name'];
                                    $r['REFERENCED_TABLE_SCHEMA'] = $r['constraint_schema'];
                                    $r['REFERENCED_TABLE_NAME'] = $r['references_table'];
                                    $r['REFERENCED_COLUMN_NAME'] = $r['references_field'];
                                    $r['COLUMN_NAME'] = $r['column_name'];

                                    /**
                                     * DROP FOREIGN KEY BECAUSE WE CHANGE THE CURRENT COLUMN
                                     */
                                    $rawSql = $connection->getDialect()->dropForeignKey($r['TABLE_NAME'], $r['TABLE_SCHEMA'], $r['CONSTRAINT_NAME']);
                                    $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                                    $existingForeignKeys[] = $r;
                                }
                            }

                            /**
                             * ALTER TABLE
                             */
                            if ($dbAdapter === 'dbPostgresql') {
                                $rawSql = $connection->getDialect()->modifyColumn($tableName, $tableColumn->getSchemaName(), $tableColumn, $localFields[$fieldName]);
                            } else {
                                $rawSql = $connection->getDialect()->modifyColumn($tableName, $tableColumn->getSchemaName(), $tableColumn);
                            }
                            $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';

                            if ($existingForeignKeys) {
                                foreach ($existingForeignKeys as $r) {
                                    /**
                                     * ADD FOREIGN KEY AFTER DROP ONE (TO CHANGE IT)
                                     */
                                    $rawSql = $connection->getDialect()->addForeignKey(
                                        $r['TABLE_NAME'],
                                        $r['TABLE_SCHEMA'],
                                        new Reference(
                                            $r['CONSTRAINT_NAME'],
                                            array(
                                                "referencedSchema" => $r['REFERENCED_TABLE_SCHEMA'],
                                                "referencedTable" => $r['REFERENCED_TABLE_NAME'],
                                                "columns" => array($r['COLUMN_NAME']),
                                                "referencedColumns" => array($r['REFERENCED_COLUMN_NAME']),
                                                'onUpdate' => $r['UPDATE_RULE'],
                                                'onDelete' => $r['DELETE_RULE']
                                            )
                                        ));
                                    $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                                }
                            }
                        }
                    }
                }

                /**
                 * DROP COLUMN (and foreign key)
                 */
                foreach ($localFields as $fieldName => $localField) {
                    if (!isset($fields[$fieldName])) {
                        if ($dbAdapter === 'dbMysql') {
                            // We check if there is a foreign key constraint
                            $results = $connection->query("SELECT TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_SCHEMA,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA = '" . $schema . "' AND TABLE_NAME = '" . $tableName . "' AND COLUMN_NAME = '" . $fieldName . "'");
                            foreach ($results->fetchAll() as $r) {
                                $ignoreDropForeignKeys[] = $r['CONSTRAINT_NAME'];
                                $rawSql = $connection->getDialect()->dropForeignKey($r['TABLE_NAME'], $r['TABLE_SCHEMA'], $r['CONSTRAINT_NAME']);
                                $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                            }
                        } elseif ($dbAdapter === 'dbPostgresql') {
                            $sqlconstraint = $this->getPGSQLConstraint($tableName, $fieldName);
                            $results = $connection->query($sqlconstraint);
                            foreach ($results->fetchAll() as $r) {
                                $ignoreDropForeignKeys[] = $r['CONSTRAINT_NAME'];
                                $rawSql = $connection->getDialect()->dropForeignKey($r['table_name'], $r['constraint_schema'], $r['constraint_name']);
                                $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                            }
                        }
                        $rawSql = $connection->getDialect()->dropColumn($tableName, $schema, $fieldName);
                        $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                    }
                }
            } else {
                /**
                 * CREATE TABLE IF NOT EXISTS
                 */
                $rawSql = $connection->getDialect()->createTable($tableName, $schema, $definition);
                if ($dbAdapter === 'dbPostgresql') {
                    $sqlInstructions = explode(';', $rawSql);
                    foreach ($sqlInstructions as $instruction) {
                        if ($instruction !== "" && strpos($instruction, '_pkey" ON') === false) {
                            $sql[] = '$this->' . $dbAdapter . '->query(\'' . $instruction . '\');';
                        }
                    }
                } else {
                    $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                }

            }
        }

        /**
         * DROP FOREIGN KEY
         */
        if ($tableExists === true && ($dbAdapter === 'dbMysql' || $dbAdapter === 'dbPostgresql')) {
            $actualReferences = $connection->describeReferences($tableName, $schema);
            /* @var $actualReference \Phalcon\Db\Reference */
            foreach ($actualReferences as $actualReference) {
                $foreignKeyExists = false;

                for ($i = count($foreignKeys) - 1; $i >= 0; --$i) {
                    if ($dbAdapter === 'dbMysql') {
                        $rules = $connection->query('SELECT UPDATE_RULE, DELETE_RULE FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_NAME="' . $actualReference->getName() . '" AND CONSTRAINT_SCHEMA ="' . $actualReference->getReferencedSchema() . '"');
                        $rules = $rules->fetch();

                        if ($tableName === $foreignKeys[$i]['table']
                            && $actualReference->getReferencedTable() === $foreignKeys[$i]['referencedTable']
                            && count(array_diff($actualReference->getColumns(), $foreignKeys[$i]['fields'])) === 0
                            && count(array_diff($actualReference->getReferencedColumns(), $foreignKeys[$i]['referencedFields'])) === 0
                            // TODO : réactiver cette ligne si Phalcon prend en compte la méthode : && $actualReference->getOnUpdate() === $foreignKeys[$i]['action']
                            && $rules['UPDATE_RULE'] === $foreignKeys[$i]['action']
                            // TODO : réactiver cette ligne si Phalcon prend en compte la méthode : && $actualReference->getOnDelete() === $foreignKeys[$i]['action']) {
                            && $rules['DELETE_RULE'] === $foreignKeys[$i]['action']
                        ) {
                            $foreignKeyExists = true;
                            array_splice($foreignKeys, $i, 1);
                            break;
                        }
                    } else {
                        if ($tableName === $foreignKeys[$i]['table']
                            && $actualReference->getReferencedTable() === $foreignKeys[$i]['referencedTable']
                            && count(array_diff($actualReference->getColumns(), $foreignKeys[$i]['fields'])) === 0
                            && count(array_diff($actualReference->getReferencedColumns(), $foreignKeys[$i]['referencedFields'])) === 0
                        ) {
                            $foreignKeyExists = true;
                            array_splice($foreignKeys, $i, 1);
                            break;
                        }
                    }
                }

                if (!$foreignKeyExists && !in_array($actualReference->getName(), $ignoreDropForeignKeys)) {
                    $rawSql = $connection->getDialect()->dropForeignKey(
                        $tableName,
                        $actualReference->getReferencedSchema(),
                        $actualReference->getName()
                    );
                    $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                }
            }
        }

        /**
         * ADD FOREIGN KEY
         */
        if ($foreignKeys) {
            foreach ($foreignKeys as $foreignKey) {
                $rawSql = $connection->getDialect()->addForeignKey(
                    $tableName,
                    $connection->getDescriptor()['dbname'],
                    new Reference(
                        $foreignKey['name'],
                        array(
                            "referencedSchema" => $connection->getDescriptor()['dbname'],
                            "referencedTable" => $foreignKey['referencedTable'],
                            "columns" => $foreignKey['fields'],
                            "referencedColumns" => $foreignKey['referencedFields'],
                            'onUpdate' => $foreignKey['action'],
                            'onDelete' => $foreignKey['action']
                        )
                    ));
                $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
            }
        }

        /**
         * INDEXES
         */
        if (isset($definition['indexes'])) {
            if ($tableExists == true) {

                $indexes = array();
                foreach ($definition['indexes'] as $tableIndex) {
                    $indexes[$tableIndex->getName()] = $tableIndex;
                }

                if ($dbAdapter === 'dbPostgresql') {
                    $rawSql = $connection->getDialect()->modifyColumn($tableName, $tableColumn->getSchemaName(), $tableColumn, $localFields[$fieldName]);
                }

                $localIndexes = array();
                $actualIndexes = $connection->describeIndexes($tableName, $schema);
                foreach ($actualIndexes as $actualIndex) {
                    $deleted = true;

                    foreach ($definition['indexes'] as $tableIndex) {
                        // hack for encoging problem
                        $tableIndexName = $tableIndex->getName();
                        $actualIndexName = $actualIndex->getName();
                        if ($tableIndexName === $actualIndexName) {
                            $deleted = false;
                            $localIndexes[$actualIndex->getName()] = $actualIndex->getColumns();
                            break;
                        } elseif (substr($actualIndex->getName(), 0, 3) !== 'IDX' && ($dbAdapter !== 'dbCassandra') && ($dbAdapter !== 'dbPostgresql')) {
                            $deleted = false;
                            break;
                        }
                    }


                    if ($deleted) {
                        $rawSql = $connection->getDialect()->dropIndex($tableName, $tableColumn->getSchemaName(), $actualIndexName);
                        $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                    }
                }

                foreach ($definition['indexes'] as $tableIndex) {
                    $tableIndexName = $tableIndex->getName();
                    if (!isset($localIndexes[$tableIndexName])) {
                        if ($tableIndexName == 'PRIMARY') {
                            $rawSql = $connection->getDialect()->addPrimaryKey($tableName, $tableColumn->getSchemaName(), $tableIndex);
                            $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                        } else {
                            $rawSql = $connection->getDialect()->addIndex($tableName, $tableColumn->getSchemaName(), $tableIndex);
                            $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                        }
                    } else {
                        $changed = false;
                        if (count($tableIndex->getColumns()) != count($localIndexes[$tableIndexName])) {
                            $changed = true;
                        } else {
                            foreach ($tableIndex->getColumns() as $columnName) {
                                if (!in_array($columnName, $localIndexes[$tableIndexName])) {
                                    $changed = true;
                                    break;
                                }
                            }
                        }
                        if ($changed == true) {
                            if ($tableIndex->getName() == 'PRIMARY') {
                                $rawSql = $connection->getDialect()->dropPrimaryKey($tableName, $tableColumn->getSchemaName());
                                $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';

                                $rawSql = $connection->getDialect()->addPrimaryKey($tableName, $tableColumn->getSchemaName(), $tableIndex);
                                $sql[] = '$this->' . $dbAdapter . '->query(\'' . $rawSql . '\');';
                            }
                        }
                    }
                }
            }

        }

        return $sql;

    }
243829
protected function getRealtion($foreignTableName, $foreignColumn, $localColumn, $selfReferences)
    {
        $modelName = $this->getModelName($foreignTableName);
        $model = Helpers::guessModelFullName($modelName, Helpers::getModelsPath());

        $params = [
            $model,
            $foreignColumn,
            $localColumn,
        ];

        $relationName = ($selfReferences ? 'child_' : '');

        if ($this->isOneToMany($foreignTableName, $foreignColumn)) {
            return new ForeignRelationship('hasMany', $params, camel_case($relationName . Str::plural($foreignTableName)));
        }

        return new ForeignRelationship('hasOne', $params, camel_case($relationName . Str::singular($foreignTableName)));
    }
847844
@Override
    public String getMethodNameForReference(final ForeignKey foreignKey) {
        final Column c = foreignKey.getColumnReferences().get(0).getForeignKeyColumn();
        // check if only one-column fk
        if (foreignKey.getColumnReferences().size() == 1) {
            return getMethodNameForColumn(c) + getClassNameForTable(c.getReferencedColumn().getParent());
        }

        final StringBuilder nameBuilder = new StringBuilder();
        final List<String> words = new ArrayList<>(Arrays.asList(foreignKey.getName()
                .toLowerCase()
                .replaceAll("(^[0-9]+|[^a-z0-9_-])", "") // Delete every not-alphanumeric or _/- character and numbers at beginning
                .split("_")));
        words.removeAll(Arrays.asList("fk", "", null)); // removes FK_ prefix and empty entries
        final List<String> tableWords = new ArrayList<>(Arrays.asList(c.getParent().getName()
                .toLowerCase()
                .replaceAll("(^[0-9]+|[^a-z0-9_-])", "") // Delete every not-alphanumeric or _/- character and numbers at beginning
                .split("_")));
        words.removeAll(tableWords);
        nameBuilder.append(words.get(0));
        for (int i = 1; i < words.size(); i++) {
            String word = words.get(i);

            nameBuilder.append(word.substring(0, 1).toUpperCase());
            nameBuilder.append(word.substring(1));
        }
        return nameBuilder.toString();
    }
1256793
private function gatherChildrenData($entity, $parentLocalization, $filter = null, $levels = null, $count = false)
	{
		$input = $this->getRequestInput();
		$localeId = $this->getCurrentLocale()->getId();
		
		// @TODO: existing_only flag is used for LinkManager, when it requests for available pages for linking.
		// should split that onto two separate methods.
		$existingOnly = $input->filter('existing_only', false, false, FILTER_VALIDATE_BOOLEAN);

		$customTitleQuery = $input->get('query', false);

		$entityManager = $this->getEntityManager();
		$pageFinder = $entity === Page::CN() 
				? new PageFinder($entityManager)
				: new TemplateFinder($entityManager);

		// Reading by one level because need specific reading strategy for application pages
		if (empty($parentLocalization)) {
			$pageFinder->addLevelFilter(0, 0);
		} else {
			$rootNode = $parentLocalization->getMaster();
			$pageFinder->addFilterByParent($rootNode, 1, 1);
		}

		$queryBuilder = $pageFinder->getQueryBuilder();

		if ($existingOnly) {
			$queryBuilder->leftJoin('e.localizations', 'l_', 'WITH', 'l_.locale = :locale')
					->setParameter('locale', $localeId)
					->leftJoin('e.localizations', 'l')
					->andWhere('l_.id IS NOT NULL OR e INSTANCE OF ' . GroupPage::CN());
		} else {
			$queryBuilder->leftJoin('e.localizations', 'l_', 'WITH', 'l_.locale = :locale')
					->setParameter('locale', $localeId)
					->leftJoin('e.localizations', 'l')
					->andWhere('l_.id IS NOT NULL OR e.global = true OR (e.level = 0 AND e.global = false)');
		}

		if($customTitleQuery) {
			$queryBuilder->andWhere('l_.title LIKE :customTitleQuery');
			$queryBuilder->setParameter('customTitleQuery', $customTitleQuery . '%');
		}

		$filterFolders = array();
		$application = null;

		if ($parentLocalization instanceof ApplicationLocalization) {

			// This is bad solution for detecting where the sitemap has been requested from.
			// Should group by month if sitemap requested in the sidebar.
			//FIXME: JS should pass preference maybe
			if (empty($filter) && $existingOnly) {
				$filter = 'group';
			}

			$application = $this->getPageApplicationManager()
					->createApplicationFor($parentLocalization, $this->getEntityManager());

			$filterFolders = $application->getFilterFolders($queryBuilder, $filter);
			
			$application->applyFilters($queryBuilder, $filter);
		}

		$query = $queryBuilder->getQuery();

		if ($input->has('offset')) {
			$offset = $input->getInt('offset');
			$query->setFirstResult($offset);
		}

		if ($input->has('resultsPerRequest')) {
			$limit = $input->getInt('resultsPerRequest');
			$query->setMaxResults($limit);
		}

		$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($query, true);

		// TODO: fix, shouldn't return mixed result depending on arguments
		if ($count) {
			// When only the count is needed...
			$count = count($filterFolders) + count($paginator);

			return $count;
		} else {

			$response = array();

			// Prepend the filter folders
			$pages = array_merge($filterFolders, iterator_to_array($paginator));

			if ( ! is_null($levels)) {
				$levels --;
			}

			foreach ($filterFolders as $filterFolder) {
				if ( ! $filterFolder instanceof TemporaryGroupPage) {
					throw new \LogicException("Application " . get_class($application) . ' returned invalid filter folders');
				}
			}

			foreach ($pages as $page) {

				$pageData = $this->convertPageToArray($page, $localeId);

				// Skipping the page
				if (is_null($pageData)) {
					continue;
				}

				$pageData['children_count'] = 0;

				$localization = $page->getLocalization($localeId);

				if ( ! empty($localization)) {
					$filter = null;
					if ($page instanceof TemporaryGroupPage) {
						$filter = $page->getTitle();
						$localization = $parentLocalization;

						// TODO: for now it's enabled for all filter folders
						$pageData['childrenListStyle'] = 'scrollList';
						$pageData['selectable'] = false;
						$pageData['editable'] = false;
						$pageData['isDraggable'] = false;
						$pageData['isDropTarget'] = true;
						$pageData['new_children_first'] = true;
					}

					if ($levels === 0 && $page instanceof TemporaryGroupPage && $page->hasCalculatedNumberChildren()) {
						$pageData['children_count'] = $page->getNumberChildren();
					} elseif ($levels === 0) {
						$pageData['children_count'] = $this->gatherChildrenData($entity, $localization, $filter, $levels, true);
					} else {
						$pageData['children'] = $this->gatherChildrenData($entity, $localization, $filter, $levels, false);
						$pageData['children_count'] = count($pageData['children']);
					}

//					// TODO: might be job for JS
//					if ($pageData['children_count'] > 0
//							&& ! empty($pageData['icon'])
//							&& $pageData['icon'] === 'page') {
//
//						$pageData['icon'] = 'folder';
//					}
				}

				$response[] = $pageData;
			}

			return $response;
		}
	}