Propel ORM:完全递归地为具有外键关系的通用模型对象提供水分,用于JSON序列化

时间:2011-03-04 01:01:53

标签: php mysql json propel

我是Propel ORM(以及一般的ORM)的新手,并试图在MySQL数据库中正确和干净地解决外键关系方面略微考虑一下。

从3个简单的MySQL表开始:

英雄:

  • ID
  • 名称
  • 描述

技能:

  • ID
  • 名称

hero_skill:

  • ID
  • hero_id
  • skill_id也

其中hero_skill具有预期的外键属性,并且生成所有Propel类。

在Propel中,我如何通过正确引用所有技能来完全“保湿”“英雄”物品

简单示例说明如何使用特定功能:

function getAllTheHeroes(){
    $query = PropelQuery::from("Hero")
    $heroes = $query->find();  //hero model objects
    foreach($heroes as $hero){
        $heroSkills = $hero->getHeroSkills();  //hero_skill model objects
        foreach($heroSkills as $heroSkill){  
            $skill = $heroSkill->getSkill();  //skill model object.
        }
        echo $hero->exportTo('JSON');  //export to JSON string (new in Propel 1.6)
    }      
}

因此,上面的代码获取所有英雄,迭代并获取hero_id的所有hero_skill记录的集合,然后迭代并获取skill_id的技能记录。重要的是它将所有这些已解析的关系打包为Hero对象的引用,因此对getWHATEVER()的调用将该对象与该数据“水合”,所有这一切使得当每个英雄被导出到JSON时,它有一个列表这个英雄的所有技能记录,而不仅仅是ids。这可以按预期工作,并且很好,因为你可以编写自定义函数来处理每种对象类型。这里的JSON类似于:

[{
"Id":1, 
"Name":"Hero McHeroington", 
"Description":"Awesome.", 
"HeroSkills":
{
    "HeroSkill_0":
    {
        "Id":1,
        "HeroId":1,
        "SkillId":2,
        "Skill":
            {
                "Id":2,
                "Name":"Interpretive Dance",
                "Rank":5
            }
    },
    "HeroSkill_1":
    {
        "Id":2,
        "HeroId":1,
        "SkillId":4,
        "Skill":
            {
                "Id":4,
                "Name":"Pottery",
                "Rank":2
            }
    },
    "HeroSkill_2":
    {
        "Id":3,
        "HeroId":1,
        "SkillId":5,
        "Skill":
            {
                "Id":5,
                "Name":"Walking",
                "Rank":1
            }
    }
}
 },{
"Id":2, 
"Name":"Squire McTinyPants",
"Description":"Chipper.", 
"HeroSkills":
{
    "HeroSkill_0":
    {
        "Id":4,
        "HeroId":2,
        "SkillId":2,
        "Skill":
            {
                "Id":2,
                "Name":"Interpretive Dance",
                "Rank":10
            }
    },
    "HeroSkill_1":
    {
        "Id":5,
        "HeroId":2,
        "SkillId":3,
        "Skill":
            {
                "Id":3,
                "Name":"Peeping",
                "Rank":6
            }
    },
    "HeroSkill_2":
    {
        "Id":6,
        "HeroId":2,
        "SkillId":6,
        "Skill":
            {
                "Id":6,
                "Name":"Skipping",
                "Rank":4
            }
    }
}
}]
Blah Blah。

我想做的是更通用的东西:

function getModel($byClassName){
    $pq = PropelQuery::from($byClassName)
    $recs = $pq->find();  // <- collection of records of unknown type
    foreach ($recs as $rec){
        //Somehow retrieve all of the 'getFOREIGNKEY' Propel generated helper functions and call them all in sequence, 
        // then iterate down into any of these logical children objects and repeat the process to fully resolve all Foreign Key relationships within this Object
        // and all this Objects 'children' 
        // AND not get stuck in infinite loops due to Many-To-Many relationships from the 'getWHATEVER' calls running in circles.


        //Or some other method entirely to accomplish the same thing that i am just not getting...

         echo $rec->exportTo('JSON');  //export to JSON string (new in Propel 1.6)
    }
}

我正在挖掘Propel Docs和Source,我仍然没有把头包裹在整个Peer / TableMap / RelationMap / etc模型中,而且我已经接近开箱即用的解决方案,但是继续打死路。

但这似乎不是一个非常独特的概念,我正试图在这里发生,所以我希望有一个Propel大师在这里可以快速指出我对此的迟钝。

谢谢!

编辑:(回应wimvds评论) 通用方法的目标是允许我在数据库级别配置关系,然后推进PHP类,并将它们用作对象,而不必担心底层数据存储。

使用特定方法,我必须在DB中定义这些关系,然后编写自定义“水合”功能(如上所列)以从数据存储中正确检索对象。这种方法的哲学问题是复制,因为如果我改变数据库中的关系,那么重新运行推进基因那么我还必须更新我的水合功能以反映结构的变化。似乎所有的部分都应该允许跳过最后一步并删除复制。

例如,上面有一个小的特定情况水合功能,我正在做的就是根据我头脑中的知识调用getWHATEVER()辅助函数,即hero_skill与英雄和技能相关,当我得到一个英雄我想检查hero_skill并获得相应的技能列表。由于外键,Propel也知道这些关系,并且当使用joinWith()时,它甚至意识到递归(将递归对象引用设置为'* RECURSION'的字符串值),因此这些部分都适用于Propel为了智能地自动保湿这些对象,同时优雅地解析/忽略递归,我只是找不到合适的语法来实现这一点。

ie:获取一个Object,解析它的FK关系,保存所有'子'对象(FK相关表中的行)并排除递归对象。

我想我正在寻找的是一种完全抽象数据存储区的方法,利用基于数据库schema.xml定义的Propel类生成能力,因此无需自定义编写一堆可能受到主题的辅助函数如果数据结构发生变化则更改。因此,允许我根据对象而不是数据库记录进行编码,这不是ORM的全部意义吗?

我希望澄清一下,谢谢!

1 个答案:

答案 0 :(得分:1)

我想您可以尝试使用 isCrossRef 表格来简化您的查询/补水。

请参阅:http://www.propelorm.org/wiki/Documentation/1.5/WhatsNew#Many-to-ManyRelationships