/** * Builds a Table object using a Php class definition * * This takes care of excluded properties, so buildLinkTable() should be called * before buildClassTable(). * * @param $class Reflection_Class * @param $more_field Column * @return Table */ private function buildClassTable(Reflection_Class $class, $more_field) { $table_name = Dao::current()->storeNameOf($class->name); $table = new Table($table_name); if (!in_array('id', $this->excluded_properties)) { $table->addColumn(Column::buildId()); } if ($more_field) { $table->addColumn($more_field); } if ($class->isAbstract()) { $table->addColumn(new Column('class', 'varchar(255)')); } else { foreach ($class->accessProperties() as $property) { if (!in_array($property->name, $this->excluded_properties)) { $type = $property->getType(); if (($type->isMultipleString() || !$type->isMultiple()) && !$property->isStatic()) { $table->addColumn(Column::buildProperty($property)); if ($property->getAnnotation('link')->value == Link_Annotation::OBJECT && $property->getAnnotation('store')->value != 'string') { $class_name = $property->getType()->asString(); $this->dependencies_context[$class_name] = $class_name; $table->addForeignKey(Foreign_Key::buildProperty($table_name, $property)); $table->addIndex(Index::buildLink($property->getAnnotation('storage')->value)); } } } } } return $table; }
/** * Builds a Table or Table[] taken from database, using a mysqli connection * * @param $mysqli mysqli * @param $table_name string * @param $database_name string * @return Table|Table[] will be a single table only if $table_name is a * single table name without jokers characters */ public static function build(mysqli $mysqli, $table_name = null, $database_name = null) { $tables = []; $result = $mysqli->query('SHOW TABLE STATUS' . (isset($database_name) ? ' IN ' . DQ . $database_name . DQ : '') . (isset($table_name) ? ' LIKE ' . DQ . $table_name . DQ : '')); /** @var $table Table */ while ($table = $result->fetch_object(Table::class)) { foreach (Column::buildTable($mysqli, $table->getName(), $database_name) as $column) { $table->addColumn($column); } foreach (Foreign_Key::buildTable($mysqli, $table->getName(), $database_name) as $foreign_key) { $table->addForeignKey($foreign_key); } $tables[] = $table; } $result->free(); $unique = isset($table_name) && strpos($table_name, '%') === false; return $unique ? reset($tables) : $tables; }
/** * Create a table in database, which has no associated class, using fields names * * @param $mysqli mysqli * @param $table_name string * @param $column_names string[] * @return boolean * @todo mysqli context should contain sql builder (ie Select) in order to know if this was * an implicit link table. If then : only one unique index should be built */ private function createImplicitTable(mysqli $mysqli, $table_name, $column_names) { $only_ids = true; $table = new Table($table_name); $ids_index = new Index(); $ids_index->setType(Index::UNIQUE); $indexes = []; foreach ($column_names as $column_name) { $table->addColumn($column_name === 'id' ? Column::buildId() : Column::buildLink($column_name)); if (substr($column_name, 0, 3) === 'id_') { if ($mysqli instanceof Contextual_Mysqli && is_array($mysqli->context)) { $ids_index->addKey($column_name); $index = Index::buildLink($column_name); foreach ($mysqli->context as $context_class) { $id_context_property = 'id_' . Names::classToProperty(Names::setToSingle(Dao::storeNameOf($context_class))); $id_context_property_2 = 'id_' . Names::classToProperty(Names::setToSingle(Namespaces::shortClassName($context_class))); if (in_array($column_name, [$id_context_property, $id_context_property_2])) { $table->addForeignKey(Foreign_Key::buildLink($table_name, $column_name, $context_class)); break; } } $indexes[] = $index; } } else { $only_ids = false; } } if ($only_ids) { $table->addIndex($ids_index); } else { foreach ($indexes as $index) { $table->addIndex($index); } } $mysqli->query((new Create_Table($table))->build()); return true; }
/** * Replace all references to $replaced by references to $replacement into the database. * Already loaded objects will not be changed. * * @param $replaced object * @param $replacement object * @return boolean true if replacement has been done, false if something went wrong */ public function replaceReferences($replaced, $replacement) { $table_name = $this->storeNameOf(get_class($replaced)); $replaced_id = $this->getObjectIdentifier($replaced); $replacement_id = $this->getObjectIdentifier($replacement); if ($replaced_id && $replacement_id && $table_name) { foreach (Foreign_Key::buildReferences($this->connection, $table_name) as $foreign_key) { $foreign_table_name = lParse($foreign_key->getConstraint(), DOT); $foreign_field_name = $foreign_key->getFields()[0]; $query = 'UPDATE ' . BQ . $foreign_table_name . BQ . LF . 'SET ' . BQ . $foreign_field_name . BQ . ' = ' . $replacement_id . LF . 'WHERE ' . BQ . $foreign_field_name . BQ . ' = ' . $replaced_id; $this->query($query); if ($this->connection->last_errno) { $error = true; } } return isset($error) ? false : true; } return false; }
/** * @param $foreign_key Foreign_Key */ public function addForeignKey(Foreign_Key $foreign_key) { $this->foreign_keys[$foreign_key->getConstraint()] = $foreign_key; }