Magento PATCH_SUPEE-11085 get Fatal error: Can’t use method return value in write context in /app/code/core/Mage/Authorizenet/Model/Directpost.php on line 391

Note:这篇文章的解决对象是PHP 5.5 以下版本的magento 报错,如果不是PHP 5.5以下版本,可能帮不到你。我使用的是1.9版本的Magento

PATCH_SUPEE-11085 主要是Magento 应对Authrize 变更key的加密类型,Pacth在SSH很好打。但是在后台创建订单时会像文章标体那样报错。

主要问题点是 PHP 5.5以下版本empty() 函数不能检查变量。

所以把line 391代码修改来适配

$response_data = $response->getData('x_SHA2_Hash'); //rewrite for PHP 5.5 lower BY Burt
  $hashConfigKey = !empty($response_data) ? 'signature_key' : 'trans_md5';

主要参考资料

stock flow

Magento Guide Authorize key

宝塔面板安装godaddy 证书

步骤一,生成CSR 和私钥

https://www.chinassl.net/ssltools/generator-csr.html

当然有其他家都可以,这一步得到CSR和密钥,就是宝塔证书的左栏( 密钥(KEY) )

步骤二,拿着CSR去godaddy 申请证书(如果你域名在godaddy上就不用这样,直接就生成了)

步骤三,下载证书crt文件,选择是一串数字和字母的,不要包含bundle字样的,编辑代码,获取就是 宝塔右栏( 证书(PEM格式) )

最后,保存生效就可以了

参看链接:

https://www.bt.cn/bbs/forum.php?mod=viewthread&tid=704&highlight=ssl%E8%AF%81%E4%B9%A6

Magento的订单状态,Magento Order Status 与 Magento Order State的区别和联系

 

Magento的订单状态,在后台一般现实的是 Order Status ,但是在数据库 sales_flat_order 表里却有两个字段 state 和status,而且两者有高重复度的值。到底两者有什么区别和联系?虽然很基础,但很多次会被困扰,准备一次讲清楚。

先讲state(可翻译成,状态/国家/州):

1.可用值包含 new, processing, complete, holded, closed, canceled 等

一般不可以自定义

2.用于订单内部处理 internally .

3.一个state【订单州】可以有很多个status【订单地位】.

 

再说status(可翻译成,状态/地位):

1.显示为Processing ,Pending ,Payment Suspected Fraud ,Payment Review Pending ,On Hold ,Complete ,Closed ,Canceled ,Pending PayPal

2.字段值可以自己定义的,System –> Order Statuses,可以创建新的【订单地位】,并和【订单州】关联

order status processing
order status的变化

 

 

参考链接

https://magento.stackexchange.com/questions/515/what-are-the-definitions-of-the-order-statuses-or-where-should-i-integrate-my/516

https://www.magestore.com/manage-magento-online-store/magento-order-status-and-magento-order-state

https://docs.magento.com/m1/ce/user_guide/order-processing/order-status.html

Magento: Difference between order states and statuses

 

贝塔斯曼数据奖学金-Python部分-1

统计学理论学完后,就到了技术部分,包含Python和SQL(使用的是Postgre)

今天先回顾学过的Python部分:

1.Data Types And Operators数据类型和操作符

首先学的是操作符,简单的加减乘除就和普通一样,比较特殊的是

** 求幂运算,简单来说就是次方,3的6次方 3**6

// 向下整数除法 7//2 =3   -7//2=-4

% 求余数

负值是等号,==是判断是否相等

+= -= *=

 

整数和浮点数

type() 检查参数类型

int(49.7) =49 直接舍去

 

报错会有两种 Exception 和error

exception是运行时报错

error是运行前,检查出来的错误。

 

布尔值true false、逻辑运算and or not


接下来是比较重要的难点

字符串string、列表list、元组tuples、set集合、字典 dictionary

Data Structure Ordered Mutable Constructor Example
int NA NA int() 5
float NA NA float() 6.5
string Yes No ' ' or " " or str() “this is a string”
bool NA NA NA True or False
list Yes Yes [ ] or list() [5, ‘yes’, 5.7]
tuple Yes No ( ) or tuple() (5, ‘yes’, 5.7)
set No Yes { } or set() {5, ‘yes’, 5.7}
dictionary No Keys: No { } or dict() {‘Jun’:75, ‘Jul’:89}

字符串:有序,不可修改

单引号来包含双引号

\ 来转义

+ 来合并字符串,*来复制,没有减法和除法

len()/format()

a.count(b)/a.find(b)


list列表 可排序可改变,使用广泛

names = [“Carol”, “Albert”, “Ben”, “Donna”]

names[0]第一个 ;names[-1]最后一个,[len(string)-1]

month[6:9]  7-9月份,不包含上限。

[:6]前6个元素,不包含7

in 和not in判断

max() 最大的int,字符串首字母靠后的,多重type无法比较-min()

sorted()从下到大排序

sorted(list,reverse=True)从大到小排序

“-“.join(list)连接字符串

b.append(‘one’)添加到列表末尾 直接使用

b=names.pop(1) 提出第二个元素


元组Tuples 包含不可变 有序的数据结构,括号可选

没有append和pop方法

tup1[0] 方括号索引查找

内置4个函数,cmp比较两个元组,max,min和tuple(listname)转化

location = (13.4125, 103.866667)
print("Latitude:", location[0])
print("Longitude:", location[1])

元组解包,就是把元组内的参数赋值,下方第二行就是解包

dimensions = 52, 40, 100
length, width, height = dimensions
print("The dimensions are {} x {} x {}".format(length, width, height))

也可以写成

length, width, height = 52, 40, 100
print("The dimensions are {} x {} x {}".format(length, width, height))

set 集合 包含唯一元素 且 顺序不定,可以修改

scores=[‘4′,’5′,’6′,’9’]

可以由list生成 set(listname)

set.add(‘newone’)添加元素 没有append() 随机添加到一个位置

set.pop()随机删除一个元素


dictionary 字典 存储的是元素对 key:value,数组的概念

key可以是int string float 不可变的值且统一

elements = {“hydrogen”: 1, “helium”: 2, “carbon”: 6}

print(elements[“helium”])

添加就直接添加 elements[“lithium”] = 3

“some” in elements 检查是否存在于字典

elements .get(“some”) 比直接方括号elements.[“some”]要安全,不存咋的话,也只返回None而不是报错

还可以设置成elements .get(“some”,”There\`s no such key”)来自定义返回语句


Compound Data Structures 应该是python的多维数组

elements = {"hydrogen": {"number": 1,
                         "weight": 1.00794,
                         "symbol": "H"},
              "helium": {"number": 2,
                         "weight": 4.002602,
                         "symbol": "He"}}

hydrogen_weight = elements[“hydrogen”][“weight”]

 



控制流 control flow

IF ELIF ELSE

注意冒号和缩进。

points = 174

points = 174  # use this input when submitting your answer

# set prize to default value of None
prize = None

# use the value of points to assign prize to the correct prize name
if points <= 50:
    prize = "wooden rabbit"
elif 151 <= points <= 180:
    prize = "wafer-thin mint"
elif points >= 181:
    prize = "penguin"

# use the truth value of prize to assign result to the correct message
if prize:
    result = "Congratulations! You won a {}!".format(prize)
else:
    result = "Oh dear, no prize this time."

print(result)

 


循环 loop

for和while的使用

usernames = ["Joey Tribbiani", "Monica Geller", "Chandler Bing", "Phoebe Buffay"]

for i in range(len(usernames)):
    usernames[i] = usernames[i].lower().replace(" ", "_")

print(usernames)

while求阶乘

# Start with a sample number for first test - change this when testing your code more!
number = 6   
# We'll always start with our product equal to the number
product = number

# Write while loop header line - how will you tell it when to stop looping?
while  number > 1:
    # Each time through the loop, what do we want to do to our number?
    number -= 1
    # Each time, what do we want to multiply the current product by?
    product *= number
# Print out final product (how do we indicate this should happen after loop ends?)
print(product)

for的方式

# This is the number we'll find the factorial of - change it to test your code!
number = 6
# We'll start with the product equal to the number
product = number

# Write a for loop that calculates the factorial of our number 
for num in range(1, number):
    product *= num

# print the factorial of your number
print(product)

range函数,使用此函数得到list的索引

range(start,stop,step) start 和step默认是1

range(5)只有一个整数时,是stop的值 ,0-4

range(2,10) 是start =2 和stop=10 step默认为1, 2~8

迭代字典

fruit_count, not_fruit_count = 0, 0
basket_items = {'apples': 4, 'oranges': 19, 'kites': 3, 'sandwiches': 8}
fruits = ['apples', 'oranges', 'pears', 'peaches', 'grapes', 'bananas']

#Iterate through the dictionary
for fruit, count in basket_items.items():
    if fruit in fruits:
       fruit_count += count
    else:
        not_fruit_count += count

print("The number of fruits is {}.  There are {} items that are not fruits.".format(fruit_count, not_fruit_count))

 

while 是条件为真时继续运行

card_deck = [4, 11, 8, 5, 13, 2, 8, 10]
hand = []

# adds the last element of the card_deck list to the hand list
# until the values in hand add up to 17 or more
while sum(hand)  < 17:
    hand.append(card_deck.pop())
limit = 40

num = 0
while (num+1)**2 < limit:
    num += 1
nearest_square = num**2

print(nearest_square)

break 和 continue

break终止并跳出循环

continue 跳过本次迭代,而不完全跳出循环

headlines = ["Local Bear Eaten by Man",
             "Legislature Announces New Laws",
             "Peasant Discovers Violence Inherent in System",
             "Cat Rescues Fireman Stuck in Tree",
             "Brave Knight Runs Away",
             "Papperbok Review: Totally Triffic"]

news_ticker = ""
for headline in headlines:
    news_ticker += headline + " "
    if len(news_ticker) >= 140:
        news_ticker = news_ticker[:140]
        break

print(news_ticker)

zip and enumerate 打包和枚举

打包可简单理解成多个list拼成字典

x_coord = [23, 53, 2, -12, 95, 103, 14, -5]
y_coord = [677, 233, 405, 433, 905, 376, 432, 445]
z_coord = [4, 16, -6, -42, 3, -6, 23, -1]
labels = ["F", "J", "A", "Q", "Y", "B", "W", "X"]

points = []
for point in zip(labels, x_coord, y_coord, z_coord):
    points.append("{}: {}, {}, {}".format(*point))

for point in points:
    print(point)

 

cast_names = ["Barney", "Robin", "Ted", "Lily", "Marshall"]
cast_heights = [72, 68, 72, 66, 76]

cast = dict(zip(cast_names, cast_heights))
print(cast)
{'Lily': 66, 'Barney': 72, 'Marshall': 76, 'Ted': 72, 'Robin': 68}

 

枚举 Enumerate

cast = ["Barney Stinson", "Robin Scherbatsky", "Ted Mosby", "Lily Aldrin", "Marshall Eriksen"]
heights = [72, 68, 72, 66, 76]

for i, character in enumerate(cast):
    cast[i] = character + " " + str(heights[i])

print(cast)

 

['Barney Stinson 72', 'Robin Scherbatsky 68', 'Ted Mosby 72', 'Lily Aldrin 66', 'Marshall Eriksen 76']

List Comprehensions 列表推导

应该理解成对list的筛选

multiples_3 = [x * 3 for x in range(1, 21)]
print(multiples_3)
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60]

贝塔斯曼数据奖学金-理论知识总结

上周完成了数据分离理论部分的学习。

这么晚才更新,一方面是想通读之后,可以总揽的角度去看学过的知识。在学生时代一位记忆中的老师也是这样教导:遇到学不懂的先不着急,硬着头皮继续往下学,有时候慢慢前面不懂的知识同了。对于这个课程也是如此,通读下来前后连贯起来,就容易明白了。比如,方差部分,讲师说正负一个标准差所覆盖的部分是68%,两个则是95%。当时听的一脸懵逼,但是就这么硬记着,后面看到Z表的时候就明白了。

第二个,也许是因为懒。

身在国内,只有论坛一种官方方式可以参与互动,当然还有微信群。

转回正题,第一部分 理论知识包含七大专题,依次是1.Intro to Research Methods(研究方法的介绍)2.Visualizing Data(数据的可视化)3.Central Tendency(集中趋势)4.Variability(可变性) 5.Standardizing(标准化) 6.Normal Distribution(正态分布)7.Sampling Distributions(抽样分布)。


第一部分 Visualizing Data(数据的可视化)

学习了数据分析的基本知识(statistical research methods),有两个概念比较重要和新鲜


1.Constructs 中文我自己翻译成构念 或者构造,也就是一些虚拟,需要测量的一些属性,而且还不是特别确定的,比如幸福,痒,心理压力,智商等

2.Operational Definition,定义操作,也就是测量measures constructs的方法。

比如IQ分数,几加仑的汽油,用美元表示的年薪。

 

比较有趣的知识点,是国外科学家早期对随机radomness的定义:

雨点落在一张纸上的位置。

 

二象限,x表示自变量 independent,y轴因变量 dependent variable

 

让我印象深刻的是 金拱门理论 ,对就是麦当劳的那个金拱门,都有麦当劳的两个国家都没有开战过。引导出一个统计学的名言:相关不代表因果(correlation dose not prove causation)。毕竟中日也都有麦当劳嘛。

 

还有一些安慰剂placebo实验,等是在控制变量Controlled Factors。


2.Visualizing Data(数据的可视化)主要学习直方图 Histogram,柱状图Bar Graphs和倾斜分布Skewed Distribution。

直方图很好理解,平时接触的也很多。柱状图有几个特点,柱状图的x轴是分类或者定型,顺序没那么重要。比如柱状图表示大洲统计的结果,不同的品牌,男或女。直方图的x周则是数字化的。

倾斜分布Skewed Distribution分为两种:Positively和Negatively。积极的是前一部分分布的多,消极的是后面部分分布的多。


3.Central Tendency(集中趋势)主要学习3M:众数Mode,中值Median和平均值Mean。

结合第二课的倾斜分布和3M,有一个很好的图去记忆和熟悉。

skew

众数:可以有多个,也可能没有(uniform分布的时候,基本是同等高度),没有计算公式,不是每一个值都影响众数。会跟着binsize 变化。

平均数,有计算公式,受极值的影响。偶数时,最中间的两个数取平均值

让我记忆比较深的是UNC大学因为乔丹,那一年的平均工资很高。

中值,也就是中位数,有公式,而且分奇数和偶数的不同符号公式,比不是严格意义的公式。

Median

3M间的对比

mode median mean


4.Variability(可变性) 主要学习计算标准方差 standard deviation SD。

第4课也是第一部分的分水岭,4-7课都是围绕方差展开。

学到如何判断异常值,根据IQR: interquartilerange 四分位距 Q3-Q1,Q2就是中值Median

<Q1-1.5xIQR 和 >Q3+1.5xIQR

平方差的和叫做SS:sum of squares   ∑(Xi – μ)^2

平方差的平均数 ASS

方差 variace =ASS

标准方差 standard deviation SD -对ASS 求根 ,用σ表示

 

贝塞尔校正系数 Bessel’s Correction(抽样低估了总体的多样性)

利用n-1作为分母来调整。

Bessel's Correction


5.Standardizing(标准化)

主要是计算分布中特定值的z值:与平均值的差值,按多少个方差计算

z=(Xi-μ)/σ  可以为负值。

查询Z表,下一章可以求出所占比率


6.Normal Distribution(正态分布)

主要讨论的是,z和p的关系。

PDF 概率密度函数 曲线下的面积代表概率。

z-table 假设标准化后的分布是正态分布。

z和p的对应,链接 先算z再查p


7.Sampling Distributions(抽样分布)

主要是探讨分组多次取样和总体的关系。

M 样本平均数的平均值。和总体的平均数相等,M=μ

SE 标准差,样本平均数的标准差,SE=σ/√n

我自己想到一个例子,比如我想知道小区居民的平均数,大家又不是同时在家,可以一起统计,那么想到一个方法是,在保安亭,每次统计10个人,早中午各一次,连续三十天(或者更长时间),那么所得10人一组的平均值,加总再计算平均值,得到M就和总体大家平均年龄很相近。得出SE也可以倒推总体标准差。

中心极限定理 The Central Limit Theorem

 

SE中,n扩大4倍,标准误差会减半。

抽样样本的Z值

Z=(Xi – M)/SE

然后可以一样算出P值,算所占比例



总结

第五章Standardizing(标准化) 学的比较欠缺。

前三个章节,没有问题,最后两个章节也已经完全掌握。

奖学金计划3.2-3.4小结

课程的3.2-3.4主要内容:

3.2 以考试和考试前的准备为例,引出调查方法:

  1. 调查多少人
  2. 调查哪些人
  3. 调查的方法

3.3 探如何测量记忆力:

背诵单词数目?最强大脑那些?或者是智商。这个是开放的回答,没有标准答案。

3.4 标题是定义结构

在接头采访行人,如何定义幸福、如何测量幸福、如何定义记忆力、如何测量痒的程度、如何测量人感受到压力?

我觉得有几个人回答的很好:可以用笑的次数测量幸福,用抓痒的次数来定义痒的程度,用血压的高低来测量人感受的压力。

贝塔斯曼数据奖学金-介绍

很荣幸,能入选贝塔斯曼数据分析奖学金计划,琐事较多,直到今天才开始正式的学习,感谢Udacity和贝塔斯曼的支持。

第一篇,课程介绍:

CORE CONTENT: Descriptive Statistics

The next set of lessons cover descriptive statistics and is the CORE CONTENT in this challenge course. You are expected to work through this content well within your 3 month timeline.

Don’t forget, your performance in the course, in addition to your participation in the forums and Slack community will be factors that contribute to the selection of the top students who will be given scholarships to the Data Foundations, Data Analyst, or Business Analyst Nanodegree programs!

核心内容:描述性统计
下一组课程涵盖描述性统计,是本次挑战课程的核心内容。你希望在3个月的时间内完成这个内容。

别忘了,你在课程中的表现,除了你参加论坛和懒散社区之外,还有助于选拔那些将给奖学金基金会、数据分析员或商业分析员纳米学位课程的奖学金的优秀学生。

 

Key Concepts

This course will teach you the basic terms and concepts in statistics as well as guide you through introductory probability.

You will learn how to….

  • Use statistical research methods.
  • Compute and interpret values like: Mean, Median, Mode, Sample, Population, and Standard Deviation.
  • Compute simple probabilities.
  • Explore data through the use of bar graphs, histograms, box plots, and other common visualizations.
  • Investigate distributions and understand a distributions properties.
  • Manipulate distributions to make probabilistic predictions on data.

关键概念
本课程将教你统计学中的基本术语和概念,并指导你介绍概率。

你将学会如何…

采用统计研究方法。
计算和解释值:均值、中值、模式、样本、人口和标准偏差。
计算简单概率。
通过使用条形图、直方图、方框图和其他常见的可视化来探索数据。
研究分布和理解分布特性。
操纵分布以对数据进行概率预测。

Magento CAPTCHA not show image backend and frontend 验证码不显示1.x版本

最近,Magento官方给出防止暴力破解安全防范意见:

全文连接在此

主要操作包括修改后台管理地址、限制登录错误次数、CAPTCHA、开启安全扫描、两步验证等(个人建议应该加上:使用更强壮的管理员密码)

关于CAPTCHA,以前就遇到过设置了,但是前台或者后台验证码图片并不显示的问题,但是不是必选项,没有深入的了解过。

【对了,如果不熟悉怎么设置CAPTCHA 可以点击这个连接(1.x版本,留意关于contact部分因为市场已经改版,所以失效)来了解如何操作】

简单来说就是文件权限问题。/media/captcha 这个文件夹(里面还有admin和base两个子文件夹)需要有读写权限。修改成775一般就可以了。我直接在FTP里修改还不成功,需要重命名后手动创建。这样前台就可以正常显示了。

终究来说,还是主机没有一个很好的config来适配Magento。

问题到此解决,如果没有办法直接访问FTP修改权限,网络也提供了数据库关闭此项设置的mysql语句:

Update 
  core_config_data  set value=0
WHERE  path LIKE  '%admin/captcha/enable%'

来自 stackflow

这样,你至少还可以继续登录后台。

 

喜乐打赏

中文翻译Custom Magento System Configuration

这是Alan 一个系类中的一篇文章(2010年2月28),翻译成中文,方便自己方便后来的人。很多地方翻译的不是很好,还有很多地方需要后面优化。

原文地址

One of the more powerful parts of the Magento eCommerce System is the Admin’s System Config section. As a developer, it will allow you to quickly and easily setup forms elements that allow your end-users to configure their Magento System and your custom modules.

管理员系统设置 部分是Magento 系统最有权利的部分。作为一个开发者,在这个部分允许你快速方便地设置表单元素,以便终端使用着配置他们的Magento 系统模块和自定义的模块。

Like a lot of things in Magento, it can be intimidating the first time you attempt to setup a new configuration section from scratch, but once you’ve done it once the power of (nearly) code-less forms will become addictive. Let’s get started.

像Magento 里的其他事情一样,第一次尝试从头去配置一个新的设置部分会被吓到,但是你一旦掌握的了如何使用它你会喜欢上这些,开始吧。

We’ll be building off the module we created in the Magento Controller Dispatch and Hello World article, although any empty module should suffice. The impatient can download the complete module for this article here.

我们将在上面连接文章里的模块里创建,或者一个空白的模块也可以。如果不耐烦可以点击上面下载这篇文章的完整模块

The following is part of a longer series about Magento aimed at developers familiar with PHP MVC development. While each article can be read stand alone, each article does build on concepts and code covered in previous articles. If you’re confused, be sure to catch up on the older stuff first.

下面是一个关于 Magento 的长系列的一部分, 它针对的是熟悉 PHP MVC 开发的开发者。虽然每篇文章都可以单独阅读, 但每篇文章都是建立在以前文章所涵盖的概念和代码之上的。如果你感到困惑, 一定要先赶上旧的教程。

 

Adding A System Config File

The first thing we need to do is add a system configuration file to our module. This file is separate from config.xml, and can be found at the following location

第一件事我们要做的是,为我们的模块添加一个系统配置文件。这个文件是单独自 config.xml的,可以在一下路径里找到:

app/code/local/Alanstormdotcom/Helloworld/etc/system.xml

While similar to the global config, the system configuration information is stored separately. If you need to view the system config file, it exists as it’s own entity. You can view the entire system config by executing the following PHP code from any controller action

有些像 全局配置,系统配置信息是分别保存的。如果你要查看系统配置文件,它以自己的实体实例存在。(暂时完全不懂,后面再修改)。你可以查看整个系统的配置,用一下PHP代码从任何controller。【这里会返回一个很大的xml,包含了已安装的插件信息,包含core,可以搜索关键字 module= 】

//header('Content-Type: text/xml');            
header('Content-Type: text/plain');            
echo $config = Mage::getConfig()
->loadModulesConfiguration('system.xml')        
->getNode()
->asXML();            
exit;

The loadModulesConfiguration method will look in each configured module’s etc folder for a file with the passed in name (in this case, system.xml). Magento has a number of other configuration files (api.xml, wsdl.xml, wsdl2.xml, convert.xml, compilation.xml, install.xml), and as a module developer you can leverage this functionality to create your own.

loadModulesConfiguration方法将会查询在每一个已经配置的模块的etc文件下,传入的名字的文件(在本例子中,为system.xml)。Magento有很多的其他配置文件比如api.xml,wsdl.xml.wsdl2.xml,convert.xml,compliation.xml,install.xml。作为一个开发者,可以利用这些功能去创建自己的 配置文件 。

 

Adding a new Tab

The first thing we’re going to do is a add a custom “Tab” to the System Configuration. Tabs are the navigation headers down the left hand side of the Admin in System->Configuration. The default tabs are General, Catalog, Customers, Sales, Services, and Advanced.

第一件事,我们要做的是添加一个Tab在系统设置里。Tabs是在后台管理页面导航栏头部system–> configuration 下进入,左边栏的那一部分。默认的Tabs有这些:General, Catalog, Customers, Sales, Services, and Advanced 等

Let’s create a new one named “Hello Config”. Create a new system config file and add the following

Location: app/code/local/Alanstormdotcom/Helloworld/etc/system.xml
<config>
    <tabs>
        <helloconfig translate="label" module="helloworld">
            <label>Hello Config</label>
            <sort_order>99999</sort_order>
        </helloconfig>
    </tabs>    
</config>

首先创建一个‘Hello Config’的模块,创建一个新的系统配置文件【system.xml】并写入代码。

A few explanations are in order. The name of the <helloconfig /> node is arbitrary, but should be unique among Tabs. It will serve as an identifier for your tab which we’ll use later in the config.

按数序介绍:<helloconfig />代码段是任意定义的但是要唯一。这个用作你 稍后配置的的tab的一个标识符。

The module="helloworld" attribute identifies which module this tab “belongs” to, <label> determines the name that will be used for your tab, and <sort_order> determines where the tab shows up in relation to the other tabs in the left hand navigation.

module="helloworld" 这个属性用来标识这个tab属于那个模块。<label>决定了用作tab的名字。<sort_order>决定了这个tab在左侧导航的排序。

With this in place, head over to the System -> Config section. One of two things should happen

操作了这些之后,回到 System -> Config部分,有两件事可以发现:

  1. The page will load as expected, but without your new tab
  2. You’ll get an error something like the following:
    Fatal error: Class 'Mage_Helloworld_Helper_Data' not found in

1.网页可以正常刷新显示,但是没有我们的新tab

2.会得到错误提示 ‘Mage_Helloworld_Helper_Date’

A Brief Interlude(插曲) for Helper Classes

Like a lot of popular PHP MVC systems, Magento has Helper classes, which are used for a variety of tasks that don’t fit neatly into Model, View, or Controller. Helper classes are one of the abstracted grouped class names, meaning system users can override default classes and module developers need to add a section to their config.xml to specify the base class name for Helpers.

如同其他PHP的MVC系统一样,Magento拥有Helper类,用于不适合在Model,View或Controller中合适贴合的各种任务。Helper类是grouped class names的一个实例化。意味着系统使用者可以覆写默认的classes,模块开发者需要在 config.xml 文件中添加一个段落用来给Helpers致命基本的类名。

A lot of the Magento System code assumes a module has a default Helper class. If you got the exception mentioned above, it’s because your Helloworld module didn’t have this default Helper class and the System was trying to use it. Let’s add one now.

Magento系统假定一个模块是有默认的Helper类。如果你看到了上面提到的错误,这是因为Hello World 模块没有一个默认的Helper类而系统又尝试去使用它,现在我们自己添加一个。

First, we need to add a section the to module’s main config.xml file (NOT the system config)

首先我们在 config.xml(注意不是system.xml文件)添加模块的主配置段落。

File: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml

<!-- ... -->
<global>
    <!-- ... -->
    <helpers>
        <helloworld>
            <class>Alanstormdotcom_Helloworld_Helper</class>
        </helloworld>
    </helpers>    
    <!-- ... -->
</global>
<!-- ... -->    

If you’ve spent anytime in the Magento config this should be straight forward. The <helloworld /> tag should be named after your module, and the <class /> tag should contain the base name of all your Helper classes, named with the Magento standard convention

如果已经有配置Magento 的经验,可以直接跳过此段落。【算了还是继续看吧】<helloworld /> 应当在模块后命名,<class />应当包含Helper 类基本的名字,以Magento 的标准约定方式命名:

Packagename_Modulename_Helper

Helper’s are loaded with the global Mage object’s static helper method. The following call (assuming the above config file)

Helper 类加载的是全局变量Mage 对象的静态 helper方法。以下调用(假定以下配置文件)

Mage::helper('helloworld/foo');

将会调用

app/code/local/Alanstormdotcom/Helloworld/Helper/Foo.php
class Alanstormdotcom_Helloworld_Helper_Foo

Magento also has the concept of a default Helper for a module. If you provide the Helper class with only the module name

Magento默认模块有一个默认的Helper类,如果你提供的Helper类只有模块名字:

Mage::helper('helloworld');

it will look for a data Helper located at

app/code/local/Alanstormdotcom/Helloworld/Helper/Data.php
class Alanstormdotcom_Helloworld_Helper_Data ...

That means the following two calls are equivalent.

这意味着以下两个调用是等价的:

Mage::helper('helloworld');
Mage::helper('helloworld/data');

Finally, we need to add the actual Helper class. Add the following file, and you’ll be good to go.

最后,我们需要添加的当前的Helper类,添加一下代码到文件:

File: app/code/local/Alanstormdotcom/Helloworld/Helper/Data.php
class Alanstormdotcom_Helloworld_Helper_Data extends Mage_Core_Helper_Abstract
{
}   

With all this done, clear your Magento cache and reload the System admin. Your error message should be gone, but your new tab is still missing.

操作完以上后,清空缓存并刷新页面,错误信息会消失,但是tab还是空的。

Note: If you’re curious about the kind of things a helper can do for you, checkout the Mage_Core_Helper_Abstract class for a list of useful methods that all helpers will have.

备注:如果你有兴趣了解各种helper可以做的事情,你可以检查Mage_Core_Helper_Abstract类去找出所有helper有的有用的方法。

Adding A New Section

The Helper interlude out of the way, our next step is figuring out why our configured Tab isn’t showing up. Each Tab has a number of sections. For example, the Advanced tab has (by default) an Admin, System, Advanced, and Developer section.

Helper类的事情讲完了,我们下一步解决为什么配置的tab没有显示。每一个tab都有几个小分类,比如默认的Advanced有Admin, System, Advanced, and Developer等小分类。

If a Tab is configured with no sections, it won’t show up. Let’s fix this by adding a <section /> node to our system config

如果Tab设置成没有小分类,它不会显示,添加<section /> 标签在system.xml中来修复此问题:

Location: app/code/local/Alanstormdotcom/Helloworld/etc/system.xml
<config>
    <tabs>
        <helloconfig translate="label" module="helloworld">
            <label>Hello Config</label>
            <sort_order>99999</sort_order>
        </helloconfig>
    </tabs>    
    <sections>
        <helloworld_options translate="label" module="helloworld">
            <label>Hello World Config Options</label>
            <tab>helloconfig</tab>
            <frontend_type>text</frontend_type>
            <sort_order>1000</sort_order>
            <show_in_default>1</show_in_default>
            <show_in_website>1</show_in_website>
            <show_in_store>1</show_in_store>                    
        </helloworld_options>
    </sections>        
</config>

There’s some familiar nodes in this new configuration section, as well as a few new faces.

这里有些熟悉的标签这新的配置代码段落,当然也有新面孔。

What is a <helloworld_options/>?

Similar to the <helloconfig /> tag above, this in a arbitrary name that’s used to identify your new section.

<helloconfig />标签一样,这是一个任意定义的名字用来标识新的小分类。

What is a <label />?

A label defines the display value used in the HTML interface for your new section.

标签用来定义显示在HTML界面的名称。

What is a <tab />?

This identifies which Tab your new section should be grouped under. We want our section to show up under our new helloconfig Tab. The helloconfig name comes from the tag used to create the Tab (<helloconfig/>)

这个标识符新的小分类分组在那个Tab下面,我们希望小分类展示在新的Hello Config Tab,这个helloconfig 名字来自与我们创建的Tab (<helloconfig/>)

What is a <frontend_type />?

This one it tricky. <frontend_type /> has meaning in other sections of the configuration (see below), but it doesn’t appear to do anything here. However, sections in the Core modules use this tag, so it’s best to follow the convention, even when you’re not sure what it does.

这一个有点难回答。<frontend_type/> 在配置的其他部分中有意义 (见下文), 但它在这里似乎不起任何作用。但是, 核心模块中的节使用此标记, 因此最好遵循该Magento 约定, 即使您不确定它的用途。

What is a <sort_order />?

Again, <sort_order /> determines where this sections shows up vertically(垂直) compared to other sections in the Tab.

有一次<sort_order /> 决定了这个小分类与其他小分类在这个tab里的垂直顺序。

What is a <show_in_default /><show_in_website /><show_in_store />?

These are boolean config options, with a valid value of 1 or 0. They determine the level of configuration score/granularity(分数/粒度) this section has.

这些是一些布尔值类型的配置选项,可以值只有1或0.这些设置决定此部分的配置xi范围级别。

With our section configured, Let’s head over to System -> Config again (reloading the Admin page often won’t be enough). You should now see your section and tab near the bottom of the left hand navigation. You can add more sections by adding additional nodes to the <sections /> node.

带着我们的此段小分类的配置,再次回到System -> Config (刷新这个admin的页面通常是不行的,可能要推出登录)。你将会看到小分类和Tab出现在左侧导航区块的下方。你可以通过配置<sections />代码添加更多的小分类。

 

Access Control 访问控制

If you click your new section link you’ll be disappointed by the results. A blank admin page will load, and the entire left hand navigation will vanish(烟消云散). That’s because the Adminhtml application can’t find an entry for our new section in the Access Control List (ACL).

如果你点击了你新的小分类,看到结果后你会失望。你个空白的页面将会出现,整个左边的导航区块会消失。这是因为Adminhtml应用程序在ACL(访问控制列表)找不到我们新的小分类的入口。

ACL is a topic all its own, but I’ll try to explain enough here so this doesn’t seem like total magic. This section is optional, and if you’re not interested skip to the end for the magic XML to paste into your config.xml

ACL是一个主题,但是作者准备详尽的解释它,以至于它不会看起来完全就是一个魔术。这个章节是可选阅读的,如果没有兴趣,可以跳转到最后把充满魔术的XML贴到config.xml 里去(那样子就失去作者和翻译的意义了)

There are certain(某些) resources (where resource is a loosely defined term(学术;长期)) that require a user to be authenticated before using them. Resource here is an abstracted(抽象) term. It might be a page in the admin, or it might be access to a certain feature. The Magento team decided that System Config sections should have ACL protection.

有些资源(那些被术语松散定义的)需要用户在使用前被授权。资源在这里是一个抽象概念,可以是admin里第一个page或者是可以进入某些功能的权利。Magento team 决定系统设置章节需要一个ACL保障。

Resources are defined via URI’s. For example, the “web” config section (under the General tab), if defined with a URI of

admin/system/config/web

资源可以用URI来定义,比如系统自带的web设置小分类(在 General tab下),如果一个资源被以下URI定义:

Our helloworld_options section would have a URI of

admin/system/config/helloworld_options

那我们的小分类 helloworld_options 应该用URI这样定义

The Admin application (often called Adminhtml) is built using the same framework as the store application (the store application is often called the frontend application). In Adminhtml action controllers, whenever a user needs to access a resource protected by ACL, the Adminhtml developer must

Admin应用程序(一般叫做Adminhtml)是和store应用程序(通常叫做 frontend 应用程序)一样的框架架构。在Adminhtml的操作控制器中,每当用户需要去访问ACL保护的资源时,Adminhtml需要以下操作:

  1. Derive a URI for whatever resource the end-user is trying to access
  2. Check that URI against the ACL system, which will determine if the
    logged in user has the right privileges that particular resource
  3. If the user does have the correct privileges, proceed. If they don’t, boot them
    or do something appropriate (like stop rendering the navigation and content areas)

1.为准备访问资源的终端用户分配一个RUI.

2.检查URI和ACL是否匹配,这将决定了登录的用户是对特定的资源有正确的权限。

3.如果用户有正确的权限,继续处理。如果没有,引导他们或者做一个正确的事情(比如停止加载导航和内容区块)

For those interested, this is done for the System Config sections in the _isSectionAllowedmethod in the following controller

app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php

如果想了解更多,在下面列出的控制器中,_isSectionAllowed 这个方法是为系统设置章节完成的。(翻译的不是特别好)

If you go to System -> Permissions -> Roles, add click the Add a new role button, you can see a graphical tree representation of all the Role Resources defined in your Magento install.

如果你在后台的 系统–>权限和角色–>角色 中,点击新增一个角色,你可以看到一个树形图形表示所有在Magento 已经安装的 角色资源。

 

Adding an ACL role (添加一个访问控制列表的角色)

That out of the way, we need to define an ACL resource for our new section. You only need to do this if you’re adding a new section. If you’re adding config options to an existing section you don’t need to touch ACL.

.叉开一个话题,我们需要为我们的新章节(小分类)定一个一个ACL资源。你只需要做这些当你在添加一个新的的章节时。如果你为一个已经存在的章节添加控制选项,你不需要接触到ACL.

In your module’s config.xml, add the following section

在你的模块的 config.xml文件,添加一下代码

File: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml    
<config>    
    <!-- ... -->
    <adminhtml>
        <acl>
            <resources>
                <admin>
                    <children>
                        <system>
                            <children>
                                <config>
                                    <children>
                                        <helloworld_options>
                                            <title>Store Hello World Module Section</title>
                                        </helloworld_options>
                                    </children>
                                </config>
                            </children>
                        </system>
                    </children>
                </admin>
            </resources>
        </acl>
    </adminhtml>
    <!-- ... -->
</config>

Yes, that’s a mouthful. Let’s break it down a bit. First off, all defined resources are contained in the following node structure.

是的,这是一大段代码,让我我们分解理解它。第一,我们定义的资源包含以下节点代码结构:

<adminhtml>
    <acl>
        <resources>
        </resources>
    </acl>
</adminhtml>

Within resource, each descending node represents a URI portion. So, this far down

在资源内部,每个降序节点代码代表一个URI 部分,所以一下的代码

<admin>
    <children>
        <system>
            <children>

gives us a URI of

给出了URI的一部分

admin/system

If you follow that all the way down, you get to the node for our config

如果继续往下看完所有,你可以看到我们设置的节点代码:

<helloworld_options>
    <title>Store Hello World Module Section</title>
</helloworld_options>

Title is what will show up in the Permissions admin.

title是现在后台 权限和角色设置下的名字。

With this in your config and your Magento cache cleared, you should now be able to view your config section. You may need to log out of the application and back into to see it. The Admin has some additional caching beyond the standard Magento cache that I haven’t been able to track down. If(typo) you log out, log back in, and navigate to your section you should now see a blank config page titled “Hello World Config Options”.

操作完上面的射中后并且清空Magento 缓存,你会看到你的设置的 小分类,你需要登出登录Magento 才能看到效果。因为Admin会有一些附加的缓存,超越了Magento 缓存里,作者找不到他们。如果你登出在登入,导航部分的你的小分类将会展示一个有着‘Hello World Config Options’标题的空白设置页面。

 

Adding Groups (添加分组)

So, we now have a blank config section. Our next step is adding a group.

到此,我们已经有了一个空白的设置小分类。我们的下一步是添加一个分组(就是点击小分类后,右侧栏位显示的不同设置的可以点击折叠或展开的,分组显示)

Groups are used to group together different configuration options, and are displayed in the Magento admin with a pop-open widget. For example, in a stock install the Advanced section has a single group named “Disable modules output”. Let’s create a group named “messages” by adding a <groups /> node to our config, nested within the <sections> node.

分组是用来分组聚集不用的配置选项,用来展示Magento 管理后台(admin不知道翻译的对不对)弹出展示的部件。举个例子,在后台设置 Advanced 章节只有有一个单独的分组叫做 ‘Disable modules output’(禁止模块输出)【用来控制插件的disabled或者enbale】,

让我们一起创建一个叫‘messages’的分组,用在config里添加一个<groups /> 的节点代码,把它嵌入<sections>的节点代码中(system.xml)。

Location: app/code/local/Alanstormdotcom/Helloworld/etc/system.xml
<config>
    <tabs>
        <helloconfig translate="label" module="helloworld">
            <label>Hello Config</label>
            <sort_order>99999</sort_order>
        </helloconfig>
    </tabs>    
    <sections>
        <helloworld_options translate="label" module="helloworld">
            <label>Hello World Config Options</label>
            <tab>helloconfig</tab>
            <frontend_type>text</frontend_type>
            <sort_order>1000</sort_order>
            <show_in_default>1</show_in_default>
            <show_in_website>1</show_in_website>
            <show_in_store>1</show_in_store>
            <groups>
                <messages translate="label">
                    <label>Demo Of Config Fields</label>
                    <frontend_type>text</frontend_type>
                    <sort_order>1</sort_order>
                    <show_in_default>1</show_in_default>
                    <show_in_website>1</show_in_website>
                    <show_in_store>1</show_in_store>                
                </messages>
            </groups>
        </helloworld_options>
    </sections>        
</config>

Each tag within this node is analogous(类似) to the tags from the top level <section /> node.

If you reload your page, you’ll now see an empty pop-open box with the title “Demo Of Config Fields”.

此节点代码每一个标记都类似于顶层<section /> 节点代码的标记。

如果你刷新你的设置页面,你将会看到一个空的弹出显示的窗口,标题是‘Demo Of Config Fields’

Adding Config Fields (设置项)

Finally, we need to add our individual configuration fields. You’ll do this by adding a <fields /> node to your <messages /> node. We’ll start with a field name “hello_message”.

最后我们需要为添加单个的设置项,需要添加一个<fields />到<messages /> 代码段。我们把hello_message最为设置项的名字。

<!-- ... -->
<messages translate="label">
    <label>Demo Of Config Fields</label>
    <frontend_type>text</frontend_type>
    <sort_order>1</sort_order>
    <show_in_default>1</show_in_default>
    <show_in_website>1</show_in_website>
    <show_in_store>1</show_in_store>                
    <fields>
        <hello_message>
            <label>Message</label>
            <frontend_type>text</frontend_type>
            <sort_order>1</sort_order>
            <show_in_default>1</show_in_default>
            <show_in_website>1</show_in_website>
            <show_in_store>1</show_in_store>                    
        </hello_message>
    </fields>                    
</messages>
<!-- ... -->    

Again, fields within your new <hello_message> node are analogous to the other nodes you’ve added so far. However, this time <frontend_type>text</frontend_type> actually does something useful by letting the system know what kind of form element you want. Reload your page, and you should now see an individual text field in the popup box.

同样的,我们新的<hello_message>代码段和其他已经添加的代码段是类似的。然而,这次的<frontend_type>text</frontend_type>实际上起到了一些作用:告诉system我们需要什么样的表格元素。刷新载入页面,我们可以看到一个新的文本设置醒在弹出的页面【应该就是鼠标点击之后看到】

Once all this configuration information is in place, you’re done. No code is needed to save/load/update your config value. The system handles that all for you.

一旦这些设置信息准备就绪了,我们也就成功了。不要代码来保存/上传/更新我们的配置设定值。system会帮我们处理。

You’re not limited to text fields. Let’s add a field called <hello_time/>

我们不限于文本选项,让我添加一个选项叫做 <hello_time/>【还是在system.xml里】

<!-- ...-->
<fields>
    <hello_message>
        <label>Message</label>
        <frontend_type>text</frontend_type>
        <sort_order>1</sort_order>
        <show_in_default>1</show_in_default>
        <show_in_website>1</show_in_website>
        <show_in_store>1</show_in_store>                    
    </hello_message>
    <hello_time>
        <label>Time to Say Hello</label>
        <frontend_type>time</frontend_type>
        <sort_order>1</sort_order>
        <show_in_default>1</show_in_default>
        <show_in_website>1</show_in_website>
        <show_in_store>1</show_in_store>                    
    </hello_time>        
</fields>
<!-- ... -->

Notice that the main difference here is the

<frontend_type>time</frontend_type>

留意此处有一个不同的地方【frontend_tyoe】标签

Reload your page, and you’ve now got a config field for saving a time value.

刷新页面,这时候我们有了ige保存时间数值的选项。

Many, but not all, of the built in Varien data form classes (lib/Varien/Data/Form/Element) are supported. The <frontend_type /> tag acts as an identifier for a factory-ish pattern. Let’s try changing our hello message to a select field.

经常,但不是每一次,被来自(lib/Varien/Data/Form/Element)的Varien data的类是支持的【没看懂,先直译】,这些<frontend_type />的标签实际是一个工厂模式的标识符。让我尝试修改我们的 hello message变成一个select设置选项。

<!-- ... -->
<hello_message>
    <label>Message</label>
    <frontend_type>select</frontend_type>
    <sort_order>1</sort_order>
    <show_in_default>1</show_in_default>
    <show_in_website>1</show_in_website>
    <show_in_store>1</show_in_store>                    
</hello_message>
<!-- ... -->

If you reload your page you’ll see that you have an HTML select, but without any values. We’re going to need to add a source model to our field definition. Try this instead.

如果你刷新页面,你将可以看到一个html选择器,但是没有任何选项值。我们现在为选项定义【没翻译好】增加一个资源模型。尝试用一下代替上面代码

<hello_message>
    <label>Message</label>
    <frontend_type>select</frontend_type>
    <!-- adding a source model -->
    <source_model>helloworld/words</source_model> 
                           
    <sort_order>1</sort_order>
    <show_in_default>1</show_in_default>
    <show_in_website>1</show_in_website>
    <show_in_store>1</show_in_store>                    
</hello_message>    

The <source_model> element defines a URI for a Model class that we’ll use to provide default values for the select. This means we’ll need to make sure that our module config.xml has its models section setup

<source_model>元素定义了一个Model类的URI,那些我们用来给selec提供一个默认值。这一位置,我们要保证,我们的模型有一个models片段在config.xml

File: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml
<config>    
    <!-- ... -->
    <global>
    <!-- ... -->
        <models>
            <!-- ... -->
            <helloworld>
                <class>Alanstormdotcom_Helloworld_Model</class>
            </helloworld>    
            <!-- ... -->
        </models>
    </global>
</config>

See the Magento Models and ORM Basics and the Class Instantiation Abstraction and Autoload article if you’re not sure what’s going on in that config.

有两篇帮助文章,用来搞懂config文件的作用

So, with that in place, if we reload our page after a cache clearing, we’ll end up with an Error something like

做到这一步,清空缓存重新加载页面,会看到下面这种的错误提示:

Warning: include(Alanstormdotcom/Helloworld/Model/Words.php)

That’s because we haven’t defined our source Model class. Let’s do that now.

这是因为我们还没有定义资源Model的类,让我们来添加它:

Note: If the warning you’re getting uses a Mage/Helloworld/... path, that means you haven’t setup your <model /> section correctly in config.xml.

注意:如果错误提示是Mage/Helloworld/... 的路径,这说明你还没有在config.xml里正确地配置<model />

To define our source Model, add the following file

为了定义我的资源Model,添加一下文件:

File: app/code/local/Alanstormdotcom/Helloworld/Model/Words.php
class Alanstormdotcom_Helloworld_Model_Words
{
    public function toOptionArray()
    {
        return array(
            array('value'=>1, 'label'=>Mage::helper('helloworld')->__('Hello')),
            array('value'=>2, 'label'=>Mage::helper('helloworld')->__('Goodbye')),
            array('value'=>3, 'label'=>Mage::helper('helloworld')->__('Yes')),            
            array('value'=>4, 'label'=>Mage::helper('helloworld')->__('No')),                        
        );
    }

}

Source Models are classes that respond to a method named toOptionsArray. This method should return an array of values that are used to populate the default values of our form elements (which descend from the Varien_Data_Form_Element_Abstract hierarchy). For a select element, this means defining a set of value/label pairs. In the above example, we’re passing our labels through the Helper’s translation method (__). While not necessary, this is always a good practice. You never know when you’re going to get big in Japan!

资源Model使用来回应叫做toOptionsArray这个方法的类。此方法是用来返回数组的值,哪些我们用来填充表格元素的默认值(继承于Varien_Data_Form_Element_Abstract 结构)。对一个select元素而言,这以为只定义了一对值/标签。在上面的例子中,我们传递我们的标签通过Helper的翻译方法  (__) 。虽然不是必要的,但仍然是一个好的经验。这句话不翻译了,没有实际意义。

Reload your page, and you should have a working select field.

刷新页面,我们可以看到select字段可以正常工作了。

For those interested in the Magento internals, the initFields method in the following class is where the source Model is used to set the field’s value

app/code/core/Mage/Adminhtml/Block/System/Config/Form.php

对此感兴趣的可以在下面文件可以了解Magento内部代码,initFields这个方法是我们资源Model用来设定字段值【待改进】。

Adding to Existing Config Sections/Groups(添加到已经存在的分类和分组)

In addition to setting up your own config Tabs and sections, you can add to an existing System Config section by adding appropriate sections to your own system.xml file.

除了设置我们自己的Tabs和小分类,我们还可以添加一个已经旬在的System Config的章节里去,做法是在system.xml里添加合适的代码段。

For example, if you add the following

File: app/code/local/Alanstormdotcom/Helloworld/etc/system.xml
<config>
    <!-- ... -->
    <sections>
        <!-- ... -->
        <general>
            <groups>
                <example>
                    <label>Example of Adding a Group</label>
                    <frontend_type>text</frontend_type>
                    <sort_order>1</sort_order>
                    <show_in_default>1</show_in_default>
                    <show_in_website>1</show_in_website>
                    <show_in_store>1</show_in_store>                    
                </example>
            </groups>
        </general>
        <!-- ... -->
    </section>
</config>

you’ll have a new group in the general Tab called “Example of Adding a Group”.

你讲会得到一个新的group的叫做Example of Adding a Group,在普通的Tab里。

Retrieving Values(检索值)

We’ve covered how to setup forms for creating configuration values. To retrieve values in our client applications and modules, we’ll use the getStoreConfig method on the global Mage object. For example, to grab the value of the select we created above, we’d use

我们已经了解如何去设置一个表格彬彬个创建设置的值。为了在客户程序和模块里索引值,我们将会全局Mage 对象在使用getStoreConfig 返回广发。例如,为了抓去我们上面创建select的值,我们应当如此操作:

Mage::getStoreConfig('helloworld_options/messages/hello_message');

The getStoreConfig method accepts a single parameter that’s a URI in the following format

getStoreConfig 发发接受一个单个的参数,所以URI会这样的格式

section_name/group_name/field_name

You can also grab an array of all your config values by specifying a partial path

你也可以用特定的部分路径去扎un去我们设置值的数组形式

Mage::getStoreConfig('helloworld_options/messages');
Mage::getStoreConfig('helloworld_options');

Finally, if you need to grab a value for a store that isn’t the store being used by the current session, getStoreConfig accepts a second parameter, the store ID

最后,如果抓取的store的值不是希望的,可以在getStoreConfig 添加第二个参数,store ID

Mage::getStoreConfig('helloworld_options',1);

Wrapup(提要)

We started off wanting to setup some System Config sections, and ended up exploring Helper classes, Access Control Lists, and the Varian Form hierarchy. In addition to what we covered above, it’s possible to create System Config options that use custom frontend and backend Models, which I’ll try to cover in a latter article.

我们从想在System Config添加一个Tba开始,讲到了 Helper 的类,访问控制列表ACL 和Varian的表格层次结构。此外我们上面所包括的,如何在System Config 选项里使用我们自定义的前台和后台的Modles,我们将在下一篇文章讲到。

You can download the complete module for this article here.

 

Magento cron job not work on 1.9.1的问题

magento的cron job问题,从一开始学习的时候,也缠绕过我,很难解决。

最近又遇到的了一个问题,mg 1.9.1 安装的了一些安全补丁patch之后,cron job在AOE Scheduler extension(这真的是一个好用的插件,文章尾部会有下载连接)的heartbeat检测超过一个小时没运行。

解决办法主要参考这里源链接

1.关掉Aschroder SMTP 插件的Queue Usage 。

思路清奇,不过在1.x版本的magento谁又没有安装过呢。

2.根目录的cron.php 增加一行

$isShellDisabled = true;

47行左右。

3.xtento 给出的指导wiki源链接 (值得翻译的一篇文章)

在cron tab 使用

wget -O /dev/null -q http://www.YOURDOMAIN.com/PATH_TO_MAGENTO/cron.php > /dev/null

 

五分钟一次 */5 * * * *

 

我是第三种解决问题,当然第一种和第二种也都调整了。

有时间设置No.1 No.2回原值,试试看。

 

关于magento cron job的基础设置:

crontab */5 * * * * /usr/bin/php -f /home/yourdomainname/public_html/cron.php

水水哥的文章 源链接

SSH 查看 cron tab

crontab -l     //列出

crontab -e    //编辑

 

记得看到有一篇文章说某个Patch修复安全问题后,会导致cron job出问题,应该是第二种方法解决。

 

下载链接:

Aoe_Scheduler-0.3.2 百度云

magento order number 自定义

主要涉及2个表,eav_entity_type和eav_entity_store

SELECT entity_type_id,entity_type_code,increment_pad_length FROM `eav_entity_type` WHERE entity_type_code =’order’;

SELECT * FROM `eav_entity_store`;

一般order很长,第一个increment_pad_length(eav_entity_type)是订单号码除了increment_prefix(eav_entity_store表)的长度。

increment_last_id(eav_entity_type)是系统组后一个订单号码


如果系统已经有了订单,存在了订单号码,可以sql语句更新

参考:

 

mysql_connect(“localhost”,$user,$psw);

mysql_select_db($db);
$store_id=1;
$prefix=’ABC’;
$start_num=’10001′;

$rs=mysql_query(“SELECT * FROM `sales_flat_order` a WHERE a.`store_id`='”.$store_id.”‘”);

while ($rw=mysql_fetch_array($rs))
{
$order_id=$rw[‘entity_id’];
$order_num = $rw[‘increment_id’];
$order_num_new=$prefix.$start_num;
$start_num++;

echo $order_id.'<br/>’;
echo $order_num.'<br/>’;
echo $order_num_new.'<br/>’;

mysql_query(“update `sales_flat_order` set `increment_id`='”.$order_num_new.”‘ where `increment_id`='”.$order_num.”‘”);
mysql_query(“update `sales_flat_order_grid` set `increment_id`='”.$order_num_new.”‘ where `increment_id`='”.$order_num.”‘”);

mysql_query(“update `sales_flat_creditmemo` set `increment_id`='”.$order_num_new.”‘ where `order_id`='”.$order_id.”‘”);
mysql_query(“update `sales_flat_creditmemo_grid` set `increment_id`='”.$order_num_new.”‘,`order_increment_id`='”.$order_num_new.”‘ where `order_id`='”.$order_id.”‘”);
mysql_query(“update `sales_flat_invoice` set `increment_id`='”.$order_num_new.”‘ where `order_id`='”.$order_id.”‘”);
mysql_query(“update `sales_flat_invoice_grid` set `increment_id`='”.$order_num_new.”‘,`order_increment_id`='”.$order_num_new.”‘ where `order_id`='”.$order_id.”‘”);
mysql_query(“update `sales_flat_shipment` set `increment_id`='”.$order_num_new.”‘ where `order_id`='”.$order_id.”‘”);
mysql_query(“update `sales_flat_shipment_grid` set `increment_id`='”.$order_num_new.”‘,`order_increment_id`='”.$order_num_new.”‘ where `order_id`='”.$order_id.”‘”);
}

12306客户服务汇总

1.改签规定:

一张车票可以办理一次改签。

车票改签后,旅客取消旅行的,可以按规定退票,但开车后改签的车票不能退票。对已改签车票暂不提供“变更到站”服务。

links


在12306.cn网站购票后,在有运输能力的前提下,可在车站售票窗口办理改签:

(1)开车前48小时(不含)以上,可改签预售期内的其他列车;

开车前48小时以内,可改签开车前的其他列车,也可改签开车后至票面日期当日24:00之间的其他列车,不办理票面日期次日及以后的改签;

开车之后,旅客仍可改签当日其他列车,但只能在票面发站办理改签。已经办理“变更到站”的车票,不再办理改签。开车前48小时~15天期间内,改签至距开车15天以上的其他列车,又在距开车15天前退票的,仍核收5%的退票费。改签后的车票乘车日期在春运期间的,退票时一律按开车时间前不足24小时标准核收退票费。

(2)按购票时所使用的在线支付工具相关规定,在铁路售票窗口改签时,改签后新车票票价高于原车票、需补收票价差额的,请使用带有银联标志的银行卡支付新车票全额票款,原车票票款在规定时间内退回购票时所使用的在线支付工具;

改签后新车票票价低于原车票的,退还差额,对差额部分核收退票费并执行现行退票费标准,应退票款在规定时间内退回购票时所使用的在线支付工具。改签后的新车票票价等于原车票的,无需办理支付。

  (3)在车站售票窗口改签后,出具纸质车票。

links


自2015年春运开始,铁路部门进一步推出了优惠旅客的服务措施,放宽了开车后改签的条件,即:在当日其他列车有余票的情况下,允许旅客在开车后办理改签。其主要变化:

一是扩大了范围,取消了“特殊情况”的限制条件,只要当日其他列车有余票,任何旅客均可在开车后办理改签;

二是延长了办理时间,将“开车后2小时内”延长至当日24时之前

三是简化了办理流程,无需经站长同意,在车站售票处改签窗口即可直接办理。

links


 

依据《铁路安全管理条例》(国务院令第639号)有关规定,在动车组列车上吸烟或者在其他列车的禁烟区域吸烟的,由公安机关责令改正,处500元以上2000元以下的罚款。


按照车票票面指定的日期、车次,可以在中途站上车,但未乘区间的票价不退。在12306.cn网站购票的,在中途站上车时,请在开车前换取纸质车票进站、乘车。


一名成年人旅客可以免费携带一名身高不足1.2米的儿童。如果身高不足1.2米的儿童超过一名时,一名儿童免费,其他儿童请购买儿童票。

儿童身高为1.2~1.5米的,请购买儿童票;超过1.5米的,请购买全价座票。

成年人旅客持卧铺车票时,儿童可以与其共用一个卧铺,并按上述规定免费或购票。


儿童票可享受客票、加快票和空调票的优惠,儿童票票价按相应客票和附加票公布票价的50%计算。免费乘车及持儿童票乘车的儿童单独使用卧铺时,另收全价卧铺票价,有空调时还另收半价空调票票价。儿童票的座别与成年人旅客的车票相同,到站不能远于成年人旅客车票的到站。

magento compiler 后Class ‘Aschroder_SMTPPro_Model_Mysql4_Setup’ not found and Mage registry key “_singleton/dewatasoft_changeattributeset/observer” already exists 错误

错误的原因是手动运行后台的tool–>compiler 设置了enable有些插件没办正确的编译,比如smtppro和changeattributeset这个两个。

解决问题的关键是,关闭compiler。当然这个时候还能登陆后台,去手动关闭是最快的解决办法了。

进入不了后台,网上推荐有两种办法:

1.FTP暂时关闭插件

具体为登陆ftp之后/app/etc/modules/文件夹下重命名对应的插件xml,刷新缓存,就可以登陆后台,再进行操作。

2.SSH进入,关闭compiler

登陆网站所在根目录后 ,执行php -f compiler.php disable

其他的命令包含php -f compiler.php compile 和php -f compiler.php enable

以上内容参考:

stackexchange上Murtuza Zabuawala的回答

stackexchange上Mayers的回答

还有一个值得阅读的帖子

Mage registry key “_singleton/tax/observer” already exists

Magento 后台CMS page 404错误,Error 404 Page Not Found on CMS-page of Magento

登陆后台 点击cms–page 弹出Error 404 Page Not Found 错误页面。如果文件没有丢失的话,是因为删除了store view或者是store的问题。

解决办法,mysql查询:

DELETE FROM cms_page_store
WHERE store_id NOT IN (SELECT store_id FROM core_store);

已经存在的cms page里有些scope指定了store viewsh或store

先删除store view,这里就会出现这个错误。

参考链接:

mdnsolutions.com/

PHP7环境安装magento报错Fatal error: Uncaught Error: Function name must be a string in \app\code\core\Mage\Core\Model\Layout.php:555 Stack trace: #0

magento安装在php7以上的环境是时候,安装或运行的时候有个错误:

Fatal error: Uncaught Error: Function name must be a string in C:\xampp\htdocs\magento\app\code\core\Mage\Core\Model\Layout.php:555 Stack trace: #0 C:\xampp\htdocs\magento\app\code\core\Mage\Core\Controller\Varien\Action.php(390): Mage_Core_Model_Layout->getOutput() #1 C:\xampp\htdocs\magento\app\code\core\Mage\Install\controllers\WizardController.php(120): Mage_Core_Controller_Varien_Action->renderLayout() #2 C:\xampp\htdocs\magento\app\code\core\Mage\Core\Controller\Varien\Action.php(418): Mage_Install_WizardController->beginAction() #3 C:\xampp\htdocs\magento\app\code\core\Mage\Core\Controller\Varien\Router\Standard.php(250): Mage_Core_Controller_Varien_Action->dispatch('begin') #4 C:\xampp\htdocs\magento\app\code\core\Mage\Core\Controller\Varien\Front.php(172): Mage_Core_Controller_Varien_Router_Standard->match(Object(Mage_Core_Controller_Request_Http)) #5 > C:\xampp\htdocs\magento\app\code\core\Mage\Core\Model\App.php(354): Mage_Core_Controller_Varien_Front->dispatch() #6 C:\xampp\htdocs\magento\app\Mage.php(683): Mage_Core_Mo in C:\xampp\htdocs\magento\app\code\core\Mage\Core\Model\Layout.php on line 555

解决方式是:

本地化app\code\core\Mage\Core\Model\Layout.php文件,

找到

$out .= $this->getBlock($callback[0])->$callback[1]();

改成

$out .= $this->getBlock($callback[0])->{$callback[1]}();

清空cache和session就可以。

 

因为在PHP7里需要声明$callback这个变量。

参考连接:

stackexchange 这个页面有给出其他几根收影响的文件。

stackoverflow

magento批量更新库存,价格,客户组价格bulk update Group Price

批量更新库存,价格等简单属性的字段值,magento自带的import/export就可以实现。

Group Price是没有自带功能或者免费插件可以实现批量更新的字段。(其实tier price也是)

下面是整理出可以用的脚本文件,收集整理来源与网络。

主要参考的有:

https://community.magento.com/t5/Programming-Questions/update-group-prices-from-CSV-file-programmatically/m-p/43281#

stackoverflow准备用SOAP API

API方法二

 

对SOAP不是很熟悉,还是采用更直接的PHP脚本:

<?php
define('MAGENTO', realpath(dirname(__FILE__))); 
 require_once MAGENTO . '/app/Mage.php'; 
 Mage::setIsDeveloperMode(true);
ini_set('display_errors', 1);
 umask(0); 
 Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); 
 $count = 0; 
 

 set_time_limit(0);
ini_set('memory_limit','1024M');
 
/***************** UTILITY FUNCTIONS ********************/
function _getConnection($type = 'core_read'){
    return Mage::getSingleton('core/resource')->getConnection($type);
}
 
function _getTableName($tableName){
    return Mage::getSingleton('core/resource')->getTableName($tableName);
}
 
function _getAttributeId($attribute_code = 'price'){
    $connection = _getConnection('core_read');
    $sql = "SELECT attribute_id
                FROM " . _getTableName('eav_attribute') . "
            WHERE
                entity_type_id = ?
                AND attribute_code = ?";
    $entity_type_id = _getEntityTypeId();
    return $connection->fetchOne($sql, array($entity_type_id, $attribute_code));
}
 
function _getEntityTypeId($entity_type_code = 'catalog_product'){
    $connection = _getConnection('core_read');
    $sql        = "SELECT entity_type_id FROM " . _getTableName('eav_entity_type') . " WHERE entity_type_code = ?";
    return $connection->fetchOne($sql, array($entity_type_code));
}
 
function _checkIfSkuExists($sku){
    $connection = _getConnection('core_read');
    $sql        = "SELECT COUNT(*) AS count_no FROM " . _getTableName('catalog_product_entity') . " WHERE sku = ?";
    $count      = $connection->fetchOne($sql, array($sku));
    if($count > 0){
        return true;
    }else{
        return false;
    }
}
 
function _getIdFromSku($sku){
    $connection = _getConnection('core_read');
    $sql        = "SELECT entity_id FROM " . _getTableName('catalog_product_entity') . " WHERE sku = ?";
    return $connection->fetchOne($sql, array($sku));
}
 
function _updateStocks($data){
    $connection     = _getConnection('core_write');
    $sku            = $data[0];
    $newQty         = $data[1];
    $productId      = _getIdFromSku($sku);
    $attributeId    = _getAttributeId();
 
    $sql            = "UPDATE " . _getTableName('cataloginventory_stock_item') . " csi,
                       " . _getTableName('cataloginventory_stock_status') . " css
                       SET
                       csi.qty = ?,
                       csi.is_in_stock = ?,
                       css.qty = ?,
                       css.stock_status = ?
                       WHERE
                       csi.product_id = ?
                       AND csi.product_id = css.product_id";
					   
					   ;
    $isInStock      = $newQty > 0 ? 1 : 0;
    $stockStatus    = $newQty > 0 ? 1 : 0;
    $connection->query($sql, array($newQty, $isInStock, $newQty, $stockStatus, $productId));
}


function _updatePrices($data){
	
	
    $connection     = _getConnection('core_write');
    $sku            = $data[0];

	$entity_id = _getIdFromSku($sku);
	
	$newPrice1       = $data[2];
     $newPrice2       = $data[3];
     $newPrice4       = $data[4];
     $newPrice5       = $data[6];
	
	$id_newPrice1 = '4' ;
	 $id_newPrice2 = '5';
	 $id_newPrice4='6' ;
	 $id_newPrice5 = '3';
	 
	 $combind_groupid_groupprice = array(
											array($newPrice1 ,$id_eco_3pb),
											array($newPrice2,$id_newPrice2),
											array($newPrice4,$id_newPrice4),
											array($newPrice5 ,$id_newPrice5 )
											);
	
		foreach ($combind_groupid_groupprice as $groupid_groupprice){
    /*  catalog_product_entity_group_price table */
		if($groupid_groupprice[0] > 0){
		
		$sql_price_one = "INSERT INTO " . _getTableName('catalog_product_entity_group_price') . " 
		(entity_id,all_groups,customer_group_id,value,website_id)
							VALUES (?,?,?,?,?) ON DUPLICATE KEY UPDATE 
					  value = ?,customer_group_id =?";
		$connection->query($sql_price_one, array($entity_id,0,$groupid_groupprice[1],$groupid_groupprice[0],0,
									$groupid_groupprice[0],$groupid_groupprice[1]));
		
		}
		else{}
		
		}
		
}

/***************** UTILITY FUNCTIONS ********************/
 
$csv                = new Varien_File_Csv();
$data               = $csv->getData(MAGENTO . '/var/import/updateGP.csv'); //path to csv
array_shift($data);
 
$message = '';
$count   = 1;
foreach($data as $_data){
    if(_checkIfSkuExists($_data[0])){
        try{
            //_updateStocks($_data);  //update qty
			
			_updatePrices($_data);
            $message .= $count . '> Success:: Qty (' . $_data[1] . ') of Sku (' . $_data[0] . ') has been updated.
<br />';
 
        }catch(Exception $e){
            $message .=  $count .'> Error:: while Upating  Qty (' . $_data[1] . ') of Sku (' . $_data[0] . ') => '.$e->getMessage().'
<br />';
        }
    }else{
        $message .=  $count .'>>> Error:: Product with Sku (' . $_data[0] . ') does\'t exist.
<br />';
    }
    $count++;
}
echo $message;

 

csv文件放在对应的path然后第一列是sku,第二列是qty,第三group pirce,注意id的对应关系。

tier price大致类似,找到对应数据库就好。

在magento论坛里的增加后面几个保存价格index特tmp的表格,我没有些,还是交给自带的index更新吧

 

XAMPP magento Fatal error: Uncaught Error: Function name must be a string in

环境是win7 64bit & XAMPP v3.2.2 & Magento 1.9.1.0

全新官方压缩包打开安装时,有错误

XAMPP Fatal error: Uncaught Error: Function name must be a string in 。。。

\app\code\core\Mage\Core\Model\Layout.php line 555

然后在 stackoverflow 找到了答案

$out .= $this->getBlock($callback[0])->$callback[1]();

local化之后,改成

$out .= $this->getBlock($callback[0])->{$callback[1]}();

 

同样答题者,给出一个连接关于mangento和PHP7 的兼容问题。

 

 

 

Apache Service detected with wrong path ON XAMPP upgrade V3.2.2

XAMPP更新的时候,如果已经老版本存在的话,需要修改环境变量的PATH,还有可能需要修改注册表

进入注册表—>

点击HKEY_LOCAL_MACHINE—->system—->currentControlSet—->Services—->找到Apache2.4,
修改ImagePath

保存退出,重启XAMPP

 

此外,新版V3.2.2安装时候,提示关闭windows的UAC

在控制面板–用户账户–更改用户账户设置 

滑块拉到最低,保存,重启。