最早的时候,作为PHP程序员,如果你想获取一组相关的变量,最好的办法就是使用数组存储。在其它编程语言里,这个办法就显得不那么简单了。他们拥有多种数据结构可以选择,每个都在存储,速度和语法上有些区别。PHP这门语言则将这些选择统统抹掉,并且只给程序员最有用的数据结构来完成这项任务。
不过PHP5已经通过内置的类和接口,视图改变这种情况,允许程序员创建自己的数据结构。
$array = new ArrayObject();
class MyCollection extends ArrayObject{…}
$collection = new MyCollection();
$collection[] = ‘bar';
之后这段对于译者来说有点难度,为了不误导大家,直接上英文。
While this is still galling to a certain type of software developer, as you don’t have access to low level implementation details, you do have the ability to create array-like Objects with methods that encapsulate specific functionality. You can also setup rules to offer a level of type safety by only allowing certain kinds of Objects into your Collection.
It should come as no surprise that Magento offers you a number of these Collections. In fact, every Model object that follows the Magento interfaces gets a Collection type for free. Understanding how these Collections work is a key part to being an effective Magento programmer. We’re going to take a look at Magento Collections, starting from the bottom and working our way up. Setup a controller action where you can run arbitrary code, and let’s get started.
数据收集
首先,我们实例化Varien_Object()类,创建一些新的对象。
$thing_1 = new Varien_Object();
$thing_1->setName('Richard');
$thing_1->setAge(24);
$thing_2 = new Varien_Object();
$thing_2->setName('Jane');
$thing_2->setAge(12);
$thing_3 = new Varien_Object();
$thing_3->setName('Spot');
$thing_3->setLastName('The Dog');
$thing_3->setAge(7);
所有的Magento模型都继承自Varien_Object()类。这在面向对象架构中是一个常用的设计模式,你可以轻易的添加新的方法或功能到任意一个对象,而不用修改类文件。
任何继承自Varien_Object()类的对象都拥有getter和setter魔术方法,可以方便的用来设置属性值。试下下面这段代码,
var_dump($thing_1->getName());
如果你还不晓得该获取什么属性,例如上面的getName()中的Name,也可以直接读取所有的数据到一个数组中
var_dump($thing_3->;getData());
上面这段代码会返回类似下面的一个数组,
array
'name' => string 'Spot' (length=4)
'last_name' => string 'The Dog' (length=7)
'age' => int 7
注意下名为“last_name”的属性,如果属性名中包含有下划线,你必须以驼峰命名的方式才能使用getter和setter魔术方法调用它。
$thing_1->setLastName('Smith');
在Magento的最新版本中,你也可以使用数组的形式来读取该属性。
var_dump($thing_3["last_name"]);
获取一些对象之后,我们给他们添加收集(Collection)。收集像数组一样,但它由PHP程序员定义。
$collection_of_things = new Varien_Data_Collection();
$collection_of_things
->addItem($thing_1)
->addItem($thing_2)
->addItem($thing_3);
绝大部分Magento数据收集继承自Varien_Data_Collection()类。任何集成自该类的方法都能够使用它的方法。(我觉得这句是废话)。
数据收集可以做些什么呢?首先,我们可以使用foreach语句循环数据
foreach($collection_of_things as $thing) {
var_dump($thing->getData());
}
还有两个方法,分别可以获取第一个和最后一个数据,
var_dump($collection_of_things->getFirstItem());
var_dump($collection_of_things->getLastItem()->getData());
当然还可以输出为XML格式~~
var_dump( $collection_of_things->toXml() );
只获取单独的一个字段,
var_dump($collection_of_things->getColumnValues('name'));
Magento团队同样提供了一些基础的过滤方法,
var_dump($collection_of_things->getItemsByColumnValue('name','Spot'));
模型收集
这些可能很有意思,但是为什么我们需要关注它呢?这是因为Magento内置的数据收集都继承自该类。也就是说,对于产品收集(或者分类收集),你可以使用同样的方法。看下下例
public function testAction() {
$collection_of_products = Mage::getModel('catalog/product')->getCollection();
var_dump($collection_of_products->getFirstItem()->getData()); }
Magento模型对象多数拥有getCollection()方法,默认的,它返回系统中和该对象同类型的对象的收集。Most Magento Model objects have a method named getCollection which will return a collection that, by default, is initialized to return every Object of that type in the system.
产品收集,以及Magento中其他的收集,还同样继承自Varien_Data_Collection_Db类。该类同样提供了很多有用的方法。例如,如果你想查看某个收集使用的select查询语句,
public function testAction() {
$collection_of_products = Mage::getModel('catalog/product')->getCollection();
var_dump($collection_of_products->getSelect());
}
上面一段代码会输入如下内容
object(Varien_Db_Select)[94]
protected ‘_bind’ =>
array
empty
protected ‘_adapter’ =>
…
因为Magento使用的是Zend的数据库抽象层,Select查询语句是个对象。让我们将其转换为字符串,
public function testAction() {
$collection_of_products = Mage::getModel('catalog/product')->getCollection();
var_dump((string)$collection_of_products->getSelect());
}
这段代码可能会返回一个简单的select语句
‘SELECT `e`.* FROM `catalog_product_entity` AS `e`’
有时候也会返回更复杂的语句
string ‘SELECT `e`.*, `price_index`.`price`, `price_index`.`final_price`, IF(`price_index`.`tier_price`, LEAST(`price_index`.`min_price`, `price_index`.`tier_price`), `price_index`.`min_price`) AS `minimal_price`, `price_index`.`min_price`, `price_index`.`max_price`, `price_index`.`tier_price` FROM `catalog_product_entity` AS `e` INNER JOIN `catalog_product_index_price` AS `price_index` ON price_index.entity_id = e.entity_id AND price_index.website_id = ‘1’ AND price_index.customer_group_id = 0′
这些不同取决于你选择的属性,还有就是前面提到过的索引和缓存。如果你看过这个系列的教程,你知道很多Magento模型使用的是EAV模型。默认情况下,EAV收集不会包含所有的对象属性。可以通过addAttributeToSelect()方法添加选取的属性。
$collection_of_products = Mage::getModel('catalog/product') ->getCollection() ->addAttributeToSelect('*');
或者,可以只添加一个属性,
$collection_of_products = Mage::getModel('catalog/product') ->getCollection() ->addAttributeToSelect('meta_title');
还可以直接以链接的方式选择多个属性
$collection_of_products = Mage::getModel('catalog/product') ->getCollection() ->addAttributeToSelect('meta_title') ->addAttributeToSelect('price');
数据库延迟加载
刚接触Magento ORM系统的程序员对于Magento数据库的调用问题会非常头疼。当使用纯SQL语句或者普通的ORM系统时,SQL语句会在对象实例化之后立刻被调用。
$model = new Customer();
//sql语句调用
echo 'Done'; //执行结束
Magento的运行方式于此不同,延迟加载的概念被应用于Magento数据库调用中。简单来说,延迟加载是SQL不会被立刻执行,知道客户端程序员需要调用该数据时。例如,当编写如下代码时,
$collection_of_products = Mage::getModel('catalog/product')->getCollection();
Magento实际上并未运行任何的数据库操作,你仍然可以继续添加需要select的属性,
$collection_of_products = Mage::getModel('catalog/product')-getCollection();
//其他操作
$collection_of_products->addAttributeToSelect('meta_title');
并且,Magento同样不会在添加一个新的属性之后运行任何数据库查询。即在你试图在收集中尝试读取内容之前,数据库不会进行任何查询。
过滤数据库收集
在数据库收集中最重要的方法就应该是addFieldToFilter()了。该方法将where字句添加到查询语句当中,一起看下下面的这段代码(将参数二替换为你产品中的sku)
public function testAction() {
$collection_of_products = Mage::getModel('catalog/product')->getCollection();
$collection_of_products->addFieldToFilter('sku', '你的产品sku');
//除此之外,还可以将收集传递个count()函数,计算select的数目
echo "该收集包含" . count($collection_of_products) . '个记录';
var_dump($collection_of_products->getFirstItem()->getData());
addFieldToFilter()方法的参数一是你希望过滤的属性,参数二是该属性的值。对于参数二,还可以指定为过滤的类型。下面看下使用该方法进行的稍微复杂的过滤。
上面说过,下面这段代码,相当于数据库中的where字句“WHERE sku = ‘xxx’”
$collection_of_products->addFieldToFilter('sku', 'xxx');
不相信?哈哈,下面这段代码可以直接输出该收集的查询语句,
public function testAction() {
var_dump( (string)
Mage::getModel('catalog/product')->getCollection() ->addFieldToFilter('sku', 'xxx')->getSelect()
);
}
输出如下,
SELECT `e`.* FROM `catalog_product_entity` AS `e` WHERE (e.sku = ‘xxx’)
必须谨记于心的是,这在使用EAV属性的时候,这些很快就会变的非常复杂,例如选择所有属性,
var_dump( (string)
Mage::getModel('catalog/product')->getCollection() ->addAttributeToSelect('*')->addFieldToFilter('sku', 'xxx') ->getSelect()
)
输出的将会是如下比较庞大的查询语句,
SELECT `e`.*, IF(_table_meta_title.value_id>0, _table_meta_title.value, _table_meta_title_default.value) AS `meta_title` FROM `catalog_product_entity` AS `e` INNER JOIN `catalog_product_entity_varchar` AS `_table_meta_title_default` ON (_table_meta_title_default.entity_id = e.entity_id) AND (_table_meta_title_default.attribute_id=’103′)
AND _table_meta_title_default.store_id=0
LEFT JOIN `catalog_product_entity_varchar` AS `_table_meta_title` ON (_table_meta_title.entity_id = e.entity_id) AND (_table_meta_title.attribute_id=’103′)
AND (_table_meta_title.store_id=’1′)
WHERE (IF(_table_meta_title.value_id>0, _table_meta_title.value, _table_meta_title_default.value) = ‘my title’)
addFieldToFilter()方法提供的更多查询子句