我需要一个PHP ORM才能很好地处理关系。 请在Zend中考虑以下代码:
$persons = new Persons();
$person = $persons->find(5)->current();
echo 'Name: '.$person->fullname;
$phones = $person->findDependentRowset('Phones');
foreach($phones as $phone)
echo 'Phone: '.$phone->phonenumber;
或xPDO中的代码:
$person = $xpdo->getObject('Persons', 5);
echo 'Name: '.$person->get('fullname');
$phones = $person->getMany('Phones');
foreach($phones as $phone)
echo 'Phone: '.$phone->get('phonenumber');
在两个脚本中,ORM执行两个查询,如下所示:
SELECT * FROM persons WHERE id=5;
SELECT * FROM phones WHERE person=5;
这意味着主要对象的一个查询和每个关系的一个查询,但我需要的是对主对象及其关系使用ONE查询! xPDO可以这样做:
$person = $xpdo->getObjectGraph('Persons', '{"Phones":{}}', 5);
echo 'Name: '.$person->get('fullname');
foreach($person->Phones as $phone)
echo 'Phone: '.$phone->get('phonenumber');
执行此查询:
SELECT * FROM persons
LEFT JOIN phones ON phones.person=persons.id
WHERE persons.id=5
这很棒但是无法设置从表中获取的字段! 这意味着在这种情况下xPDO使用“SELECT *”所以如果我得到一个对象及其4个关系,我将得到所有这些表的所有字段!
所以我需要一个ORM来执行下面的查询,例如上面的内容:
SELECT persons.fullname , phones.phonenumber FROM persons
LEFT JOIN phones ON phones.person=persons.id
WHERE persons.id=5
Doctrine可以通过DQL实现,但我认为Doctrine不适合个人项目。是否有任何PHP ORM来执行此操作?
由于 AHHP
答案 0 :(得分:3)
xPDO可以做到。你只需要调整你的想法和你的要求。
记住objectGraph使用对象的类名,其中图中的关系用于图和查询中。
$criteria = $this->xpdo->newQuery('prefixClient');
if (!empty($limit))
$criteria->limit($limit);
$criteria->where(array('Child.planid' => $this->getPrimaryKey(),
'Child.active' => true,
'GrandChild.someAttribute' => true,
'GreatGrandChild.someOtherAttribute' => true,
'suspended' => false
));
$out = $this->xpdo->getCollectionGraph('prefixClient', '{"Child":{"GrandChild":{"GreatGrandChild":{}}}}', $criteria);
您可以在关系的任何方面设置WHERE,包括在suspended =>中显示的当前对象假行。
我的书可能会帮助您建立您的架构和关系。对象在命名中应该总是单数,而它们的关系可以是复数(1:M)或单数(1:1)。
答案 1 :(得分:1)
哦,伙计,
我一直在吃这种狗粮大约2个月,我喜欢它。红豆。
嵌套bean,它是将一个对象作为另一个对象的属性的话。
http://www.redbeanphp.com/manual/nested_bean
整个文件非常小。适用于SQL。我正在一个大型项目中使用它,并喜欢我能多快完成任务。
约翰。
答案 2 :(得分:0)
Gacela可以通过多种方式自动获取相关信息:
1)继承关系
在以下示例中:
CREATE TABLE wizards (
wizardId INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
fname VARCHAR(255) NOT NULL,
lname VARCHAR(255) NOT NULL,
ROLE ENUM('teacher', 'student') NULL,
addressId INT UNSIGNED NULL,
CONSTRAINT fk_address_wizard
FOREIGN KEY (addressId)
REFERENCES addresses(addressId)
ON DELETE SET NULL
) ENGINE = Innodb;
CREATE TABLE students (
wizardId INT UNSIGNED NOT NULL PRIMARY KEY,
houseId INT UNSIGNED NOT NULL,
isDAMembmer BOOL NOT NULL DEFAULT 0,
CONSTRAINT fk_wizard_student
FOREIGN KEY (wizardId)
REFERENCES wizards(wizardId)
ON DELETE CASCADE,
CONSTRAINT fk_house_students
FOREIGN KEY (houseId)
REFERENCES houses(houseId)
ON DELETE RESTRICT
) ENGINE = Innodb;
students
表与wizards
表具有相同的主键,并且由于外键关系定义,Gacela将检测到students
继承
来自wizards
的所有字段。
2)依赖关系
这可能更接近你想要的东西:
CREATE TABLE addresses (
addressId INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
locationName VARCHAR(255) NOT NULL
) ENGINE = Innodb;
CREATE TABLE wizards (
wizardId INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
fname VARCHAR(255) NOT NULL,
lname VARCHAR(255) NOT NULL,
ROLE ENUM('teacher', 'student') NULL,
addressId INT UNSIGNED NULL,
CONSTRAINT fk_address_wizard
FOREIGN KEY (addressId)
REFERENCES addresses(addressId)
ON DELETE SET NULL
) ENGINE = Innodb;
但是,此示例与您的示例略有不同,因为addressId位于wizards
表中,因此创建了belongsTo关系,而不是hasMany,这是
你的例子反映了什么。
Gacela有第三种选择,但我首先建议你考虑一下,虽然急需获取数据通常比较好,但是会有真正的性能影响 总是急于获取而不是延迟加载数据。正是由于这个原因,Gacela(以及基本上所有其他Data Mapper或ORM)默认情况下并不急于从hasMany关系中获取数据。 也就是说,您可以编写如下内容:
class Mapper extends \Gacela\Mapper
{
public function find($id)
{
$query = $this->_source()->query();
$query->from('persons', array('fullName'))
->join('phones', 'phones.person=persons.id', array('phonenumber'), 'left')
->where('persons.id = :id', array(':id' => $id);
$data = $this->_source->query($query);
return $this->_load($data);
}
}