出发前的准备

2011游记第二篇

旅行最重要的东西,非钱莫属,我曾经有无数个攒钱的计划,虽然收入不低,但偏偏连一毛钱也攒不下,但我很清楚,即使没钱,我也一样会开始一段旅途。

大概在2月份的时候,我向公司提出辞职,领导不想失去一个忠实的“奴隶”,想方设法留我并且还涨了薪水,于是我决定在这里最后工作三个月,5月10号我终于离开了这个“牢笼”。

离职的时候我手里只有最后一个月的薪水,不过还好,我还有一个朋友那里来的项目计划,还有一份今年六月份动漫展展位的合同,我想这些应该是我最后的机会,于是5月剩下的20天,我忙于某个知名教育软件的破解工作。6月初,忙于动漫展的准备和展会的销售工作,我想这是我人生中真真正正的第一桶金,我的玩具销量好的超乎想象,展会7天,在第6天的时候连我从哈尔滨调过来的货也全部卖光了,最后连请朋友吃饭的钱也都算上,7天净赚5000多。

展会结束后我开始置办旅行装备,项目款也陆续到帐,上下打点之后自己剩下一半。

旅行还有一个很重要的东西便是线路,对于线路我比较模糊,因为我一直都不清楚我能有多少钱去旅行,花销有多大,能走多少地方,所以我只是在google map上标注了我想去的地方,并且尽量让这些地方都顺路。

写于2011.9.19

深入理解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)](http://www.wemvc.com/1230.html)。当然你不必了解很底层的东西,你只需要知道如何用就可以了。

适合对象:高级开发者

作者:精东

最后修改时间: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_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'));
Magneto还给我们提供了一些基本的过滤功能
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模型都有个方法叫`getCollection`默认情况下,它会返回系统中所有的数据。

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' => 
...
从上面可以看出,Magento使用的是ZendFramework的数据库链接层。接下来让我们看看更有意义的东西
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'
这个差异取决于你选择的字段,同样也涉及到索引和缓存。如果你看过之前的文章,那么你应该知道很多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 Object
echo 'Done'; //execution continues
但是Magento不是这样的,它采用的是[Lazy Loading](http://en.wikipedia.org/wiki/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语句。

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());

}

addFieldToFilter方法中的第一个参数是你想过滤的字段名称,第二个是你想过滤的值。例如刚刚sku是字段名称,n2610是值。

第二个参数也可以被用来指定某一类型的数据。稍微有些复杂,我们继续往下看。

$collection_of_products->addFieldToFilter('sku','n2610');
这个等同于sql中的where条件句
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()
);
输出的将是下面的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` 
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')
在你有空的时候可以好好研究下上面的sql语句,我们先不转移焦点,继续我们下面的讲解。

其它比较运算符

我确定在刚刚的练习中,你想知道如何实现一个不是“=”的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'))
正如你看到的,第二个参数是一个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 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%')
但是,聪明的你可以发现,上面的例子不可能返回任何结果,因为一个sku不可能以a开头,同时也以b开头。 我们希望用的应该是”OR”,那么如何实现呢?这又使我们将焦点集中到了addFieldToFilter方法的第二个参数上。

如果你希望构造一个or的语句,首先我们构造两个参数。

public function testAction()
{
        $filter_a = array('like'=>'a%');
        $filter_b = array('like'=>'b%');
}
然后将它们作为一组参数传入addFieldToFilter方法中,如下。
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语句,就可以获取几乎所有模型的所有你想要的数据。

原文链接:http://www.wemvc.com/1229.html

深入理解Magento-第九章-修改、扩展、重写Magento代码

作为一个开发者的你,肯定要修改Magento代码去适应你的业务需求,但是在很多时候我们不希望修改Magento的核心代码,这 里有很多原因,例如将来还希望升级Magento、还想使用更多的Magento代码。如果你正在寻找修改Magento代码的最佳方式,那么此篇文章将 会是一个不错的教程。

适合对象:高级开发者

适合目标:开发者希望自定义修改Magento

当前版本:Magento versions: 1.4.0.1

作者:精东

最后修改时间:2010年7月13日

版本:V 0.3.0

重写Magento模块(Module)

第一步,你需要创建属于你自己代码的命名空间,例如Wemvc,App等,为了方便与大家分享代码,我将空间命名为App。

app/
     code/
            core/
            community/
            local/
                    App/
假如你现在打算修改Mage/Catalog/Block/Breadcrumbs.php这个文件,你可以在你的命名空间,App里添加一个新的 模块“Catalog”。接下来创建块(Block)目录,并复制Breadcrumbs.php到你的新目录中。这里还需要你创建一个 config.xml配置文件。
app/
     code/
            core/
            community/
            local/
                    App/
                               Catalog/
                                          Block/
                                                 Breadcrumbs.php
                                          etc/
                                                 config.xml
修改Breadcrumbs.php的类名为App_Catalog_Block_Breadcrumbs,并继承原类名Mage_Catalog_Block_Breadcrumbs。 现在,你需要激活你的新模块,这样magento才能够知道你的新模块。

创建文件app/etc/modules/App_All.xml,添加如下代码。

< ?xml version="1.0"?>
<config>
     <modules>
        <App_Catalog>
            <active>true</active>
            <codePool>local</codePool>
        </App_Catalog>
     </modules>
</config>
下面我们需要一个特殊的标签来复写掉Breadcrumbs,下面我们通过模块的配置文件来实现。

重写Magento区块(Blocks)

编辑文件“app/code/local/App/Catalog/etc/config.xml”

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <App_Catalog>
            <version>0.1.0</version>
        </App_Catalog>
    </modules>
    <global>
        <blocks>
            <catalog>
                <rewrite>
                        <breadcrumbs>App_Catalog_Block_Breadcrumbs</breadcrumbs>
                </rewrite>
            </catalog>
        </blocks>
    </global>
</config>
我们需要添加一个“blocks” 标签,或者在已经存在的“blocks”标签中添加内容。然后在模块名后面添加rewrite标签,在这个例子中模块名是“catalog”。然后我们看 “breadcrumbs”标签,这个标签帮助magento找到我们我们想修改的块。在我们的列子中,breadcrumbs是Magento核心代码 中的类名: app/code/core/Mage/Catalog/Block/Breadcrumbs.php。如果你有更多的目录层级,可以用下滑线来分隔。例 如:
      <blocks>
          <catalog>
              <rewrite>
                      <category_view>App_Catalog_Block_Category_View</category_view>
              </rewrite>
          </catalog>
      </blocks>
在这个例子中,我们重写了app/code/core/Mage/Catalog/Block/Category/View.php。

在breadcrumbs标签中的值是你的类名,这样Magento就可以获取你的类,因为类名与你的目录名一致。用过zend framework的人都知道,自动加载auto loader这个东西,它会跟你类名中的下滑线去你的目录中需要对应的类文件。记住一点,下滑线代表下一级别的文件夹,如果你的类名与你的文件目录名不一 致,那么Magento根本不会理睬你。
举例来说:

App_Catalog_Block_Breadcrumbs → /app/code/local/App/Catalog/Block/Breadcrumbs.php 
App_Catalog_Block_Category_View → /app/code/local/App/Catalog/Block/Category/View.php

重写Magento控制器(Controller)-正则表达式匹配式

重写Magento控制器我们我们以重写购物车为例。

1、首先在App下创建新的模块,依次创建如下文件:

/app/code/local/App/Shopping
/app/code/local/App/Shopping/etc
/app/code/local/App/Shopping/etc/config.xml
/app/code/local/App/Shopping/controllers
/app/code/local/App/Shopping/controllers/CartController.php
2、编辑/app/code/local/App/Shopping/etc/config.xml文件,加入如下代码:
<?xml version="1.0"?>
<config>
    <modules>
        <App_Shopping>
            <version>0.1.0</version>
        </App_Shopping>
    </modules>
    <global>
        <!-- This rewrite rule could be added to the database instead -->
        <rewrite>
            <!-- This is an identifier for your rewrite that should be unique -->
            <!-- THIS IS THE CLASSNAME IN YOUR OWN CONTROLLER -->
            <App_Shopping_cart>
                <from><![CDATA[#^/checkout/cart/#]]></from>
                <!--
                    - Shopping module matches the router frontname below - checkout_cart
                    matches the path to your controller Considering the router below,
                    "/shopping/cart/" will be "translated" to
                    "/App/Shopping/controllers/CartController.php" (?)
                -->
                <to>/shopping/cart/</to>
            </App_Shopping_cart>
        </rewrite>
    </global>
    <!--
        If you want to overload an admin-controller this tag should be <admin>
        instead, or <adminhtml> if youre overloading such stuff (?)
    -->
    <frontend>
        <routers>
            <App_Shopping>
                <!-- should be set to "admin" when overloading admin stuff (?) -->
                <use>standard</use>
                <args>
                    <module>App_Shopping</module>
                    <!-- This is used when "catching" the rewrite above -->
                    <frontName>shopping</frontName>
                </args>
            </App_Shopping>
        </routers>
    </frontend>
</config>
3、改写你自己的控制器 /app/code/local/App/Shopping/controllers/CartController.php 请将下面的代码添加到你的控制器中,我们唯一修改的地方是在index动作中添加一个error_log();
< ?php
# 控制器不会自动加载,所以我们需要包含文件,这里与区块(Block)不一样
require_once 'Mage/Checkout/controllers/CartController.php';
class App_Shopping_CartController extends Mage_Checkout_CartController
{
    #覆写indexAction方法
    public function indexAction()
    {
        # Just to make sure
        error_log('耶~成功重写购物车!');
        parent::indexAction();
    }
}
在这段代码中,首先是类名,跟前面讲到的区块(Block)一样,我们自己的类名是App_Shopping_CartController继承原先Mage_Checkout_CartController.在indexAction中我们记录了一段信息。

4、修改App_All.xml,激活我们新的Shopping模块

<?xml version="1.0"?>
<config>
     <modules>
        <App_Catalog>
            <active>true</active>
            <codePool>local</codePool>
        </App_Catalog>
        <App_Shopping>
            <active>true</active>
            <codePool>local</codePool>
        </App_Shopping>
     </modules>
</config>
到这里,清除缓存后,你已经可以看到error_log成功记录了我们的信息,打开页面http://www.wemvc.dev /checkout/cart/,显示的是购物车页面,一切正常,但如果你访问http://www.wemvc.dev/shopping/cart /,你会发现是首页。。。。我们期望的购物车视图还没有出现,如何解决呢?让我们接下来往下看。

5、修改视图文件app/design/frontend/[myinterface]/[mytheme]/layout/checkout.xml
在layout标签中,添加下面内容:

	<app_shopping_cart_index>
        <update handle="checkout_cart_index"/>
    </app_shopping_cart_index>
注意,这里的大小写敏感。

到这里基本大功告成,但是,我建议你学习下正则表达式,因为刚刚的代码中,有这么一段:

<from>< ![CDATA[#^/checkout/cart/#]]></from>
这里是使用正则表达式进行匹配的。

还有一点,经过尝试,这里是可以支持同模块名覆盖的,例如Magento代码中商品详情页是Mage_Catalog_ProductController::viewAction(),如果我们想重写这个Controller,我们可以这样做:

a.简历新的目录/app/code/local/App/Catalog/controllers/ProductController.php
代码如下:

require_once 'Mage/Catalog/controllers/ProductController.php';

/**

  • Product controller
  • @category Mage
  • @package Mage_Catalog
    /
    class App_Catalog_ProductController extends Mage_Catalog_ProductController
    {
    /
    *
    • View product action
      */
      public function viewAction()
      {
      echo ‘覆盖过的….’;
      parent::viewAction();
      }
      }
b.编辑/app/code/local/App/Catalog/etc/config.xml,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<config>
 <modules>
 <App_Catalog>
     <version>0.1.0</version>
 </App_Catalog>
 </modules>
 <global>
 <!-- This rewrite rule could be added to the database instead -->
 <rewrite>
     <!-- This is an identifier for your rewrite that should be unique -->
     <!-- THIS IS THE CLASSNAME IN YOUR OWN CONTROLLER -->
     <App_Shopping_cart>
         <from><![CDATA[#^/catalog/product/#]]></from>
         <!--
             - Shopping module matches the router frontname below - checkout_cart
             matches the path to your controller Considering the router below,
             "/shopping/cart/" will be "translated" to
             "/App/Shopping/controllers/CartController.php" (?)
         -->
         <to>/catalog/product/</to>
     </App_Shopping_cart>
 </rewrite>
 <blocks>
     <catalog>
         <rewrite>
                 <breadcrumbs>App_Catalog_Block_Breadcrumbs</breadcrumbs>
         </rewrite>
     </catalog>
 </blocks>
 </global>
 <frontend>
 <routers>
     <catalog>
         <use>standard</use>
         <args>
             <module>App_Catalog</module>
             <frontName>catalog</frontName>
         </args>
     </catalog>
 </routers>
 </frontend>
</config>
清空缓存,刷新你的商品详情页,看是不是变了,呵呵。但是这个方法有个弊病,你需要把这个模块的所有Controller都复写掉,不然你会遇到比较大的麻烦。说到这,我再介绍一种重写方法. 仔细看配置文件的写法:
<?xml version="1.0"?>
<config>
  <modules>
 <App_Mycms>
     <version>0.1.0</version>
 </App_Mycms>
 </modules>
 <frontend>
 <routers>
     <mycms>
         <use>standard</use>
         <args>
             <module>App_Mycms</module>
             <frontName>mycms</frontName>
         </args>
     </mycms>
 </routers>
 </frontend>  
 <global>
 <routers>
     <cms>
         <rewrite>
             <index>
                 <to>App_Mycms/index</to>
                 <override_actions>true</override_actions>
                 <actions>
                    <noroute><to>App_Mycms/index/noroute</to></noroute>
                 </actions>
             </index>
         </rewrite>
     </cms>
 </routers>	 
 </global>
</config>
综上所述,三种重写方法都各有千秋,关键看你用在什么地方。另外我们在实践中发现,Magento好像不建议你自己的模块名与现有系统中的模块名一 致,例如Mage_Customer是已有的,它的模块名叫Customer,如果你想复写它,那么最好你再建一个App_Customers之类的。

重写Magento模型和动作助手(Model&Helper)

我们在改写Magento的过程中,为了实现自己的业务逻辑,难免要改它的业务模型。你可以尝试用模块下的配置文件配置你自己的类,继承你想重写的模型或者助手,然后调用自己的类。现在我们以用户模型为例深入讲解。

a.首先创建自己的模块文件夹

app/code/local/App/Customer
app/code/local/App/Customer/etc/config.xml
app/code/local/App/Customer/Model
app/code/local/App/Customer/Model/Customer.php
b.修改app/etc/modules/App_All.xml
        <App_Customer>
            <active>true</active>
            <codePool>local</codePool>
        </App_Customer>
c.修改自己的模块配置文件app/code/local/App/Customer/etc/config.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <App_Customer>
            <version>0.1.0</version>
        </App_Customer>
    </modules>

&lt;global&gt;
    &lt;models&gt;
        &lt;customer&gt;
            &lt;rewrite&gt;
                &lt;customer&gt;App_Customer_Model_Customer&lt;/customer&gt;
            &lt;/rewrite&gt;
        &lt;/customer&gt;
    &lt;/models&gt;
&lt;/global&gt;

</config>

d.现在写你新的Model,在文件app/code/local/App/Customer/Model/Customer.php中新建类App_Customer_Model_Cutomer
class App_Customer_Model_Customer extends Mage_Customer_Model_Customer {
    // 重写已存在的方法
    public function validate() {
        // Define new validate rules. From now magento call this validate method instead of existing method
        //return $errors;
        return true;
    }

// 你还可以创建新的方法
public function newMethod() {
    // function logic
}

}

e.我们再重写一个类,以加深理解。接下来我们重写Customer Address Model。 跟重写Customer Model一样,我们先编辑模块的配置文件app/code/local/App/Customer/etc/config.xml。
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <App_Customer>
            <version>0.1.0</version>
        </App_Customer>
    </modules>

&lt;global&gt;
    &lt;models&gt;
        &lt;customer&gt;
            &lt;rewrite&gt;
                &lt;customer&gt;App_Customer_Model_Customer&lt;/customer&gt;
                &lt;address&gt;App_Customer_Model_Address&lt;/address&gt;
            &lt;/rewrite&gt;
        &lt;/customer&gt;
    &lt;/models&gt;
&lt;/global&gt;

</config>

上面看出来了么,rewrite标签内的customer和address其实就是你要覆写的magento model。 接下来创建model class App_Customer_Model_Address,并写你要覆盖和新增的方法
class App_Customer_Model_Address extends Mage_Customer_Model_Address {
    // 重写已存在的方法
    public function validate() {
        // Define new validate rules. From now magento call this validate method instead of existing method
        //return $errors;
        return true;
    }

// 你还可以创建新的方法
public function newMethod() {
    // function logic
}

}

f.我再讲下如何覆盖Magento的模型资源,这里以复写Address Entity Model class为例,我们先来修改模块的配置文件app/code/local/App/Customer/etc/config.xml。
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <App_Customer>
            <version>0.1.0</version>
        </App_Customer>
    </modules>

&lt;global&gt;
    &lt;models&gt;
        &lt;customer&gt;
            &lt;rewrite&gt;
                &lt;customer&gt;App_Customer_Model_Customer&lt;/customer&gt;
                &lt;address&gt;App_Customer_Model_Address&lt;/address&gt;
            &lt;/rewrite&gt;
        &lt;/customer&gt;
        &lt;customer_entity&gt;
            &lt;rewrite&gt;
                &lt;address&gt;App_Customer_Model_Entity_Address&lt;/address&gt;
            &lt;/rewrite&gt;
        &lt;/customer_entity&gt;
    &lt;/models&gt;
&lt;/global&gt;

</config>

接下来创建类文件。
class App_Customer_Model_Entity_Address extends Mage_Customer_Model_Entity_Address {
    protected function _afterSave(Varien_Object $address) {
        // Write your code
    }
}

总结

在本章中我们学习了如何重写模块、重写控制器、重写区块,以及如何重写模型和助手,基本重写Magento代码对你来说已经不是难事了。文章至此, 要恭喜你,你已经掌握了大部分修改Magento的技能。下面的文章我们会进行更深入的研究。最后感谢所有Sasacake Team Member,是他们对待工作的热情和责任感促使我写这些教程。

原文链接:http://www.wemvc.com/1187.html

为何远行

2011游记第一篇

长春->西安->西宁->格尔木->拉萨->巴松措->墨脱->丽江->大理->桂林->深圳->广州->上海->青岛->End.

从踏上行程至今,我一直还是不明白为什么要有这样一次远行。这次远行的最初想法产生在四年前大学一年级的时候,为什么想去,已经想不起来了。这几年一直忙忙碌碌,忙于工作,忙于爱情,忙于每天的碌碌无为。有的时候我想给这一切找一个出口,有的时候我想让这一切结束。

时间日复一日,当我发现爱情已经伤痕累累,当我发现每天晚上都在无意义的加班工作,当我发现梦想渐渐远离,我觉得我有必要做点什么。一个不经意的机会,我在网上看到了一个叫墨脱的地方,听说了途中的千难万险,那一刻,我被深深的吸引住了。

今年年初的时候,我在网上买了一本叫《背包十年》的书,作者小鹏讲述了他十年的旅行经历,这让我的那个已经深埋已久的想法再次萌发,并且一发不可收拾。于是早在半年之前,我便开始准备我的旅行。

不过当时我是打算结束身边的一切的,离开这个我生活了五年的地方,结束这样一段感情,去一个陌生的地方,开始新的生活。可偏偏事与愿违,最后我还是回到了这里,准备续写新的篇章。

写于2011.9.19

“我和谷岳很快就会离年轻这一词越来越远,我们常年如同蚂蚁一般努力奋斗在时代洪流面前,渐渐变得微不足道,物质的家园早已褪色,精神的家园形单影只,搭车旅行,在路上,更像一场迟来的成人礼。” - 《搭车去柏林》

Magento安装教程

1.下载

从官方网站(http://www.magentocommerce.com/download)下载最新版本的magento及示例数据。

  • 系统程序Full Release - stable version ver 1.6.1.0 - Added October 19, 2011
  • 示例数据Sample Data ver 1.2.0 - Added December 29, 2008
    2.安装

在安装之前,确认你已经安装了php运行环境,并确保apache和mysql服务已经正常运行。将解压后的目录放到web目录下,如果要安装测试数据需要把Sample Data中的media目录复制到magento安装目录中去。

  • xampp的web目录是htdocs
  • WAMPServer的web目录是Apache\WWW

打开http://localhost/magento 开始按照提示进行安装。

选择同意条款,下一步

选择时区和货币种类,下一步

如果未做相应设置可能会出现上面这种提示,因为magento是基于这些模块运行的。

到你的php.ini中找到这个下面这些内容:

extension=php_mcrypt.dll extension=php_curl.dll extension=php_mysql.dll extension=php_mysqli.dll extension=php_pdo_mysql.dll

确保前面的分号”;”已经被去掉

如果是xampp或者WAMPServer需要修改两个php.ini,xampp的在 apache\bin, WAMPServer在C:\wamp\bin\apache\Apache2.2.11\bin目录下, 在php.ini中做同样修改。

另外安装过程中创建数据库的时间比较长,需要临时修改PHP.ini中的一些设置:

max_input_time = 300 memory_limit = 512M mysql.connect_timeout = 300 max_execution_time = 1800

修改好之后重新启动apache服务,然后刷新页面之后弹出界面如下:

输入数据库名和数据库的用户名和密码,如果还没有数据库需要为magento手动创建一个新的数据库,WEB设置可以保持默认设置。

创建你的数据库 例如:

名称: magento
字符集为: utf-8
字符集设置: utf8_bin

如果需要使用测试数据,需要在下一步之前导入sample data。选择新创建的数据库,在右边的窗口中选择导入(Import)功能,选择sample data压缩包中的数据文件magento_sample_data_for_1.2.0.sql

在弹出窗口中找到下载并解压缩的示例数据文件后,点击open后返回导入页面,点击右下角的GO开始导入数据。

导入数据后,再通过浏览器窗口进行magento系统的安装。

可以选择会话(session)数据保存在数据库(database)中,默认是在临时文件夹中以文件的形式存在

填写你登陆后台的密码和账号,继续下一步

到这里magento就已经安装完毕了,点击Go to Backend或者进入http://localhost/magento/index.php/admin/登陆你的后台。

如果安装了示例数据,再安装电子商务系统后,当访问具体商品时会出错,提示访问的页面不存在。这是因为系统生成的静态网址需要被更新,因此我们需要重新建立静态网址索引,登陆系统管理后台,进行system/index management页面,选择所有的索引(最重要的就是catalog url rewrites),然后选择重建索引(Reindex data)并执行。

重建索引后再访问具体商品时就能正常访问了。

3.汉化

在Magento 1.6版本中的后台默认已经支持中文,对前台需要我们手工进行汉化。

方法一,通过Magento Connect自动安装程序安装

在管理界面上选择Magento connect Manager进入插件安装管理界面

www.magentocommerce.com网站上查找相关的插件:

http://www.magentocommerce.com/extension/359/magento-community-modules--chinese-simplified-china-language-pack

Magento Community Modules - Chinese Simplified (China) Language Pack

KEY: magento-community/Locale_Mage_community_zh_CN

由于这个插件还处于beta版本,我们要先设置插件管理可以接受beta版本的程序(默认只接受稳定版本的插件)。

在setting页面上选择可以接受状态为Beta,然后点击保存设置

把这个KEY拷贝粘贴到插件管理界面上的插件代码文件框中,然后点击安装即可。

方法二,把汉化文件包拷贝到相关的目录下

把汉化包解压得到一个文件夹app,拷贝这个文件夹到安装目录下,覆盖其中的app文件夹即可。

注:本文为修改版,原文出自豆丁网。