深入理解Magento-第十章-数据操作数据收集器
在我們開始介紹數據操作前,我們先介紹一個神兵利器—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';在接下來的文章中,我認為你已經了解ArrayObject、IteratorAggregate、Countable。如果還是很陌生,我建議你先閱讀這篇文章PHP5對象迭代(Object Iteration)。當然你不必了解很底層的東西,你只需要知道如何用就可以了。
適合對象:高級開發者
作者:精東
最后修改時間: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);Magento中所有的Model都繼承Varien_Object,在面向對象編程中,這樣做的好處是當你想往多個Model中添加方法的時候,你只需要簡單地修改一個文件即可。
在繼承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注意last_name屬性,是用下滑線分隔的,如果你想用get和set魔術方法,那么需要使用駝峰命名法。
$thing_1->setLastName('Smith');在新版本的magento中你可以用array關聯數組的方式獲取數據。
var_dump($thing_3["last_name"]);T這個歸功于php5的新特性,ArrayAccess接口。也是 “Object Oriented Programming”.
現在然我們把這些對象加到數據收集器Varien_Data_Collection中。很多程序員將Collection看成是數組,當然我不反對。
$collection_of_things=new Varien_Data_Collection();$collection_of_things->addItem($thing_1)->addItem($thing_2)->addItem($thing_3);大多數Magento data Collections繼承于Varien_Data_Collection,你可以使用里面的任何一個方法。
那么我們可以做些什么呢?接下來我們使用foreach去循環它。
foreach($collection_of_thingsas$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'));Magneto還給我們提供了一些基本的過濾功能
var_dump($collection_of_things->getItemsByColumnValue('name','Spot'));模型數據收集器(Model Collections)
前面我們有提到,所有Magento的模型數據收集器都繼承Varien_Data_Collectionm,所以理論上我們可以使用之前的所有方法。下面讓我們以product模型實戰下。
publicfunction testAction(){$collection_of_products= Mage::getModel('catalog/product')->getCollection();var_dump($collection_of_products->getFirstItem()->getData());}基本所有的Magento模型都有個方法叫getCollection默認情況下,它會返回系統中所有的數據。
Magento的數據收集器Collection包含很多復雜的邏輯來處理數據,無論是否使用索引或緩存、EAV表等。
上面的產品數據收集器,它里面還有Varien_Data_Collection_Db類。這個類給你很多有用的方法,例如如果你向看sql的select語句。
publicfunction 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'=>arrayempty ?protected '_adapter'=>...從上面可以看出,Magento使用的是ZendFramework的數據庫鏈接層。接下來讓我們看看更有意義的東西
publicfunction testAction(){$collection_of_products= Mage::getModel('catalog/product')->getCollection();//var_dump($collection_of_products->getSelect()); //might cause a segmentation faultvar_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'這個差異取決于你選擇的字段,同樣也涉及到索引和緩存。如果你看過之前的文章,那么你應該知道很多Magento表是使用Eav表結構的,默認情況下一個eav的數據收集器將不會包含所有的對象字段,你可以通過addAttributeToSelect來添加它們。讓我們看看例子。
$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 Objectecho'Done';//execution continues但是Magento不是這樣的,它采用的是Lazy Loading。延遲加載意味著在程序需要數據前,sql是不執行的,如下。
$collection_of_products= Mage::getModel('catalog/product')->getCollection();在這個時候Magento還沒有鏈接數據庫,你可以放心地去做你想要做的事。
$collection_of_products= Mage::getModel('catalog/product')->getCollection();$collection_of_products->addAttributeToSelect('meta_title');你不必擔心每次添加屬性的時候Magento都會執行一個sql,去獲取數據,sql只有在你需要數據的時候才會被執行。
Magento對數據庫連接層做了良好的封裝,當然它也考慮到了效率問題。在一般情況下,你沒必要去擔心sql后臺是怎么執行的,只需要專心做你的功能,例如區塊、布局等。這是Magento非常優秀的地方。
過濾數據(Filtering Database Collections)
最重要的一個方法是addFieldToFilter。通過這個方法可以添加我們sql中的WHERE語句。
publicfunction 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 goodnessecho"Our collection now has ".count($collection_of_products).' item(s)';var_dump($collection_of_products->getFirstItem()->getData());}addFieldToFilter方法中的第一個參數是你想過濾的字段名稱,第二個是你想過濾的值。例如剛剛sku是字段名稱,n2610是值。
第二個參數也可以被用來指定某一類型的數據。稍微有些復雜,我們繼續往下看。
$collection_of_products->addFieldToFilter('sku','n2610');這個等同于sql中的where條件句
WHERE sku ="n2610"下面的例子自己嘗試下
publicfunction 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());輸出的將是下面的sql語句。
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`INNERJOIN`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=0LEFTJOIN`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')在你有空的時候可以好好研究下上面的sql語句,我們先不轉移焦點,繼續我們下面的講解。
其它比較運算符
我確定在剛剛的練習中,你想知道如何實現一個不是“=”的where條件句,例如不等于、大于、小于。剛剛我們有講過addFieldToFilter的第二個參數允許傳入不同“類型”。
其實很簡單,只要將一個簡單的數組作為第二個參數傳入addFieldToFilter方法就可以變換條件句。
數組的鍵就是“類型”,關聯的值就是你想過濾的值。我們改寫下上面的代碼。
publicfunction testAction(){var_dump((string) ? ? Mage::getModel('catalog/product')->getCollection()->addFieldToFilter('sku',array('eq'=>'n2610'))->getSelect());}看上面的過濾器
addFieldToFilter('sku',array('eq'=>'n2610'))正如你看到的,第二個參數是一個php的數組。它的鍵是“eq”,代表等于的意思。
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 equalWHERE (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
inandnin條件句中,語序你傳入一個數組作為值。例如:
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 過濾
這是另一種過濾方式,在傳入的數組中,允許你傳入兩個鍵,是從哪里到哪里的意思,一個數值區間。
publicfunction 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%')但是,聰明的你可以發現,上面的例子不可能返回任何結果,因為一個sku不可能以a開頭,同時也以b開頭。
我們希望用的應該是”OR”,那么如何實現呢?這又使我們將焦點集中到了addFieldToFilter方法的第二個參數上。
如果你希望構造一個or的語句,首先我們構造兩個參數。
publicfunction testAction(){$filter_a=array('like'=>'a%');$filter_b=array('like'=>'b%');}然后將它們作為一組參數傳入addFieldToFilter方法中,如下。
publicfunction 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語句,就可以獲取幾乎所有模型的所有你想要的數據。
轉載于:https://blog.51cto.com/vick1992/1280997
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的深入理解Magento-第十章-数据操作数据收集器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Eclipse C++的配置问题laun
- 下一篇: SqlDataReader对象的Next