entityClass, $array->name); // Copy all fields. $this->type = $array->type; $this->table = $array->table; $this->foreignKeyName = $array->foreignKeyName; $this->foreignValueName = $array->foreignValueName; } /** * Get current table / foreign key / foreign value state. * @param string $fromTable Table from which to get values. * @return array{string, string, string} Table, Foreign key, Foreign value. */ public function getState(string $fromTable): array { return [ $table = $this->getTable() ?? "{$fromTable}_{$this->name}", $foreignKey = $this->getForeignKeyName() ?? "$table.".str_snake_singularize($fromTable)."_id", $foreignValue = $this->getForeignValueName() ?? "$table.".str_snake_singularize($this->name), ]; } /** * Extract a column name from a fully qualified name. * @return string The column name. */ private function getColumnName(string $fullyQualifiedName): string { return substr($fullyQualifiedName, strrpos($fullyQualifiedName, ".") + 1); } /** * Setup inline loading for the current array field in an entity query. * @param EntityQuery $baseQuery The entity query to alter. * @param string $prefix Prefix to add to the name of the properties. * @return Raw Generated select subquery. * @throws MissingConditionValueException */ public function genSelect(EntityQuery $baseQuery, string $prefix = ""): Raw { // Get all auto values for undefined tables or keys. [$table, $foreignKey, $foreignValue] = $this->getState($baseQuery->getTableName()); // Build subquery SELECT SQL. $sql = ((new SelectQuery($baseQuery->getDatabase(), $table)) ->select($foreignValue) ->whereColumn("{$baseQuery->getTableName()}.".$baseQuery->getPrimaryKeyName(), "=", $foreignKey))->build(); // Return the raw SELECT of a JSON array. return new Raw( "ARRAY_TO_JSON(ARRAY($sql->sql)) AS $prefix$this->name", $sql->bindings, ); } /** * @param Entity $entity Entity for which to save. * @param array $value Array to save. * @return void * @throws MissingConditionValueException * @throws UnknownDatabaseException * @throws NotCurrentTransactionException */ public function save(Entity $entity, array $value): void { // Start a transaction for the whole save. $transaction = $entity->getDatabase()->startTransaction(); // Get all auto values for undefined tables or keys. [$table, $foreignKey, $foreignValue] = $this->getState($entity->getTableName()); // Get entity primary key value. $entityKey = $entity->{array_first_or_val($entity->getPrimaryFields())}; // Delete existing values. ((new DeleteQuery($entity->getDatabase(), $table)) ->where($foreignKey, "=", $entityKey)) ->execute(); // Get actual columns names. $foreignKey = $this->getColumnName($foreignKey); $foreignValue = $this->getColumnName($foreignValue); // Insert new ones. ((new InsertQuery($entity->getDatabase(), $table))) // Insert all values of the array. ->values(...array_map(fn (mixed $val) => ([ $foreignKey => $entityKey, $foreignValue => $val, ]), $value)) ->execute(); // Commit transaction. $transaction->commit(); } }