PHP / Phalcon - Автоматическое вложение объектов
Скажем, у меня есть три таблицы:
CREATE TABLE divisions {
idDivision INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR (40) NOT NULL
}
CREATE TABLE clubs {
idClub INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
idDivision INT NOT NULL,
name VARCHAR(40) NOT NULL
}
CREATE TABLE footballers (
idFootballer INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
idClub INT NOT NULL,
name VARCHAR (40) NOT NULL
)
И у меня есть несколько прекрасных моделей Phalcon, чтобы представлять их.
Теперь, что я хотел бы сделать, это сделать это:
$divisions = new Divisions();
print json_encode($divisions::findFirst(), JSON_NUMERIC_CHECK);
И это возвращает объект JSON что-то вроде:
{
idDivision: 1,
name: "Welsh Premier League",
clubs: [
{
idClub: 1,
idDivision: 1,
name: "Airbus UK",
players: [
{
idPlayer: 1,
idClub: 1,
name: "Alf Jones"
},
...
]
},
..
]
}
Есть ли простой способ сделать это с моделью Phalcon?:)
1 ответ
Решение
Чтобы получить вложенные модели автоматически используйте эту рекурсивную функцию.
$getRelations = function($model, $namespace, $alias = null, $instances = null) use (&$getRelations)
{
$modelsManager = $model->getModelsManager();
$relations = $modelsManager->getRelations($namespace);
if (is_null($instances)) {
$response = $model->toArray();
}
if (count($relations)) {
// loop relations
foreach ($relations as $i => $relation) {
$options = $relation->getOptions();
// get alias
if (isset($options['alias'])) {
$subAlias = $options['alias'];
$modelName = $relation->getReferencedModel();
$subModel = new $modelName();
// get from model
if (is_null($alias) && count($model->{$subAlias})) {
$response[$subAlias] = $getRelations(
$subModel, $modelName, $subAlias, $model->{$subAlias}
);
// get from object instance
} elseif (count($instances)) {
foreach ($instances as $k => $instance) {
$response[$k] = $instance->toArray();
$response[$k][$subAlias] = $getRelations(
$subModel, $modelName, $subAlias, $instance->{$subAlias}
);
}
}
}
}
} else {
$response = $instances->toArray();
}
return $response;
};
Вы можете назвать это так:
$model = new Division::findFirst($divisionId);
$namespace = 'AppName\Models\Division';
$data = $getRelations($model, $namespace);
$this->response->setJsonContent($data);
Убедитесь, что вы определили псевдоним для каждой вложенной модели следующим образом:
class Division extends \Phalcon\Mvc\Model
{
public function initialize()
{
$this->hasMany('id', 'AppName\Models\Club', 'division_id', array(
'alias' => 'clubs'
));
}
}
ОБНОВИТЬ
Вместо этого используйте приведенный ниже код (поместите его в базовую модель). Этот новый код позволит вам получить отношения по новой (пустой) модели.
public function getModelName()
{
return get_called_class();
}
public function toArray($columns = null, $isRelated = false)
{
return !$isRelated ? parent::toArray($columns) : $this->_toArrayRelations();
}
private function _toArrayRelations()
{
$getRelations = function($model, $instances = null) use (&$getRelations)
{
$hasInstances = count($instances);
$modelsManager = $model->getModelsManager();
$relations = $modelsManager->getRelations($model->getModelName());
if (!$hasInstances) {
$response = $model->toArray();
}
if (count($relations)) {
// loop relations
foreach ($relations as $i => $relation) {
$options = $relation->getOptions();
// get alias
if (isset($options['alias'])) {
$subAlias = $options['alias'];
$modelName = $relation->getReferencedModel();
$subModel = new $modelName();
$subModelRelation = $model->{$subAlias};
// get from model
if (!$hasInstances) {
$response[$subAlias] = $getRelations(
$subModel, $subModelRelation
);
// get from object instance
} else {
foreach ($instances as $k => $instance) {
$response[$k] = $instance->toArray();
$response[$k][$subAlias] = $getRelations(
$subModel, $instance->{$subAlias}
);
}
}
}
}
} elseif ($hasInstances) {
foreach ($instances as $k => $instance) {
$response[$k] = $instance->toArray();
}
}
return $response;
};
return $getRelations($this);
}
Также проще звонить с контроллера.
$model = new Division::findFirst($divisionId);
$data = $model->toArray(null, 1);
$this->response->setJsonContent($data);
В Phalcon вы можете определить связь между моделями внутри самой модели. Пример:
class FirstModel extends \Phalcon\Mvc\Model
{
public function initialization()
{
$this->hasMany('field', SecondModel::class, 'referenceField', [options]);
}
}
class SecondModel extends \Phalcon\Mvc\Model
{
public function initialization()
{
$this->hasMany('field', ThirdModel::class, 'referenceField', [options]);
}
}
class ThirdModel extends \Phalcon\Mvc\Model
{
// ... some code
}
В заключение:
$results = FirstModel::find();