2018年3月4日星期日

magento缓存系列详解:如何缓存一个block

magento是基于zend framework的,所以cache的使用基本也继承了他的一些特性。我们要知道缓存中有几个重要的概念:
数据本身;数据的标识;缓存生命期;缓存操作接口;
Zend_Cache 的使用比较简单, 它可以把数据保存到 File, Memcache, SQLite 等介质(称为后端, Backend)中. 还有前端(Frontend), 主要用来对要缓存的数据进行转换, 如序列化.
Zend Framework 后端主要有
    apc (Zend_Cache_Backend_Apc),
    files (Zend_Cache_Backend_File),
    memcached (Zend_Cache_Backend_Memcached)
    and some more.. 
Magento 增加了几种:
    database (Varien_Cache_Backend_Database)
    eaccelarator (Varien_Cache_Backend_Eaccelarator).

为了更深入的理解magento cache,本文就以缓存某个block为例,分析下他的工作流程和原理。在magento中,所有的block都是继承自Mage_Core_Block_Abstract,当输出某个block到页面时,会调用到这个类的toHtml方法,该方法中有如下code片段:
[php] view plain copy
  1. $html = $this->_loadCache();//加载缓存,假设为第一次加载,还没有被缓存过,进入if代码段  
  2. if ($html === false) {  
  3.     $translate = Mage::getSingleton('core/translate');  
  4.     /** @var $translate Mage_Core_Model_Translate */  
  5.     if ($this->hasData('translate_inline')) {  
  6.         $translate->setTranslateInline($this->getData('translate_inline'));  
  7.     }  
  8.   
  9.     $this->_beforeToHtml();  
  10.     $html = $this->_toHtml();  
  11.     $this->_saveCache($html);//这句代码很简单,但却在内部完成了大量的工作,下面进入它内部深入分析  
  12.   
  13.     if ($this->hasData('translate_inline')) {  
  14.         $translate->setTranslateInline(true);  
  15.     }  
  16. }  
继续看本类中的function _saveCache($data)
[php] view plain copy
  1. function _saveCache($data)  
  2.     /** 
  3.      * Save block content to cache storage 
  4.      * 
  5.      * @param string $data 
  6.      * @return Mage_Core_Block_Abstract 
  7.      */  
  8.     protected function _saveCache($data)  
  9.     {  
  10.         if (is_null($this->getCacheLifetime()) || !Mage::app()->useCache(self::CACHE_GROUP)) {  
  11.             return false;  
  12.         }  
  13.         $cacheKey = $this->getCacheKey();  
  14.         /** @var $session Mage_Core_Model_Session */  
  15.         $session = Mage::getSingleton('core/session');  
  16.         $data = str_replace(  
  17.             $session->getSessionIdQueryParam() . '=' . $session->getEncryptedSessionId(),  
  18.             $this->_getSidPlaceholder($cacheKey),  
  19.             $data  
  20.         );  
  21.   
  22.     //可以肯定进入了Mage_Core_Model_App 的function saveCache  
  23.         Mage::app()->saveCache($data$cacheKey$this->getCacheTags(), $this->getCacheLifetime());  
  24.         return $this;  
  25.     }  
打开Mage_Core_Model_App 的function saveCache
[php] view plain copy
  1. /** 
  2.  * Saving cache data 
  3.  * 
  4.  * @param   mixed $data 
  5.  * @param   string $id 
  6.  * @param   array $tags 
  7.  * @return  Mage_Core_Model_App 
  8.  */  
  9. public function saveCache($data$id$tags=array(), $lifeTime=false)  
  10. {  
  11.     $this->_cache->save($data$id$tags$lifeTime);  
  12.     return $this;  
  13. }  
可以看到$this->_cache这个对象调用了save,继续看$this->_cache到底属于哪个类的实例,在本类中找到protected function _initCache(),code如下:
[php] view plain copy
  1. /** 
  2.  * Initialize application cache instance 
  3.  * 
  4.  * @return Mage_Core_Model_App 
  5.  */  
  6. protected function _initCache()  
  7. {  
  8.     $this->_isCacheLocked = true;  
  9.     $options = $this->_config->getNode('global/cache');  
  10.     if ($options) {  
  11.         $options = $options->asArray();  
  12.     } else {  
  13.         $options = array();  
  14.     }  
  15.   
  16.     //实例化Mage_Core_Model_Cache,并传入参数$options  
  17.     $this->_cache = Mage::getModel('core/cache'$options);  
  18.     $this->_isCacheLocked = false;  
  19.     return $this;  
  20. }  
上面Mage::getModel('core/cache', $options)的$options是app/etc/local.xml中节点global/cache下的配置,假设ocal.xml如下:
[html] view plain copy
  1. <config>  
  2.     <global>  
  3.         <cache>  
  4.             <backend>apc</backend>  
  5.             <slow_backend>File</slow_backend>  
  6.             <auto_refresh_fast_cache>1</auto_refresh_fast_cache>  
  7.             <prefix>MYSHOP_</prefix>  
  8.             <default_priority>10</default_priority>  
  9.         </cache>  
  10.     </global>  
  11. </config>  
能看到$this->_cache是实例化了实例化Mage_Core_Model_Cache,所以Mage_Core_Model_App 中的$this->_cache->save($data, $id, $tags, $lifeTime)即调用的Mage_Core_Model_Cache的function save。进入Mage_Core_Model_Cache的save:
[php] view plain copy
  1. /** 
  2.  * Save data 
  3.  * 
  4.  * @param string $data 
  5.  * @param string $id 
  6.  * @param array $tags 
  7.  * @param int $lifeTime 
  8.  * @return bool 
  9.  */  
  10. public function save($data$id$tags=array(), $lifeTime=null)  
  11. {  
  12.     /** 
  13.      * Add global magento cache tag to all cached data exclude config cache 
  14.      */  
  15.     if (!in_array(Mage_Core_Model_Config::CACHE_TAG, $tags)) {  
  16.         $tags[] = Mage_Core_Model_App::CACHE_TAG;  
  17.     }  
  18.     return $this->_frontend->save((string)$data$this->_id($id), $this->_tags($tags), $lifeTime);  
  19. }  
可以看到$this->_frontend->save(...)这句,那么这里的_frontend是什么呢?继续看此类的构造函数(只列出部分code):
[php] view plain copy
  1. $backend    = $this->_getBackendOptions($options);  
  2.    $frontend   = $this->_getFrontendOptions($options);  
  3.   
  4.    $this->_frontend =Zend_Cache::factory('Varien_Cache_Core'$backend['type'], $frontend$backend['options'],true, true, true);  
没错_frontend就是类Varien_Cache_Core的一个实例,因为Varien_Cache_Core是继承自Zend_Cache_Core,所以这里_frontend实际上实例化的是Zend_Cache_Core,即调用的是Zend_Cache_Core的save,再继续分析,打开Zend_Cache_Core,找到function save它里面包含了如下代码片段:
[php] view plain copy
  1. if (($this->_extendedBackend) && ($this->_backendCapabilities['priority'])) {  
  2.     $result = $this->_backend->save($data$id$tags$specificLifetime$priority);  
  3. else {  
  4.     $result = $this->_backend->save($data$id$tags$specificLifetime);  
  5. }  
可以看到这里实际上又变成了_backend的来调用的save,(开头我们已经说了backend是用来保存数据的),那么这里_backend到底是哪个backend(file,db,apc...)呢?继续分析,在这个类里面有一个方法setBackend:
[php] view plain copy
  1. /** 
  2.  * Set the backend 
  3.  * 
  4.  * @param  Zend_Cache_Backend $backendObject 
  5.  * @throws Zend_Cache_Exception 
  6.  * @return void 
  7.  */  
  8. public function setBackend(Zend_Cache_Backend $backendObject)  
  9. {  
  10.    $this->_backend= $backendObject;  
  11.     // some options (listed in $_directivesList) have to be given  
  12.     // to the backend too (even if they are not "backend specific")  
  13.     $directives = array();  
  14.     foreach (Zend_Cache_Core::$_directivesList as $directive) {  
  15.         $directives[$directive] = $this->_options[$directive];  
  16.     }  
  17.     $this->_backend->setDirectives($directives);  
  18.     if (in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_backend))) {  
  19.         $this->_extendedBackend = true;  
  20.         $this->_backendCapabilities = $this->_backend->getCapabilities();  
  21.     }  
  22.   
  23. }  
里面有$this->_backend= $backendObject这句,$backendObject是传入的参数,那么是何时调用的setBackend呢?实际上,这个方法是在上边Mage_Core_Model_Cache里的save方法中调用$this->_frontend = Zend_Cache::factory('Varien_Cache_Core', $backend['type'], $frontend, $backend['options'], true, true, true);这句的的时候,已经被调用了,可以打开Zend_Cache的factory 方法查看,会发现有一句$frontendObject->setBackend($backendObject);参数$backendObject是factory传入的参数$backend['type'],$backend['type']到底是什么呢,我们在Mage_Core_Model_Cache的构造函数中看到$backend=$this->_getBackendOptions($options)这句,所以$backend是在本类的_getBackendOptions中被设置的,找到_getBackendOptions,code如下:
[php] view plain copy
  1. /** 
  2.  * Get cache backend options. Result array contain backend type ('type' key) and backend options ('options') 
  3.  * 
  4.  * @param   array $cacheOptions 
  5.  * @return  array 
  6.  */  
  7. protected function _getBackendOptions(array $cacheOptions)  
  8. {  
  9.     $enable2levels = false;  
  10.     $type   = isset($cacheOptions['backend']) ? $cacheOptions['backend'] : $this->_defaultBackend;  
  11.     if (isset($cacheOptions['backend_options']) && is_array($cacheOptions['backend_options'])) {  
  12.         $options = $cacheOptions['backend_options'];  
  13.     } else {  
  14.         $options = array();  
  15.     }  
  16.   
  17.     $backendType = false;  
  18.     switch (strtolower($type)) {  
  19.         case 'sqlite':  
  20.             if (extension_loaded('sqlite') && isset($options['cache_db_complete_path'])) {  
  21.                 $backendType = 'Sqlite';  
  22.             }  
  23.             break;  
  24.         case 'memcached':  
  25.             if (extension_loaded('memcache')) {  
  26.                 if (isset($cacheOptions['memcached'])) {  
  27.                     $options = $cacheOptions['memcached'];  
  28.                 }  
  29.                 $enable2levels = true;  
  30.                 $backendType = 'Memcached';  
  31.             }  
  32.             break;  
  33.         case 'apc':  
  34.             if (extension_loaded('apc') && ini_get('apc.enabled')) {  
  35.                 $enable2levels = true;  
  36.                 $backendType = 'Apc';  
  37.             }  
  38.             break;  
  39.         case 'xcache':  
  40.             if (extension_loaded('xcache')) {  
  41.                 $enable2levels = true;  
  42.                 $backendType = 'Xcache';  
  43.             }  
  44.             break;  
  45.         case 'eaccelerator':  
  46.         case 'varien_cache_backend_eaccelerator':  
  47.             if (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) {  
  48.                 $enable2levels = true;  
  49.                 $backendType = 'Varien_Cache_Backend_Eaccelerator';  
  50.             }  
  51.             break;  
  52.         case 'database':  
  53.             $backendType = 'Varien_Cache_Backend_Database';  
  54.             $options = $this->getDbAdapterOptions();  
  55.             break;  
  56.         default:  
  57.             if ($type != $this->_defaultBackend) {  
  58.                 try {  
  59.                     if (class_exists($type, true)) {  
  60.                         $implements = class_implements($type, true);  
  61.                         if (in_array('Zend_Cache_Backend_Interface'$implements)) {  
  62.                             $backendType = $type;  
  63.                         }  
  64.                     }  
  65.                 } catch (Exception $e) {  
  66.                 }  
  67.             }  
  68.     }  
  69.   
  70.     if (!$backendType) {  
  71.         $backendType = $this->_defaultBackend;  
  72.         foreach ($this->_defaultBackendOptions as $option => $value) {  
  73.             if (!array_key_exists($option$options)) {  
  74.                 $options[$option] = $value;  
  75.             }  
  76.         }  
  77.     }  
  78.   
  79.     $backendOptions = array('type' => $backendType'options' => $options);  
  80.     if ($enable2levels) {  
  81.         $backendOptions = $this->_getTwoLevelsBackendOptions($backendOptions$cacheOptions);  
  82.     }  
  83.     return $backendOptions;  
  84. }  
代码有些长,但这个方法很重要,后端具体使用什么类型存储缓存都是在这里被设置和转换的,有代码分析可知,默认的Backend为file,其他有sqlite, apc, memcached, xcache, eaccelerator, database等几种类型,当backend是memcached, apc,xcache时,magento就自动开启two level cache,具体设置可以自行看function _getTwoLevelsBackendOptions。

接着上面的save分析,本例因为backend设置为apc,所以backend最终的type为TwoLevels(apc默认开启TwoLevels),即调用的是Zend_Cache_Backend_TwoLevels的save 方法;save成功之后,第二次需要输出这个block时,首先会$this->_loadCache(),对于已经缓存过的block,会直接从缓存中取出。
以上就是magento缓存某个block的整个流程,至于具体如何去save,因backend不同会有所不同,可以自行参看源码;clean cache原理类似,不再赘述。
本例以magento 1.5版本为基础进行分析,不同版本code可能会有所不同;

Magento Transactional Emails常规设置

magento 允许我们自行管理电子邮件,修改电子邮件内容和设置电子邮件的一些参数。
我们从一个示例开始学习如何进行邮件管理:登入后台 System -> Transactional Emails
单击Add New Template按钮,将显示New Email Template页面(如下图所示)。在Load Default Template 下拉框中,首先选择您要编辑的现有模板名称,这里我们"New account"模板为例。单击"Load Template" button.然后下面Template Information中将会显示你load模板的内容,就是说在现有的基础上,可以对subject,content,style进行修改,以满足自己特定需求,然后save即可。

现在我们已经创建了电子邮件模板,接下来要告诉 magento 使用自己的电子邮件模板。选择System->Configuration->Customer Configuration -> Create New Account Options 在 Default Welcome Email 中选择我们刚刚保存的模板。

总结一下,首先我们需要加载现有的电子邮件模板从Admin -> System -> Transactional Email,然后去System -> Configuration和这个邮件关联的部分,如果邮件是关于Sales的, 就找到Sales Email, 关于 Customer的话就去 Customer Configuration, 如果是关于Contact Us 就点击 Contacts 标签.进入关联的标签后,在Email Template下拉框中选择对应的模板。
另外邮件发送的时候需要标题,名称和发送邮件的地址。这些仍然是在后台就可以设置,登入Admin -> System -> Configuration -> Store Email Address,这里列出了magento默认的几个邮件组,如General Contact, Sales Representative , Custom Support等;
完成以上步骤后,就可以使用邮件模板发送邮件了,比如你想要改变Order Emails ,登入Admin -> System -> Configuration -> Sales Email -> Order,分别对每个项进行设置即可。

2018年2月27日星期二

8 Healthcare SEO Tips to Keep Medical Practices in the Game

SEO, or search engine optimization, is one of the most important tools required in order to build a successful blog or website today.
Optimizing a website for search engines offers a variety of benefits that help to boost online visibility while ultimately increasing the number of page views and visitors you receive each day.
Implementing a few SEO tips when working in the healthcare industry can help to keep medical practices in the game and competing online for visitors and visibility.

Research Trending Topics and Keywords in Your Healthcare Niche

Research the latest trending topics and most relevant keywords in your niche using tools such as Google Trends and Google Analytics.
Post content and share updates using trending words and phrases to help boost your website’s SEO while also attracting the right audience and demographic.

Choose Appropriate Page Titles and Headers

Always use proper grammar and punctuation when crafting new page and post titles for your website. Avoid using hyphens whenever possible.
  • Create titles based on the most significant topic covered in each piece you share.
  • Research the keywords you want to use in your title to compare popularity and the current trend of the search.
Optimize each of your post’s titles each time you create and update.

Share Links to Other Content of Yours in Your Posts

Sharing links to other posts you have on your website or blog with each new update is a way to boost SEO. It also increases page views from visitors who are actively browsing.
Including links to other content on your site with each new post is a quick way to create a sitemap. A sitemap helps search engine bots to virtually “crawl” your website much easier and in less time.

Use a CMS That Support SEO Plugins

Use a content management system (CMS) such as WordPress that allows you to install SEO-related plugins.
With the right SEO plugins and a CMS such as WordPress, always guarantee that each piece of content you publish is fully optimized for all search engines.
  • Implement tags, meta tags, and other keywords for each page
  • Use your choice of SEO plugins and CMS
If you are unsure of how to go about implementing CMS such as WordPress and want an optimized healthcare website, consider hiring a professional web design company.
Using an advanced CMS is highly recommended for optimal tools to manage and improve SEO and content management.

Allow Guests to Contribute Their Posts to Your Website

Allow other medical practitioners and professionals to contribute guest posts to your blog. They are likely to share a link to your website using their social media profiles or official websites and blogs, boosting your SEO.
The more interaction you gain from other websites, the higher up your website will appear within the first pages of search results.

Guest Blog on Another Site

Connect with other medical professionals in your field to inquire about guest-blogging on their websites or social media pages. In exchange, offer them a spot on your blog or within the next update you publish on social media.
When you share your posts on other professional pages or websites, you increase your credibility while building a positive, professional relationship for yourself in the medical field online.
The more your website’s link and optimized headlines appear on other websites, the better your search engine ranking.

Create and Link Your Social Media Accounts

Creating social media accounts is necessary for most professionals and companies to survive and thrive today.
Having a social media page specifically for your medical practice or its blog is a way to connect with potential patients. Social media also boosts your website’s SEO with each update you share.
Updating social media pages consistently is key to generating more followers while keeping loyal users genuinely interested in what you have to say.
  • Cross-post your updates using multiple social media platforms such as Facebook, Instagram, LinkedIn, and Twitter.
  • Choose the top keywords in your medical niche to grab the attention of new potential followers.
Create a posting schedule to prevent your followers from becoming bored or disinterested in your content.

Share Relevant and Engaging Updates on Social Media Using Relevant Keywords

Share relevant and engaging updates in your field of medicine on social media. Be sure to use relevant keywords in the title of the post you link.
Also include your selected keyword in the update you share on social media itself.  This link explains how to choose keywords.
Social media is a great tool to quickly boost your website’s overall search engine optimization organically.
The more optimized your website and online presence is, the easier it becomes to reach potential patients and clients in any field or industry.

Implementing the right SEO tips and tricks can help you to quickly boost your medical practice’s overall ranking in both local and international search results across top engines today such as Google, Yahoo!, and Bing.

Also Read: