标签归档 magento建站

通过清心醉

magento开发|深入分析magento之创建分类

由于magento的EVA模型实在太多数据了,作者也没有那么多的时间去一个个查看数据字段的参数,现将创建(根)分类时所写入SQL的数据进行解释:

由于MAGENTO是使用自增ID的方式,如果我们要独立写添加分类的时候,就需要获取当前的最大ID值+1处理.

$ID=新增分类的ID,建议使用表内最大值+1;

$categoryname=分类名称

catalog_category_entity  1条主数据:
字段参数:
$ID==3==3==1==当前时间==当前时间 ==1/$ID==1==1

#注: 1/$ID是因为1为全站整目录,$ID表示是全站目录中的其中一个根目录.

catalog_category_entity_datetime 2条时间数据
字段参数:
自增ID==3==59==0==$ID==NULL
自增ID==3==60==0==$ID==NULL

catalog_category_entity_decimal 1条数据
字段参数:
自增ID==3==70==0==$ID==NULL
catalog_category_entity_int 6条数据
字段参数:
自增ID==3==42==0==$ID==0
自增ID==3==67==0==$ID==1
自增ID==3==50==0==$ID==NULL
自增ID==3==51==0==$ID==0
自增ID==3==68==0==$ID==0
自增ID==3==69==0==$ID==0

catalog_category_entity_text 5条数据
自增ID==3==44==0==$ID==NULL
自增ID==3==47==0==$ID==NULL
自增ID==3==48==0==$ID==NULL
自增ID==3==62==0==$ID==NULL
自增ID==3==65==0==$ID==NULL

catalog_category_entity_varchar 6条数据
自增ID==3==41==0==$ID==$categoryname
自增ID==3==46==0==$ID==NULL
自增ID==3==49==0==$ID==PRODUCTS
自增ID==3==58==0==$ID==NULL
自增ID==3==61==0==$ID==NULL
自增ID==3==43==0==$ID==$categoryname

通过清心醉

magento开发|magento建站|深入理解magento之分类产品筛选器

在magento后台管理分类,如果打开了magento指定的分类,可以查看当前分类内的产品信息,如果点击了筛选器,就会列出所有的产品列表
因为一个系统2个类型的网站店铺,所以要修改magento筛选的功能.
在magento/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/Product.php块文件里.

有这么一个方法:
protected function _prepareCollection()
{
if ($this->getCategory()->getId()) {
$this->setDefaultFilter(array(‘in_category’=>1));
}
$collection = Mage::getModel(‘catalog/product’)->getCollection()
->addAttributeToSelect(‘name’)
->addAttributeToSelect(‘sku’)
->addAttributeToSelect(‘price’)
->addStoreFilter($this->getRequest()->getParam(‘store’)) //获取的店铺ID
->joinField(‘position’,
‘catalog/category_product’,
‘position’,
‘product_id=entity_id’,
‘category_id=’.(int) $this->getRequest()->getParam(‘id’, 0),
‘left’);
$this->setCollection($collection);

if ($this->getCategory()->getProductsReadonly()) {
$productIds = $this->_getSelectedProducts();
if (empty($productIds)) {
$productIds = 0;
}
$this->getCollection()->addFieldToFilter(‘entity_id’, array(‘in’=>$productIds));
}

return parent::_prepareCollection();
}
上面的红字那行,自己写个获取站点店铺的方法,就可以完整的实现只提取当前店铺的产品!

切记:获取的店铺store必须为数字

通过清心醉

magento开发-建站|magento产品列表页关闭操作功能

今天一位外贸用户的网站管理员需要修改magento的用户权限,其实多简单的事啊,修改下magento用户组就可以了.但发现有个magento做的不是很好的,因为magento的权限里,产品列表页面有个操作功能,可以修改产品为删除.如果员工帐号出了问题直接就是批量的删除(也许你会说,打开产品一样可以删除啊,我相信没谁有那么多的时间无聊的去一个个删掉).为此作者受magento客户的要求修改了下管理页视图:

class Mage_Adminhtml_Block_Catalog_Product_Grid extends Mage_Adminhtml_Block_Widget_Grid

而且Mage_Adminhtml_Block_Widget_Grid使用的视图模板是:$this->setTemplate(‘widget/grid.phtml’);

(注:相关产品等表都是使用该视图模板,后期还要修改)

在grid.phtml模板文件里:

<?php if($this->getMassactionBlock()->isAvailable()): ?>
<?php echo $this->getMassactionBlockHtml() ?>
<?php endif ?>

你可以直接删除这些,但同时也会删除多选的功能,所以跟踪下代码进行修改:

public function getMassactionBlockHtml()
{
return $this->getChildHtml(‘massaction’);
}

好了,这引用了其他的视图模型:

文件在:magento/app/design/adminhtml/default/default/template/widget/grid/massaction.phtml

 

<?php //权限控制修改开始 ?>
<?php if(Mage::getFobAdmin()) {?>
<td>
<div class=”right”>
<div class=”entry-edit”>
<?php if ($this->getHideFormElement() !== true):?>
<form action=”” id=”<?php echo $this->getHtmlId() ?>-form” method=”post”>
<?php endif ?>
<?php echo $this->getBlockHtml(‘formkey’)?>
<fieldset>
<span class=”field-row”>
<label><?php echo $this->__(‘Actions’) ?></label>
<select id=”<?php echo $this->getHtmlId() ?>-select” class=”required-entry select absolute-advice local-validation”>
<option value=””></option>
<?php foreach($this->getItems() as $_item): ?>
<option value=”<?php echo $_item->getId() ?>”<?php echo ($_item->getSelected() ? ‘ selected=”selected”‘ : ”)?>><?php echo $_item->getLabel() ?></option>
<?php endforeach; ?>
</select>
</span>
<span class=”outer-span” id=”<?php echo $this->getHtmlId() ?>-form-hiddens”></span>
<span class=”outer-span” id=”<?php echo $this->getHtmlId() ?>-form-additional”></span>
<span class=”field-row”>
<?php echo $this->getApplyButtonHtml() ?>
</span>
</fieldset>
<?php if ($this->getHideFormElement() !== true):?>
</form>
<?php endif ?>
</div>

<div class=”no-display”>
<?php foreach($this->getItems() as $_item): ?>
<div id=”<?php echo $this->getHtmlId() ?>-item-<?php echo $_item->getId() ?>-block”>
<?php echo $_item->getAdditionalActionBlockHtml() ?>
</div>
<?php endforeach; ?>
</div>
</div>
</td>
<?php }?>
<?php //权限控制修改结束 ?>

通过清心醉

magento开发|magento打开产品列表的时候关闭操作栏的网站选择

magento打开产品列表的时候关闭操作栏的网站选择,因为如果不对这一块进行限制,服装站的管理员就可以调用数码站的产品.虽然说前几篇文章作者说了通过store来进行控制,但也不太好看,因此为了不必要的麻烦,对magento进行二次开发:magento/app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Filter/Select.php

public function getHtml()
{
//该方法进行产品序表输出
$html = ‘<select name=”‘.$this->_getHtmlName().'” id=”‘.$this->_getHtmlId().'” class=”no-changes”>’;
$value = $this->getValue();
foreach ($this->_getOptions() as $option)
{
if($this->_getHtmlName()==’websites’ && !Mage::getFobAdmin()) //如果select的下拉为websites并且不是后台的超级管理员的话,直接中指
{
break;
}
if (is_array($option[‘value’]))
{
$html .= ‘<optgroup label=”‘ . $this->escapeHtml($option[‘label’]) . ‘”>’;
foreach ($option[‘value’] as $subOption)
{
$html .= $this->_renderOption($subOption, $value);
}
$html .= ‘</optgroup>’;
}
else
{
$html .= $this->_renderOption($option, $value);
}
}
$html.='</select>’;

return $html;
}

通过清心醉

magento开发|magento显示当前用户的站点管理

我们都知道magento可以多站点-多店铺-多语言化.两个网站之间,不能显示不属于当前网站的产品信息参数,因为我们要限制store;

magento/app/design/adminhtml/default/default/template/store/switcher.phtml文件里

就是进行循环的了,我们修改下部分的代码:在<?php foreach ($this->getStores($group) as $store): ?>里面

<?php
$store_name=$this->escapeHtml($website->getName()); //获取店铺名称
if($store_name==Mage::getSingleton(‘admin/session’)->getUser()->getUsername()) //如果是对应的用户进行输出
{
?>
<?php if ($showWebsite == false): ?>
<?php $showWebsite = true; ?>
<optgroup label=”<?php echo $this->escapeHtml($website->getName()) ?>”></optgroup>
<?php endif; ?>
<?php if ($showGroup == false): ?>
<?php $showGroup = true; ?>
<optgroup label=”&nbsp;&nbsp;&nbsp;<?php echo $this->escapeHtml($group->getName()) ?>”>
<?php endif; ?>
<option value=”<?php echo $this->escapeHtml($store->getId()) ?>”<?php if($this->getStoreId() == $store->getId()): ?> selected=”selected”<?php endif; ?>>&nbsp;&nbsp;&nbsp;&nbsp;<?php echo $this->escapeHtml($store->getName()) ?></option>
<?php }?>

<?php if(Mage::getFobAdmin()) {// 如果是管理员 ?>
<?php if ($showWebsite == false): ?>
<?php $showWebsite = true; ?>
<optgroup label=”<?php echo $this->escapeHtml($website->getName()) ?>”></optgroup>
<?php endif; ?>
<?php if ($showGroup == false): ?>
<?php $showGroup = true; ?>
<optgroup label=”&nbsp;&nbsp;&nbsp;<?php echo $this->escapeHtml($group->getName()) ?>”>
<?php endif; ?>
<option value=”<?php echo $this->escapeHtml($store->getId()) ?>”<?php if($this->getStoreId() == $store->getId()): ?> selected=”selected”<?php endif; ?>>&nbsp;&nbsp;&nbsp;&nbsp;<?php echo $this->escapeHtml($store->getName()) ?></option>
<?php }?>

第二个判断是因为管理员是管理整个MAGENTO的,所以权限不同,全部循环输出

 

通过清心醉

magento重置筛选器

前几篇文章作者写了magento后台打开产品页显示当前用户的产品,虽然产品管理页面有个重置筛选器不能查看到其他站点的数据.

但在产品的详细配置里,比如相关产品,超售产品等等,还是有数据库里的全部信息的.

今天就来作者来详细介绍下magento的重置筛选器.

magento的重置筛选器,是通过onclick事件进行触发:

我们来看看有哪些:

产品的管理页::productGridJsObject.resetFilter()

产品参数里的相关产品页::related_product_gridJsObject.resetFilter()

产品参数里的超售页::up_sell_product_gridJsObject.resetFilter()

产品参数里的交叉销售::cross_sell_product_gridJsObject.resetFilter()

细心的人会发现,该方法是通过组合进行的, 后面的方法都是resetFilter();

app/code/core/Mage/Adminhtml/Block/Widget/Grid.php里面有protected function _prepareLayout()方法

我们来看看相关的:

$this->setChild(‘reset_filter_button’,
$this->getLayout()->createBlock(‘adminhtml/widget_button’)
->setData(array(
‘label’ => Mage::helper(‘adminhtml’)->__(‘Reset Filter’),
‘onclick’ => $this->getJsObjectName().’.resetFilter()’,
))
);

productGridJsObject.resetFilter()的方法是在

magento/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Grid.php

里,看目录的命名应该就能知道了.至于后面的产品参数里的三个,作者稍后在进行写上.

通过清心醉

magento开发|magento后台打开产品页显示当前用户的产品

magento开发修改了后台对不同店铺的操作.假设老板请了员工A做数码产品,又请了B做服装产品.

而2个不同的产品类别分在了两个域名的站点上,这样A和B两个员工的产品互相之间就不能显示了.

因次我们对magnento二次开发,让他只显示对应的站点的产品信息.(后期还会对magento进行二次开发修改相关产品等参数).

在magento/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Grid.php里

有protected function _getStore()这一个获取店铺的方法

作者自己写了个封装,是用来判断用户类型和对应的可以修改的站点的

修改过后的方法为:

protected function _getStore()
{
if (Mage::getFobAdmin())
{
$storeId = (int) $this->getRequest()->getParam(‘store’, 0);
}
else
{
$data=Mage::getUserWebsites();
$storeId=$data[‘0’][‘website_id’];
unset($data);
}
return Mage::app()->getStore($storeId);
}

通过清心醉

magento开发|magento不同站点的分类禁止显示

今天magento开发的重点就是分类的权限限制.可能很多人不知道我为什么要这么修改magento的功能.

(用户要我给magento做两个分类,对应不同的网站,一个专卖数码产品一个专卖,所以上传的话为了避免另一个站的分类数据在产品选择分类那显示出来,最好的方法就是对magento二次开发了.)

好了,说开发吧:

产品分类筛选显示模板目录:
/app/esign/adminhtml/default/defalt/template/catalog/product/edit/categories.phtml

因为magento是使用AJAX进行请求的,所以,我们看不到太多的PHP的语句,基本都是JavaScript覆盖了.

在一开始就有个getRootNode(),是magento分类的全部参数.具体数据太多,自行打印可查看

在categories.phtml里进行foreach循环输出.

在JavaScript里有个bildCategoryTree(parent, config)的方法,里面就是循环输出分类

我们可以看到有个变量:var _node = Object.clone(config[i]);

通过for循环组合输出,可以看到里面包含了ID.

好了,有ID了就好办了;

比如作者不希望显示根分类为2的属性,作者修改了下该方法

function bildCategoryTree(parent, config){
if (!config) return null; //is no catagory
if (parent && config && config.length){
for (var i = 0; i < config.length; i++){
//config.length为根目录的数量
config[i].uiProvider = Ext.tree.CheckboxNodeUI;
var node;
var _node = Object.clone(config[i]);
if(_node[‘id’]==2)
{
// break;
}
else
{
if (_node.children && !_node.children.length) {
delete(_node.children);
node = new Ext.tree.AsyncTreeNode(_node);
} else {
node = new Ext.tree.TreeNode(config[i]);
}
parent.appendChild(node);
node.loader = node.getOwnerTree().loader;
if(config[i].children){
bildCategoryTree(node, config[i].children);
}
}
}
}
}

这样如果分类ID如果=2的话,系统就不会进行输出调用了.

因为要对应系统,所以我们需要根据数据库里的来屏蔽非当前站点分类

开发的话,自己写个模型来进行提取站点的根分类

数据库对应的表段为:

core_store //站点信息参数
core_store_group //站点分类参数

至于要如何获取站点的store_id,作者前面的文章已经有说(强制增加站点);

根据store_id来提取分类就可以了.

通过清心醉

magento开发|magento强制关闭产品上传网站选择

前文作者说了magento强制给产品增加网站,不过那是由后端控制器中进行操作的.

由于magento后台一般没有什么主题化,所以主题这一块也要修改下.

因为默认的网站已经通过后端控制器完成,所以显示的时候就需要关闭掉网站这一块(具体左边的网站就不关闭了)

app/design/adminhtml/default/default/template/catalog/product/edit/websites.phtml文件里

我们可以看到foreach ($this->getWebsiteCollection() as $_website):

这里就是循环输出对应网站的选项,还包括多语言(多店铺视图)的选择提示,直接注释掉就完事了.

通过清心醉

magento开发|magento强制给产品增加网站

magento上传产品的时候,会需要自己选择产品在哪个网站的显示.

如果我有A\B两个站,那么就必须要两个都勾选择.这时候,只有二次开发magento才能满足我们的需求了:

magento上传产品(包括修改magento产品)的时候,都是以数组product的类型POST到product控制器里.

而product又是一个数组,里面会有[“website_ids”]参数,查看下参数原体:

[“website_ids”]=> array(2) { [0]=> string(1) “1” [1]=> string(1) “2” }这么一个二维数组.

因为作者给A\B两个站都是产品的网站,所以会有两个数值,参数1/2表示网站的website信息.

如此一来,我们可以关闭magento上传产品时选择分类的功能,在product控制器里进行强制增加

$productData[‘website_ids’][‘0’]=”1″;$productData[‘website_ids’][‘1’]=”2″;

这样在写入数据库的时候,就可以完整的实现自动添加到对应网站的功能了.

 

 

通过清心醉

Magento安全漏洞修复脚本

magento最近出了个新的漏洞补丁,以8月4日进行脚本的下载修复:

到https://www.magentocommerce.com/download下在对应版本的

至于补丁的安装:

https://info2.magento.com/rs/magentoenterprise/images/Installing-a-Patch-for-Magento-Community-Edition.pdf

Please upload the patch into your Magento root directory and run the appropriate SSH command:
For patch files with the file extension .sh:
sh patch_file_name.sh
Example: sh PATCH_SUPEE-1868_CE_1.7.0.2_v1.sh
For patch files with the file extension .patch:
patch –p0 < patch_file_name.patch
Once that is done, refresh the cache in the Admin under “System > Cache Management” so that the changes will be reflected. We highly recommend you test all patches in a test environment before taking them live.
For further instructions, see: Installing a Patch for Community Edition

以下为magento1.8-1.9的安全补丁:magento1.8-1.9

通过清心醉

magento开发-magento关闭编译文件的执行

Magento有一种功能叫代码重写,比如我们需要修改magento的核心url功能.

一般magento核心的文件都是在/app/code/core/mage里面.

需要修改的话复制到/app/code/local/mage…对应的文件夹里面

修改过的文件可以实现效果,但速度非常的慢.因为Magento要跑遍core和local目录.

而magento编译功能可以把修改过后的编译成新的文件(即有新的功能),如果一来加快使用文件的速度.

但如果使用了编译,如果要进行magento的二次开发的功能的时候,每次修改过后都要进行编译过,影响了速度

include/config.php文件里:

define(‘COMPILER_INCLUDE_PATH’, dirname(__FILE__).DIRECTORY_SEPARATOR.’src’);

把这行注释掉,就可以不使用编译后的文件了.而是直接使用核心文件.

通过清心醉

magento开发-为产品URL强制添加用户名

我们都知道,magento可以通过块/控制器直接来操作模型进行数据库的操作.

magento产品添加,要想强制在URL上添加用户名,必须要找到块类

流程是:控制器->布局->通过Block引用

居然有提到布局,那么就肯定会有xml的布局配置文件

adminhtml里有个catalog.xml配置文件:

<adminhtml_catalog_product_new>
<update handle=”editor”/>
<reference name=”content”>
<block type=”adminhtml/catalog_product_edit” name=”product_edit”></block>
</reference>
<reference name=”left”>
<block type=”adminhtml/catalog_product_edit_tabs” name=”product_tabs”></block>
</reference>
<reference name=”js”>
<block type=”adminhtml/catalog_product_edit_js” template=”catalog/product/js.phtml” name=”catalog_product_js”></block>
<block type=”core/template” template=”catalog/wysiwyg/js.phtml”/>
</reference>
</adminhtml_catalog_product_new>

这是后台添加新产品的一个实现功能

adminhtml/catalog_product_edit 好了,在这我们就知道块文件在哪了

adminhtml/block/catalog/product/edit.phtml

class Mage_Adminhtml_Block_Catalog_Product_Edit extends Mage_Adminhtml_Block_Widget
{
public function __construct()
{
parent::__construct();
$this->setTemplate(‘catalog/product/edit.phtml’);
$this->setId(‘product_edit’);
}

….

}

构造方法里就强制调用了模板,这样就简单操作了.

form action=”<?php echo $this->getSaveUrl() ?>

在Edit.php块里可以看到:

public function getValidationUrl()
{
return $this->getUrl(‘*/*/validate’, array(‘_current’=>true));
}

public function getSaveUrl()
{
return $this->getUrl(‘*/*/save’, array(‘_current’=>true, ‘back’=>null));
}

一个是AJAX提交JSON修改产品方法,一个是保存的方法即新增加产品.

不知道提交的控制器是否一样,暂时先不管,首先我们为新增加的产品的URL进行截获.

/adminhtml/controllers/catalog/productcontroller.php文件里

protected function _initProductSave()方法里有个

$productData = $this->getRequest()->getPost(‘product’);

处理接收POST过来的product的数组,打印可以查看.

在写个方法来进行URL_KEY的对比:

public static function setProductUrlMall($key)
{
/**
* 暂时不对中文字符串URL进行截取修改
*/
$data; //组合的URL;
$userid=Mage::getSingleton(‘admin/session’)->getUser()->getUserId();
$text=”fob-“.$userid.”-“;
$textleng=strlen($text); //查看mall+用户ID的长度
$keyleng=strlen($key); //查看url_key的长度
if ($keyleng<=$textleng) //如果传递过来的都小于默认,那肯定就要重新组合了.
{
$data=”$text”.”$key”;
return $data;
}
else
{ //如果URL的长度大于默认数字
$tempkey=substr($key, 0,$textleng); //提取URL与默认值相同长度的前X位
if ($tempkey==$text)
{
//如果前X位与默认值相同,那表示已经存在了
return $key;
}
else
{
$data=”$text”.”$key”;
return $key;
}
}
}

 

然后修改_initProductSave()的方法:

$urlkey=Mage::setProductUrlMall($productData[‘url_key’]); //将URL传递给方法进行判断组合.

unset($productData[‘url_key’]);
$productData[‘url_key’]=$urlkey;

 

通过清心醉

magento开发-后台获取管理员的名字和ID

magento开发后台,我们需要捕抓管理员的名字和ID值

如果是在头部,可以使用

$this->getUser()->getUserId() //获取管理员ID

$this->getUser()->getUsername() //获取管理员名

作者5月份时候有写过块功能

头部header.phtml文件是存在块功能的;

block/page/header.php块文件里可以看到:

public function getUser()
{
return Mage::getSingleton(‘admin/session’)->getUser();
}

这里面封装了一个获取管理员的SESSION参数的方法;

那如果我想在magento的页脚下显示用户名,是否也可以直接使用$this->getUser()->getUsername()调用呢?

答案是不允许的,因为块文件block/page/footer.php文件里没有function getUser()的方法,当然有时候我们为了不过于的频繁修改,可以考虑直接修改核心,在footer.php块功能里增加该方法

或者直接在需要使用的地方使用Mage::getSingleton(‘admin/session’)->getUser() ->getUsername();来获取

通过清心醉

magento开发-magento提取产品

网站的二次开发,基于商城的莫过于是提取产品了.magento开发也一样,今天对magento进行二次开发,对magento提取产品的大概细节进行了编写.以下为实际编写代码.

$_products = $this->getProductCollection(); //获取产品信息
var_dump($_products->getItems()); die(“数据提取完毕”);
//getItems()方法里已经获取了所有的产品信息参数,但这里获取的产品的URL只是域名后半部分
//所以

foreach($_products->getItems() as $product) //二维数组foreach循环提取
{
echo “</br>产品的URL为:”.$product->getProductUrl(); //输出独里的URL
//应该是在这里面为URL进行了拼接
//如果改成var_dump($product); 就能看到$product其实就是一个对象:数据格式为:
/*
object(Mage_Catalog_Model_Product)#271 (32)
{
[“_cacheTag”:protected]=> string(15) “catalog_product”
[“_eventPrefix”:protected]=> string(15) “catalog_product”
[“_eventObject”:protected]=> string(7) “product”
[“_canAffectOptions”:protected]=> bool(false)
[“_typeInstance”:protected]=> NULL
[“_typeInstanceSingleton”:protected]=> NULL
[“_linkInstance”:protected]=> NULL
[“_customOptions”:protected]=> array(0) { }
[“_urlModel”:protected]=> NULL
[“_errors”:protected]=> array(0) { }
[“_optionInstance”:protected]=> NULL
[“_options”:protected]=> array(0) { }
[“_reservedAttributes”:protected]=> NULL
[“_isDuplicable”:protected]=> bool(true)
[“_calculatePrice”:protected]=> bool(true)
[“_defaultValues”:protected]=> array(0) { }
[“_storeValuesFlags”:protected]=> array(0) { }
[“_lockedAttributes”:protected]=> array(0) { }
[“_isDeleteable”:protected]=> bool(true)
[“_isReadonly”:protected]=> bool(false)
[“_resourceName”:protected]=> string(15) “catalog/product”
[“_resource”:protected]=> NULL
[“_resourceCollectionName”:protected]=> string(26) “catalog/product_collection”
[“_dataSaveAllowed”:protected]=> bool(true)
[“_isObjectNew”:protected]=> NULL
[“_data”:protected]=> array(35)
{
[“entity_id”]=> string(1) “7”
[“entity_type_id”]=> string(1) “4”
[“attribute_set_id”]=> string(1) “4”
[“type_id”]=> string(6) “simple”
[“sku”]=> string(1) “7”
[“has_options”]=> string(1) “0”
[“required_options”]=> string(1) “0”
[“created_at”]=> string(19) “2013-03-12 00:48:01”
[“updated_at”]=> string(19) “2013-03-12 00:49:26”
[“cat_index_position”]=> string(1) “0”
[“price”]=> string(8) “885.0000”
[“tax_class_id”]=> string(1) “0”
[“final_price”]=> string(8) “885.0000”
[“minimal_price”]=> string(8) “885.0000”
[“min_price”]=> string(8) “885.0000”
[“max_price”]=> string(8) “885.0000”
[“tier_price”]=> NULL
[“news_from_date”]=> string(19) “2013-03-11 00:00:00”
[“news_to_date”]=> string(19) “2019-03-11 00:00:00”
[“name”]=> string(13) “cba的产品3”
[“url_key”]=> string(5) “cba-3”
[“msrp_enabled”]=> string(1) “2”
[“msrp_display_actual_price_type”]=> string(1) “4”
[“small_image”]=> string(12) “no_selection”
[“thumbnail”]=> string(12) “no_selection”
[“short_description”]=> string(13) “cba的产品3”
[“special_price”]=> NULL
[“msrp”]=> NULL
[“special_from_date”]=> NULL
[“special_to_date”]=> NULL
[“status”]=> string(1) “1”
[“do_not_use_category_id”]=> bool(true)
[“request_path”]=> string(10) “cba-3.html”
[“is_salable”]=> string(1) “1”
[“stock_item”]=> object(Varien_Object)#281 (7)
{
[“_data”:protected]=> array(1)
{
[“is_in_stock”]=> string(1) “1”
}
[“_hasDataChanges”:protected]=> bool(false)
[“_origData”:protected]=> NULL
[“_idFieldName”:protected]=> NULL
[“_isDeleted”:protected]=> bool(false)
[“_oldFieldsMap”:protected]=> array(0) { }
[“_syncFieldsMap”:protected]=> array(0) { }
}
}
[“_hasDataChanges”:protected]=> bool(true)
[“_origData”:protected]=> NULL
[“_idFieldName”:protected]=> string(9) “entity_id”
[“_isDeleted”:protected]=> bool(false)
[“_oldFieldsMap”:protected]=> array(0) { }
[“_syncFieldsMap”:protected]=> array(0) { }
}
*/
}

通过清心醉

Magento重写URL之重建索引

前几天写了个中文URL的插件,包括中文及其他字符允许

比如作者的网店  点击查看MAGENTO之URL

其实重写过后,重新刷新索引或者没用,这时候

用phpmyadmin进入magento数据库

找到core_url_rewrite表段,然后选择”清空”

之后重新在后台进行索引即可!

通过清心醉

Magento 开发实例七(模型Model)资源安装配置

本来先要写数据库的增删改查的,但如果懂PHP的朋友们看了前面的文章,相信都能想到办法了。所以先说说资源的配置问题,下文再写详细的增删改查。

作者提醒:永远不要相信国内搜索的数据,如果真的想认真学开发,好好GOOGLE看看国外正宗的开源教程,或者多看Magento的核心代码的编写规范以及插件的规范。作者就因为误信国内的数据,所以资源配置都得最后来弄。

正文开始:app.tar

Magento都是由配置文件做系统的支撑的。

读取modules所有的模块配置->

读取所有模块里的etc目录里的配置文件(比如config.xml)->

根据etc目录里的配置文件分配路由、资源等(需要的时候调用出来)->

然后就是MVC的访问操作了。就是作者前面几篇文章所说

 

其实,Magento当读取到etc/config.xml文件的时候,会查看有没有setup节点,如果有,执行安装,一般来说都是只执行一次,所以一会我们写的代码里要有中指。

 

首先增加安装配置:

<mymodule_setup>

<setup>

<module>Mage_Mymodule</module>

</setup>

<connection>

<use>core_setup</use>

</connection>

</mymodule_setup>

 

定义个module_setupsetup里直接使用module,表示直接使用模块里的mysql4-install.0.1.0.php文件

 

在这里作者要特别说明下,<setup><module>Mage_Mymodule</module></setup>

看这名字就知道,是项目名/模块(插件名)

至于<connection><use>core_setup</use></connection>

 

我们可以追踪到app/code/core/Mage/Core/Model/Resource/Setup文件

class Mage_Core_Model_Resource_Setup

{

const DEFAULT_SETUP_CONNECTION = ‘core_setup’;

const VERSION_COMPARE_EQUAL = 0;

const VERSION_COMPARE_LOWER = -1;

const VERSION_COMPARE_GREATER = 1;

 

const TYPE_DB_INSTALL = ‘install’;

const TYPE_DB_UPGRADE = ‘upgrade’;

const TYPE_DB_ROLLBACK = ‘rollback’;

const TYPE_DB_UNINSTALL = ‘uninstall’;

const TYPE_DATA_INSTALL = ‘data-install’;

const TYPE_DATA_UPGRADE = ‘data-upgrade’;

………

………

}

一般来说我们是需要配置个类继承该类来进行安装的,但由于作者在<setup>节点里直接使用的是模块的名称而不是<class>(比如配置的Blog就是class),这时候Magento会自动找到sql目录里的mysql4-install.0.1.0.php文件。

 

这要特别说明下的就是

Config.xml里有个配置文件的版本:

<modules>

<Mage_Mymodule>

<version>1.1.1</version>

</Mage_Mymodule>

</modules>

 

但我们mysql4-install.0.1.0文件,是不受那个版本的影响,如果需要默认安装,必须要有mysql4-install.0.1.0.php

 

Mage/Mymodule/sql/mymodule_setup/Mysql4-install.0.1.0.php

#目录里的mymodule_setup是我们前面定义的,可以看config.xml文件

#写入下面的

<?php

echo “类名是:”.get_class($this).”</br>”;

die(“exit”);

 

在这里我们一定要加个die();否则流程走了一次,就不走了哦!

而且后面我们执行有SQL的操作的时候,也加个DIE好点,看数据库里存在数据了再把DIE关闭.

这时候只要一刷新缓存:

2015-05-03

看到了吧,作者没定义任何类,系统自动使用核心的Setup类,就是作者前面说的app/code/core/Mage/Core/Model/Resource/Setup文件。

 

动起来吧:让我们用资源配置来安装数据表/字段并且写入数据:

首先我们要确保数据库里没有blog表哦

2015-05-03-01

修改mysql4-install-0.1.0.php

#注:请保留die(“exit”);

 

<?php

echo “类名是:”.get_class($this).”</br>”;

$installer=$this; #把类重新赋值,也可以直接使用$this,这不是强制的,但只是命名规范而已

$installer->startSetup(); #启动安装方法,可以在app/code/core/Mage/Core/Model/Resource/Setup里查看到

$table=$installer->getTable(‘mymodule/blog’);#添加表名称,如果有前缀,会自动增加哦.

$sql=”CREATE TABLE $table(id int primary key auto_increment,name varchar(128),phone varchar(128))”;

$intosql=”INSERT INTO $table(name,phone)VALUES(‘qingxinzui’,’13823819185′)”;

$installer->run($sql);

$installer->run(intosql);

$installer->endSetup();

die(“安装成功!”);

 

然后我们刷新下页面

 

类名是:Mage_Core_Model_Resource_Setup
安装成功!

 

看看MYSQL里吧

是不是已经有了你想要的表和字段内容了?

 

这时候我们就可以把die(“安装成功!”);取消掉了

同时删除magento数据库里的blog表和字段

重新走一遍。

 

如果你是和作者一样的走法你会发现,刷新后,直接返回主页了,其实是因为数据已经写入成功,已经没有DIE中止了。

这时候再看数据库里,blog表和字段内容都存在的。

资源配置安装完成。

 

如果我们需要升级

修改config.xml文件里的版本号

比如作者修改为1.1.2

然后创建个mysql4-upgrade-1.1.1-1.1.2.php

 

这有些会迷惑的,我们一开始安装的时候文件名是mysql4-install-0.1.0.php

怎么这是1.1.1

0.1.0是默认安装,当写入到数据库之后(可以在core_resource看)版本实际是以config.xml里的<version>写入的

所以我们要针对当前的<version>来进行命名升级

 

mysql4-upgrade-1.1.1-1.1.2.php文件写入:

 

<?php

echo “类名是:”.get_class($this).”</br>”;

$installer=$this; #把类重新赋值,也可以直接使用$this,这不是强制的,但只是命名规范而已

$installer->startSetup();

$table=$installer->getTable(‘mymodule/blog’);

$intosql=”INSERT INTO $table(name,phone)VALUES(‘qingxinzui1′,’13823819185’)”;

$installer->run($intosql);

$installer->endSetup();

die(“安装成功!”);

 

我们一样加个die看是否有写入

如果blog表里多一行数据,说明成功。

这时候我们在关闭DIE,让系统再执行一次,如此一来我们应该有3行数据了。

 

以后我们需要再进行升级模块(插件)

只需要看config.xml里的配置文件的<version>是多少

然后在模块(插件)的sql目录里创建对应的文件

mysql4-upgrade-<version>-新的<version>.php

如:mysql4-upgrade-1.1.1-1.1.2.php

这时候别忘记了把config.xml里的也修改成1.1.2

现在的版本你要不确定可以core_resource表里看。

 

通过清心醉

Magento 开发实例六(模型Model)通过Block(块)功能提取所有数据

需要学习的下载看:app.tar

回顾上文的具体流程:

URL触发控制器-> 控制器如果有执行布局-> 触发布局type里的Block(块功能)-> 系统实例化Block块类-> 调用Block块里面的类方法(需要在视图里调用方法,所以作者直接用构造方法)-> 类方法里进行SQL写入-> 视图输出

 

如果要进行所有数据返回到数据集,Magento提供了getCollection()的方法,因此我们需要配置getCollection()的配置项来配置模型集合。

 

作者的是以blog做为表,在每个模型配置/实例化类中都有指定mymodule/blog

 

每个模型都有一个“protected属性“_resourceCollectionName,该值是从父类“Mage_Core_Model_Abstract继承来的。这个属性的值是这个模型对应的模型集合的URI

protected ‘_resourceCollectionName’ => string ‘mymodule/blog_collection’

 

更多具体的我们可以:

$data1=Mage::getModel(‘mymodule/blog’);

var_dump($data); #打印数组就可以看到protected ‘_resourceCollectionName’ =>

 

在默认情况下,这个值是模型的URI加上“_collectionMagento把模型集合也看做是一种资源(Resrouce),所以运用资源模型的命名规则,模型集合的全名是

我们追踪config.xml,看看我们的配置

<global><models><mymodule_resource> 在资源配置里,我们可以看到我们定于的资源类<class>Mage_Mymodule_Model_Resource

 

Mage_Mymodule_Model_Resource_Blog_Collection

#因为我们是在Blog模型资源下

然后我们要创建如下文件

class Mage_Mymodule_Model_Resource_Blog_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract{

protected function _construct()

{

$this->_init(‘mymodule/blog’);

}

}

 

在这说下,如果是继承,可以查看核心代码的目录

 

好了,同样,我们在mymodule/index/index视图里增加个调用表单,用于输出blog表里的全部数据,增加个触发URL

<a href=<?php echo $this->getUrl(‘mymodule/blog/blogsql’); ?>查看全部的blog数据</a>

 

这时候,Blog执行控制器我们需要写多个blogsql的代码:

function blogsqlAction()

{

$this->loadLayout();

$this->renderLayout();

}

直接引用布局,我们来增加布局配置:local.xml

<mymodule_blog_blogsql>

<reference name=”root”>

<block type=”mymodule/blogsql” name=”root” output=”toHtml” template=”mymodule/blogsql.phtml”/>

</reference>

</mymodule_blog_blogsql>

 

Block()里增加个Blogsql的方法:

 

class Mage_Mymodule_Block_Blogsql extends Mage_Core_Block_Template

{

protected $data;

function __construct()

{

$this->data=Mage::getModel(‘mymodule/blog’)->getCollection(); #实例模型全部资源

return $this->data; #返回的模型的值,给视图直接调用

}

}

 

 

 

已经实现了我们需要的,然后我们在视图里操作输出吧:

 

 

 

Blogsql.phtml文件里:

 

 

 

blogsql的视图:</br>

 

<?php

 

$o=0;

 

foreach($this->data as $blog)

 

{

 

echo “编号:”.$o++.”名字:”.$blog->getName().”-电话“.$blog->getPhone().”</br>”;

 

}

?>

 如果我们需要之需要获取全部数据集中的name

可以用:$this->data=Mage::getModel(‘mymodule/blog’)->getCollection()->addAttributeToSelect(‘name’);

 

 

通过清心醉

Magento 开发实例五(模型Model)通过Block(块)功能操作数据库

需要的可以下载来看和测试!app.tar

接开发实例四,上文作者是直接在控制器里进行SQL的写入操作,如此以来,我想在视图里显示我写入的数据是什么(即$_POST过来的数据),就不能直接引用了。

这时候,我们可以利用MagentoBlock()功能来实现:

上文说了,在Blog控制器里增加个ceshiAction的方法

 

首先嘛肯定也要写个触发入口,作者还是选择用mymodule/index/index模板里增加个表单

提交到/mymodule/blog/ceshi

#index.phtml文件里:

传递到测试表单->控制器->布局->通过Block引用->视图调用显示

<form action=”<?php echo $this->getUrl(‘mymodule/blog/ceshi’); ?>” method=”post”>

<p>名字::<input type=”text” name=”name” /></p>

<p>电话::<input type=”text” name=”phone” /></p>

<input type=”submit” name=”添加” />

</form>

 

然后我们来写下blog控制器的ceshiAction方法

function ceshiAction() #引用Block

{

#首先我们在index.phtml视图里增加另外一个表单,把值传到这里来

#首先我们调用布局

$this->loadLayout();

$this->renderLayout();

#我们要注意布局里的写法. 跟踪到local.xml文件

}

 

local.xml布局里我们写多个新的节点

<mymodule_blog_ceshi>

<reference name=”root”>

<block type=”mymodule/ceshi” name=”root” output=”toHtml” template=”mymodule/ceshi.phtml”/>

</reference>

</mymodule_blog_ceshi>

 

在这里可能注意到了一个type=”mymodule/ceshi” ,这是一个URI

根据Block块的功能,我们需要在config.xml里定义

<blocks>

<mymodule>>

<class>Mage_Mymodule_Block</class>

</mymodule>

</blocks>

Model的定义一样,这里到时会定义到一个类

App/code/local/Mage/Mymodule/Block里创建个Ceshi.php文件

也许你会问,为什么要定义Ceshi.php文件,系统是怎么知道该类文件的存在。

type=”mymodule/ceshi”的完整URI是:/mage/mymodule/block/ceshi.php

所以class里那么写就好了。

Ceshi.php文件里这么写::

class Mage_Mymodule_Block_Ceshi extends Mage_Core_Block_Template

{

#和模型/控制器一样的,命名规则注意下,这里我是继承Mage_Core_Block_里的Template

#其实还有很多种,方式不同,看需求来继承使用。

}

 

定义好了Block()之后,我们来弄多个template=”mymodule/ceshi.phtml”视图模板

内容先不加。

 

正式开始走流程了:

<form action=”<?php echo $this->getUrl(‘mymodule/blog/ceshi’); ?>” method=”post”>

这里我们表单会把数据提交到ceshiAction()的方法中

我们在方法里直接调用了布局,根本未进行任何操作。但是因为布局local.xml里我们有定义type=”mymodule/ceshi”,而且config.xml里又有类定义

所以这时候其实就会跑到

Mage/Mymodule/Block/Ceshi.php文件里

class Mage_Mymodule_Block_Ceshi extends Mage_Core_Block_Template

{

/*

class Mage_Page_Block_Html extends Mage_Core_Block_Template

#块类的定义必须继承Mage_Core_Block

#同时注意类名的写法

#项目名_模块(插件)_Block_目录/文件

*/

protected $data;

 

function __construct()

{

$this->data=$this->getRequest()->getPost(); #获取POST过来的数据

#echo $this->data[‘name’].”</br>”.$this->data[‘phone’];

$blog=Mage::getModel(‘mymodule/blog’); #实例模型

$blog->setName($this->data[‘name’]); #name字段的值

$blog->setPhone($this->data[‘phone’]); #phone字段的值

$blog->save(); #如果写入成功

return $this->data; #返回的值包括这里的全部方法,都可以直接给模板调用哦

}

}

 

作者使用构造方法来实现,其实在这里可以进行判断如果数据写入失败和成功又如何调用,为走流程,更深的得慢慢研究就先放着了。

到这里,布局文件type=”mymodule/ceshi”里的流程我们走完了,接下来就是要看视图了

template=”mymodule/ceshi.phtml”

<?php

echo “您写入的用户名为:”.$this->data[‘name’].”</br>”.”您写入的电话号码为:”.$this->data[‘phone’];

?>

 

搞定,一个简单的Block()操作完成

 

具体是:

触发控制器->

控制器如果有执行布局->

触发布局type里的Block(快功能)->

系统实例化Block块类->

调用Block块里面的类方法(需要在视图里调用方法,所以作者直接用构造方法)->

类方法里进行SQL写入->

视图输出

通过清心醉

Magento 开发实例四(模型Model)通过表单添加数据

:项目名称由Qxz改为Mage

前面说了我们可以通过页面ID获取数据,对于对SQLModel操作,最重要的莫过于增删改查了。由于资源配置的失败,导致无法进行EAV的测试。作者以基础模型来例来实现点增删改查。

基本模型操作

所有的模型最终都继承自类Varien_Object”。这个类属于Magento的系统类库,不属于Magento的核心模块。你可以在以下位置找到这个类

lib/Varien/Object.php

Varien_Object”也实现了一些PHP的特殊函数,比如神奇的__call”。你可以对任何一个属性调用get, set, unset, has”方法(比如我们要调用表内的ID字段)

$blog->getId();

$blog->setId(1);

$blog->unsetId();

if($blog->hasId()){}

 

为了有效的利用这些方便的方法,我们在定义数据表列名的时候要用小写,并用下划线作为分隔符,比如id”。在最近的Magento版本中,这个规则已经被弱化,为了实现PHPArrayAccess”接口

$id=$blog->[‘id’];

$blog->[‘id’]=25;

//etc…

 

 

Magento模型的数据保存在_data”属性中,这个属性是protected”修饰的。父类Varian_Object”定义了一些函数用来取出这些数据。

 

前一篇说模型基础的时候,作者使用了$blog->getData();

当然也可以$blog->getData(‘name’);来获取指定idname的值

 

然后说说适配器,也就是实现读写分里

 

例子中,我们已经可以从数据库中取数据了,但是我们却没有为资源模型设置读写适配器,怎么回事呢?原因很简单,那就是因为Magento会为没有适配器的资源模型启用默认适配器。我们也可以显式的配置默认的适配器

<resources>

<mymodule_write>

<connection>

<use>core_write</use>

</connection>

</mymodule_write>

<mymodule_read>

<connection>

<use>core_read</use>

</connection>

</mymodule_read>

</resources>

#如果有配置资源,也写在<resources></resource>节点里。

我们看到有两个新的标签节点:mymodule_writemymodule_read一个读,一个写。

 

我们来给Blog执行控制器增加inster的方法来尝试写入数据库:。

首先说说我们用SQL命令创建的表

包含3个字段

ID(自增)产品品种,name,phone 在这里ID因为是自增的关系,所以不需要进行写入数据:

我们再看看inster的方法:

$blog=Mage::getModel(‘mymodule/blog’); #实例模型

$blog->setName(‘电话号码‘); #name字段的值

$blog->setPhone(‘13823811’); #phone字段的值

$blog->save(); #写入

echo “数据写入完成!”;

#请确保页面是UTF-8格式,否则写入乱码!

 

这些,对数据的增加我们就有一定的了解了吧。

我们在修改Index控制器的表单,自己创建个表单,然后数据交给Blog控制器的forminster()方法

class Mage_Mymodule_IndexController extends Mage_Core_Controller_Front_Action

{

public function indexAction() #默认方法

{

$this->loadLayout();

$this->renderLayout();

}

Index控制器里我们直接调用布局了,所以我们直接修改布局吧

 

跟踪mymodule_index布局文件

<mymodule_index_index>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/index.phtml”/>

</reference>

</mymodule_index_index>

可以看到我们使用的模板是index.phtml,直接在这里加个表单吧(template)目录里

 

<form action=”<?php echo $this->getUrl(‘mymodule/blog/forminster’); ?>” method=”post”>

<p>名字::<input type=”text” name=”name” /></p>

<p>电话::<input type=”text” name=”phone” /></p>

<input type=”submit” name=”添加” />

</form>

在这里,我们form表单提交的URL已经很明显了

提交到mymodule模块的blog控制器里的forminster方法中

 

function forminsterAction() #表单POST调用写入数据

{

#在这就不对数据进行是否空值等判断了

$data=$this->getRequest()->getPost(); #获取POST过来的数据

#注意到了这里是数组了哦

#echo $data[‘name’].”</br>”.$data[‘phone’];

$blog=Mage::getModel(‘mymodule/blog’); #实例模型

$blog->setName($data[‘name’]); #name字段的值

$blog->setPhone($data[‘phone’]); #phone字段的值

if($blog->save()) #如果写入成功

{

#调用布局

$this->loadLayout();

$this->renderLayout();

#这时候我们需要给该方法写个布局,local.xml里增加个

/*在这里我们调用的视图里,只是提示写入数据成功并且输入的参数

要么在视图里实例Model,直接视图里操作,不过这就不符合MVC.

为此我们新创建一个ceshiAction()的方法,下一次会讲解。

*/

}

else

{

echo “error_forminsterAction”;

}

}

 

这样就可以写入了。当然这是没有进行数据判断的,save()的方法是否安全也要看下核心源码,还有一个是作者的phone字段用的是int(16),测试的时候别写太长或者修改为text吧。

 

save()用于新增和修改数据

如果我们需要修改

上面加多个

$blog->load(‘主键值);

所以接下来我们就要修改数据了。前面插入和提取数据我们可以看出问题点:都是对单一的操作。如果要修改数据,那么肯定是要先获取表内指定的数据。

以往的mysql的操作都是读取数据集,在通过fro等方式进行循环输出数据,进行修改。

 

因为我们的字段只有id(自增、主键),namephone

所以我们要提取全部的name,phone进行修改,form_insterAction()的方法已经很清楚的告诉我们获取POST数据来写入,上文作者说的提取,是根据指定ID

 

如果我们在方法里加多个

 

$data=$this->getRequest()->getPost(); #获取POST过来的数据

 

#注意到了这里是数组了哦

 

#echo $data[‘name’].”</br>”.$data[‘phone’];

 

$blog=Mage::getModel(‘mymodule/blog’); #实例模型

 

#$blog->load(1); #修改主键为1

 

$blog->setName($data[‘name’]); #name字段的值

 

$blog->setPhone($data[‘phone’]); #phone字段的值

 

 

 

如果我们使用了blog->load(1)的话,就是指定修改主键id=1的了,因此我们需要通过循环提取数据集,POST多个隐藏的主键ID过来(为什么说隐藏,因为ID一般我们都不进行输出的)

 

 

 

到此为止,一个写入数据库的表单操作就这么完成了。

 

现在还有一个问题:

 

如果在控制器中执行了SQL的操作,比如文中的添加的namephone

 

我想在视图里调用出来,又该如何操作呢?

 

这几天在进行资源配置安装因为老出错,所以浪费了些时间

 

需要在视图进行调用的话,就需要使用Block的块功能了,具体的下文分享!