在我们开始介绍数据操作前,我们先介绍一个神兵利器—Varien Data Collections。在最早的时候我们写php通常用Array来做数据收集器,这个小东西可发挥了大作用,要知道如果你想在其他语言中实现Array有多么难过。 例如c、c++。
在php5中,更是发扬了Array,php内置了一些类和接口,允许你创建你自己的数据结构。Magento充分利用了这一点,在使用 Varien_Data_Collection来做数据收集的时候,它实现了php内置IteratorAggregate对象迭代器和 Countable两个接口。下面是用php内置类ArrayObject的一个例子。
$array = new ArrayObject(); class MyCollection extends ArrayObject{} $collection = new MyCollection(); $collection[] = 'bar';
适合对象:高级开发者
作者:精东
最后修改时间:2010年5月31日
版本:V 0.1.0
在Magento代码中,其实每个Model都有个Collection。了解这些数据收集器是如何工作的是你成为一个真正Magento开发人员的关键点。
下面让我们开始吧,前面我们创建过一个Helloworld模块,现在我们继续用他开始我们接下来的学习。
创建一个数据收集器首先,我们创造一些新的对象。
$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);
在继承Varien_Object的类中,有两个魔术方法,get/set,你可以很方便的向对象中加入一个属性(值),让我们看个例子。
var_dump($thing_1->getName());
var_dump($thing_3->getData());
array 'name' => string 'Spot' (length=4) 'last_name' => string 'The Dog' (length=7) 'age' => int 7
$thing_1->setLastName('Smith');
var_dump($thing_3["last_name"]);
现在然我们把这些对象加到数据收集器Varien_Data_Collection中。很多程序员将Collection看成是数组,当然我不反对。
$collection_of_things = new Varien_Data_Collection(); $collection_of_things ->addItem($thing_1) ->addItem($thing_2) ->addItem($thing_3);
那么我们可以做些什么呢?接下来我们使用foreach去循环它。
foreach($collection_of_things as $thing) { var_dump($thing->getData()); }
var_dump($collection_of_things->getFirstItem()); var_dump($collection_of_things->getLastItem()->getData());
var_dump( $collection_of_things->toXml() );
var_dump($collection_of_things->getColumnValues('name'));
var_dump($collection_of_things->getItemsByColumnValue('name','Spot'));
模型数据收集器(Model Collections)
前面我们有提到,所有Magento的模型数据收集器都继承Varien_Data_Collectionm,所以理论上我们可以使用之前的所有方法。下面让我们以product模型实战下。
public function testAction() { $collection_of_products = Mage::getModel('catalog/product')->getCollection(); var_dump($collection_of_products->getFirstItem()->getData()); }
Magento的数据收集器Collection包含很多复杂的逻辑来处理数据,无论是否使用索引或缓存、EAV表等。
上面的产品数据收集器,它里面还有Varien_Data_Collection_Db类。这个类给你很多有用的方法,例如如果你向看sql的select语句。
public function testAction() { $collection_of_products = Mage::getModel('catalog/product')->getCollection(); var_dump($collection_of_products->getSelect()); //might cause a segmentation fault }
object(Varien_Db_Select)[94] protected '_bind' => array empty protected '_adapter' => ...
public function testAction() { $collection_of_products = Mage::getModel('catalog/product')->getCollection(); //var_dump($collection_of_products->getSelect()); //might cause a segmentation fault var_dump( (string) $collection_of_products->getSelect() ); }
'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'
$collection_of_products = Mage::getModel('catalog/product') ->getCollection() ->addAttributeToSelect('*'); //the asterisk is like a SQL SELECT *
//or just one $collection_of_products = Mage::getModel('catalog/product') ->getCollection() ->addAttributeToSelect('meta_title');
//or just one $collection_of_products = Mage::getModel('catalog/product') ->getCollection() ->addAttributeToSelect('meta_title') ->addAttributeToSelect('price');
延迟加载(Lazy Loading)
一般情况下,我们在创建sql后需要立刻执行,从而获取数据,例如。
$model = new Customer(); //SQL Calls being made to Populate the Object echo 'Done'; //execution continues
$collection_of_products = Mage::getModel('catalog/product') ->getCollection();
$collection_of_products = Mage::getModel('catalog/product') ->getCollection(); $collection_of_products->addAttributeToSelect('meta_title');
Magento对数据库连接层做了良好的封装,当然它也考虑到了效率问题。在一般情况下,你没必要去担心sql后台是怎么执行的,只需要专心做你的功能,例如区块、布局等。这是Magento非常优秀的地方。
过滤数据(Filtering Database Collections)
最重要的一个方法是addFieldToFilter。通过这个方法可以添加我们sql中的WHERE语句。
public function testAction() { $collection_of_products = Mage::getModel('catalog/product') ->getCollection(); $collection_of_products->addFieldToFilter('sku','n2610');//another neat thing about collections is you can pass them into the count //function. More PHP5 powered goodness echo "Our collection now has " . count($collection_of_products) . ' item(s)'; var_dump($collection_of_products->getFirstItem()->getData());
}
第二个参数也可以被用来指定某一类型的数据。稍微有些复杂,我们继续往下看。
$collection_of_products->addFieldToFilter('sku','n2610');
WHERE sku = "n2610"
public function testAction() { var_dump( (string) Mage::getModel('catalog/product') ->getCollection() ->addFieldToFilter('sku','n2610') ->getSelect()); }
SELECT `e`.* FROM `catalog_product_entity` AS `e` WHERE (e.sku = 'n2610')'
var_dump( (string) Mage::getModel('catalog/product') ->getCollection() ->addAttributeToSelect('*') ->addFieldToFilter('meta_title','my title') ->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')
其它比较运算符
我确定在刚刚的练习中,你想知道如何实现一个不是“=”的where条件句,例如不等于、大于、小于。刚刚我们有讲过addFieldToFilter的第二个参数允许传入不同“类型”。
其实很简单,只要将一个简单的数组作为第二个参数传入addFieldToFilter方法就可以变换条件句。
数组的键就是“类型”,关联的值就是你想过滤的值。我们改写下上面的代码。
public function testAction() { var_dump( (string) Mage::getModel('catalog/product') ->getCollection() ->addFieldToFilter('sku',array('eq'=>'n2610')) ->getSelect() ); }
addFieldToFilter('sku',array('eq'=>'n2610'))
Magento在这个函数中有一系列英语的缩写,这些词的资料可以参考《tear of remembrance》。这些沿用了Perl语言中的一些比较运算符号。
在这里我将Magento所有的条件判断符号列出来供大家参考。
array("eq"=>'n2610') WHERE (e.sku = 'n2610')array(“neq”=>'n2610')
WHERE (e.sku != 'n2610')array(“like”=>'n2610')
WHERE (e.sku like 'n2610')array(“nlike”=>'n2610')
WHERE (e.sku not like 'n2610')array(“is”=>'n2610')
WHERE (e.sku is 'n2610')array(“in”=>array('n2610'))
WHERE (e.sku in ('n2610'))array(“nin”=>array('n2610'))
WHERE (e.sku not in ('n2610'))array(“notnull”=>'n2610')
WHERE (e.sku is NOT NULL)array(“null”=>'n2610')
WHERE (e.sku is NULL)array(“gt”=>'n2610')
WHERE (e.sku > 'n2610')array(“lt”=>'n2610')
WHERE (e.sku < 'n2610')array(“gteq”=>'n2610')
WHERE (e.sku >= 'n2610')array(“moreq”=>'n2610') //a weird, second way to do greater than equal
WHERE (e.sku >= 'n2610')array(“lteq”=>'n2610')
WHERE (e.sku <= 'n2610')array(“finset”=>array('n2610'))
WHERE (find_in_set('n2610',e.sku))array('from'=>'10','to'=>'20')
WHERE e.sku >= '10' and e.sku <= '20'
in, nin, find_in_set
in
and nin
条件句中,语序你传入一个数组作为值。例如:
array("in"=>array('n2610','ABC123') WHERE (e.sku in ('n2610','ABC123'))
notnull, null
关键字NULL是最特殊的sql句,它将忽略你传入的值。
array("notnull"=>'n2610') WHERE (e.sku is NOT NULL)
from – to 过滤
这是另一种过滤方式,在传入的数组中,允许你传入两个键,是从哪里到哪里的意思,一个数值区间。
public function testAction { var_dump( (string) Mage::getModel('catalog/product') ->getCollection() ->addFieldToFilter('price',array('from'=>'10','to'=>'20')) ->getSelect() ); }
WHERE (_table_price.value >= '10' AND _table_price.value <= '20')
AND 或者 OR
根据刚才讲的内容,你可以知道,通过多个 addFieldToFilter
方法可以获得一个”AND”的条件句。
function testAction() { echo( (string) Mage::getModel('catalog/product') ->getCollection() ->addFieldToFilter('sku',array('like'=>'a%')) ->addFieldToFilter('sku',array('like'=>'b%')) ->getSelect() ); }
WHERE (e.sku LIKE 'a%') AND (e.sku LIKE 'b%')
如果你希望构造一个or的语句,首先我们构造两个参数。
public function testAction() { $filter_a = array('like'=>'a%'); $filter_b = array('like'=>'b%'); }
public function testAction() { $filter_a = array('like'=>'a%'); $filter_b = array('like'=>'b%'); echo( (string) Mage::getModel('catalog/product') ->getCollection() ->addFieldToFilter('sku',array($filter_a,$filter_b)) ->getSelect() ); }
WHERE (((e.sku LIKE 'a%') OR (e.sku LIKE 'b%')))
总结
恭喜你,你现在已经是一个很不错的Magento开发者了!因为你不需要写任何sql语句,就可以获取几乎所有模型的所有你想要的数据。