【问题标题】:PHP / Phalcon - Automatically nesting objectsPHP / Phalcon - 自动嵌套对象
【发布时间】:2014-11-25 10:39:35
【问题描述】:

假设我有三张桌子:

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 模型做到这一点? :)

【问题讨论】:

    标签: php 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);
    

    【讨论】:

    • 我还没有测试过(所以不被接受),但是谢谢 - 我认为这会非常非常有用! :)
    • 嗯,我们有这种代码,但是很慢。它为每个对象生成多个查询。因此,如果我想要一个具有嵌套关系的对象列表,它会变得歇斯底里地慢(300 个对象>1s)
    • @maddanio 是的,我记得我很久以前就向 Phalcon 团队提到过这一点。显然关系引用只能在逐个对象的基础上工作。
    【解决方案2】:

    在 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();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-20
      • 1970-01-01
      • 1970-01-01
      • 2021-09-10
      • 2012-04-10
      • 1970-01-01
      相关资源
      最近更新 更多