TL;博士:
Areport_event.subject_id == 0
通常是被忽略的用户代理或显式排除的路由触发通常由 Magento 记录的事件的结果。
见app/code/core/Mage/Log/etc/config.xml
:
<config>
<global>
<!-- : -->
<ignoredModules>
<entities>
<install/>
<adminhtml/>
<admin/>
</entities>
</ignoredModules>
<ignore_user_agents>
<google1>Googlebot/1.0 (googlebot@googlebot.com http://googlebot.com/)</google1>
<google2>Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)</google2>
<google3>Googlebot/2.1 (+http://www.googlebot.com/bot.html)</google3>
</ignore_user_agents>
<!-- : -->
</global>
</config>
长答案
为了解释为什么会发生这种情况,我需要更详细地说明。
当任何 Magento 控制器动作即将被调度时,controller_action_predispatch
将触发一个事件,就在动作调度实际发生之前。
再看看app/code/core/Mage/Log/etc/config.xml
:
<config>
<frontend>
<events>
<controller_action_predispatch>
<observers>
<log>
<class>log/visitor</class>
<method>initByRequest</method>
</log>
</observers>
</controller_action_predispatch>
<!-- : -->
</events>
</frontend>
</config>
显示,该Mage_Log
模块为事件定义了一个观察者controller_action_predispatch
,由方法表示Mage_Log_Model_Visitor::initByRequest()
:
public function initByRequest($observer)
{
if ($this->_skipRequestLogging || $this->isModuleIgnored($observer)) {
return $this;
}
$this->setData($this->_getSession()->getVisitorData());
$this->initServerData();
if (!$this->getId()) {
$this->setFirstVisitAt(now());
$this->setIsNewVisitor(true);
$this->save();
}
return $this;
}
当发送当前请求的用户代理与(GoogleBot)之一匹配时,该属性$this->_skipRequestLogging
将为。true
<ignored_user_agents />
如果请求路由匹配其中之一(即,或; 在 EE 中也是) ,则该方法$this->isModuleIgnored()
仅返回。true
<ignoredModules />
install/
adminhtml/
admin/
api/
关键是,如果这两者中的一个返回true
,则观察者立即退出,即根本不会创建/保存访问者。
现在,为了进一步解释以您的catalog_product_view
案例为例,请查看另一个配置文件,app/code/core/Mage/Reports/etc/config.xml
这次:
<config>
<frontend>
<events>
<catalog_controller_product_view>
<observers>
<reports>
<class>reports/event_observer</class>
<method>catalogProductView</method>
</reports>
</observers>
</catalog_controller_product_view>
<!-- : -->
</events>
</frontend>
</config>
它定义了事件的观察者catalog_controller_product_view
,由
Mage_Reports_Model_Event_Observer::catalogProductView()
方法表示:
public function catalogProductView(Varien_Event_Observer $observer)
{
$productId = $observer->getEvent()->getProduct()->getId();
Mage::getModel('reports/product_index_viewed')
->setProductId($productId)
->save()
->calculate();
return $this->_event(Mage_Reports_Model_Event::EVENT_PRODUCT_VIEW, $productId);
}
这个观察者的最后一行调用了这个_event()
方法:
protected function _event($eventTypeId, $objectId, $subjectId = null, $subtype = 0)
{
if (is_null($subjectId)) {
if (Mage::getSingleton('customer/session')->isLoggedIn()) {
$customer = Mage::getSingleton('customer/session')->getCustomer();
$subjectId = $customer->getId();
}
else {
$subjectId = Mage::getSingleton('log/visitor')->getId();
$subtype = 1;
}
}
$eventModel = Mage::getModel('reports/event');
$storeId = Mage::app()->getStore()->getId();
$eventModel
->setEventTypeId($eventTypeId)
->setObjectId($objectId)
->setSubjectId($subjectId)
->setSubtype($subtype)
->setStoreId($storeId);
$eventModel->save();
return $this;
}
看看这个else
块,尤其是这一行:
$subjectId = Mage::getSingleton('log/visitor')->getId();
当访问者由于忽略的用户代理或排除的路由而根本没有被创建/保存时,那么$subjectId
将是null
.
由于表列subject_id
被定义为NOT NULL(参见app/code/core/Mage/Reports/sql/reports_setup
SQL 脚本),0
最终将被保存。
那是因为 MySQL 的数据类型默认值。