Home  >  Article  >  php教程  >  SmartWiki Development Diary Laravel Cache Extension

SmartWiki Development Diary Laravel Cache Extension

WBOY
WBOYOriginal
2016-12-05 13:26:251605browse

For the introduction to SmartWiki, please read: http://www.cnblogs.com/lifeil/p/6113323.html

Because the SmartWiki demo site is deployed on Alibaba Cloud, Alibaba Cloud has a 128M free Memcache service. After configuring it according to the Memcached configuration method, I found that Laravel reported an error. Check the log and the error location is addServer error and cannot connect to Alibaba Cloud. Memcache.

I was helpless, so I wrote a script according to the Alibaba Cloud installation manual and put it on the server. As a result, I could connect and write.

The script provided by Alibaba Cloud is as follows:

<?<span style="color: #000000">php
</span><span style="color: #800080">$connect</span> = <span style="color: #0000ff">new</span> Memcached;  <span style="color: #008000">//</span><span style="color: #008000">声明一个新的memcached链接</span>
<span style="color: #800080">$connect</span>->setOption(Memcached::OPT_COMPRESSION, <span style="color: #0000ff">false</span>); <span style="color: #008000">//</span><span style="color: #008000">关闭压缩功能</span>
<span style="color: #800080">$connect</span>->setOption(Memcached::OPT_BINARY_PROTOCOL, <span style="color: #0000ff">true</span>); <span style="color: #008000">//</span><span style="color: #008000">使用binary二进制协议</span>
<span style="color: #800080">$connect</span>->addServer('00000000.ocs.aliyuncs.com', 11211); <span style="color: #008000">//</span><span style="color: #008000">添加OCS实例地址及端口号
//$connect->setSaslAuthData('aaaaaaaaaa, 'password'); //设置OCS帐号密码进行鉴权,如已开启免密码功能,则无需此步骤</span>
<span style="color: #800080">$connect</span>->set("hello", "world"<span style="color: #000000">);
</span><span style="color: #0000ff">echo</span> 'hello: ',<span style="color: #800080">$connect</span>->get("hello"<span style="color: #000000">);
</span><span style="color: #008080">print_r</span>( <span style="color: #800080">$connect</span>-><span style="color: #000000">getVersion());
</span><span style="color: #800080">$connect</span>->quit();

Looking at laravel's Memcached driver, the code to create a Memcached object in /vendor/laravel/framework/src/Illuminate/Cache/MemcachedConnector.php is as follows:

<span style="color: #0000ff">public</span> <span style="color: #0000ff">function</span> connect(<span style="color: #0000ff">array</span> <span style="color: #800080">$servers</span><span style="color: #000000">)
{
    </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>-><span style="color: #000000">getMemcached();
    </span><span style="color: #008000">//</span><span style="color: #008000"> For each server in the array, we'll just extract the configuration and add
    // the server to the Memcached connection. Once we have added all of these
    // servers we'll verify the connection is successful and return it back.</span>
    <span style="color: #0000ff">foreach</span> (<span style="color: #800080">$servers</span> <span style="color: #0000ff">as</span> <span style="color: #800080">$server</span><span style="color: #000000">) {
        </span><span style="color: #800080">$memcached</span>-><span style="color: #000000">addServer(
            </span><span style="color: #800080">$server</span>['host'], <span style="color: #800080">$server</span>['port'], <span style="color: #800080">$server</span>['weight'<span style="color: #000000">]
        );
    }
    </span><span style="color: #800080">$memcachedStatus</span> = <span style="color: #800080">$memcached</span>-><span style="color: #000000">getVersion();
    </span><span style="color: #0000ff">if</span> (! <span style="color: #008080">is_array</span>(<span style="color: #800080">$memcachedStatus</span><span style="color: #000000">)) {
        </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('No Memcached servers added.'<span style="color: #000000">);
    }
    </span><span style="color: #0000ff">if</span> (<span style="color: #008080">in_array</span>('255.255.255', <span style="color: #800080">$memcachedStatus</span>) && <span style="color: #008080">count</span>(<span style="color: #008080">array_unique</span>(<span style="color: #800080">$memcachedStatus</span>)) === 1<span style="color: #000000">) {
        </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('Could not establish Memcached connection.'<span style="color: #000000">);
    }
    </span><span style="color: #0000ff">return</span> <span style="color: #800080">$memcached</span><span style="color: #000000">;
}</span>

You can see that Laravel's Memcached does not have the option to set the setOption method. It only includes the simplest connection establishment, and then calls getVersion to test whether it is connected. Alibaba Cloud's demo code sets the options to turn off compression and use the binary binary protocol.

There is no choice but to extend the functions of Memcached yourself to implement custom options. The extended cache in laravel can be extended using Cache::extend. The extension code is as follows:

Cache::extend('MemcachedExtend', <span style="color: #0000ff">function</span> (<span style="color: #800080">$app</span><span style="color: #000000">) {

    </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>->createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">);

    </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取缓存前缀</span>
    <span style="color: #800080">$prefix</span> = <span style="color: #800080">$app</span>['config']['cache.prefix'<span style="color: #000000">];

    </span><span style="color: #008000">//</span><span style="color: #008000"> 创建 MemcachedStore 对象</span>
    <span style="color: #800080">$store</span> = <span style="color: #0000ff">new</span> MemcachedStore(<span style="color: #800080">$memcached</span>, <span style="color: #800080">$prefix</span><span style="color: #000000">);

    </span><span style="color: #008000">//</span><span style="color: #008000"> 创建 Repository 对象,并返回</span>
    <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Repository(<span style="color: #800080">$store</span><span style="color: #000000">);
});</span>
<span style="color: #008000">/*</span><span style="color: #008000">*
 * 创建Memcached对象
 * @param $app
 * @return mixed
 </span><span style="color: #008000">*/</span>
<span style="color: #0000ff">protected</span> <span style="color: #0000ff">function</span> createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">)
{
    </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 Memcached 服务器配置</span>
    <span style="color: #800080">$servers</span> = <span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.servers'<span style="color: #000000">];


    </span><span style="color: #008000">//</span><span style="color: #008000"> 利用 Illuminate\Cache\MemcachedConnector 类来创建新的 Memcached 对象</span>
    <span style="color: #800080">$memcached</span> = <span style="color: #0000ff">new</span><span style="color: #000000"> \Memcached;

    </span><span style="color: #0000ff">foreach</span> (<span style="color: #800080">$servers</span> <span style="color: #0000ff">as</span> <span style="color: #800080">$server</span><span style="color: #000000">) {
        </span><span style="color: #800080">$memcached</span>-><span style="color: #000000">addServer(
            </span><span style="color: #800080">$server</span>['host'], <span style="color: #800080">$server</span>['port'], <span style="color: #800080">$server</span>['weight'<span style="color: #000000">]
        );
    }

    </span><span style="color: #008000">//</span><span style="color: #008000"> 如果服务器上的 PHP Memcached 扩展支持 SASL 认证</span>
    <span style="color: #0000ff">if</span> (<span style="color: #008080">ini_get</span>('memcached.use_sasl') && <span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_user']) && <span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_pass'<span style="color: #000000">])) {

        </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 sasl 认证用户名</span>
        <span style="color: #800080">$user</span> = <span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_user'<span style="color: #000000">];

        </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 sasl 认证密码</span>
        <span style="color: #800080">$pass</span> = <span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_pass'<span style="color: #000000">];

        </span><span style="color: #008000">//</span><span style="color: #008000"> 指定用于 sasl 认证的账号密码</span>
        <span style="color: #800080">$memcached</span>->setSaslAuthData(<span style="color: #800080">$user</span>, <span style="color: #800080">$pass</span><span style="color: #000000">);
    }

    </span><span style="color: #008000">//</span><span style="color: #008000">扩展</span>
    <span style="color: #0000ff">if</span> (<span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.options'<span style="color: #000000">])) {
        </span><span style="color: #0000ff">foreach</span> (<span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.options'] <span style="color: #0000ff">as</span> <span style="color: #800080">$key</span> => <span style="color: #800080">$option</span><span style="color: #000000">) {
            </span><span style="color: #800080">$memcached</span>->setOption(<span style="color: #800080">$key</span>, <span style="color: #800080">$option</span><span style="color: #000000">);
        }
    }
    </span><span style="color: #800080">$memcachedStatus</span> = <span style="color: #800080">$memcached</span>-><span style="color: #000000">getVersion();

    </span><span style="color: #0000ff">if</span> (! <span style="color: #008080">is_array</span>(<span style="color: #800080">$memcachedStatus</span><span style="color: #000000">)) {
        </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('No Memcached servers added.'<span style="color: #000000">);
    }

    </span><span style="color: #0000ff">if</span> (<span style="color: #008080">in_array</span>('255.255.255', <span style="color: #800080">$memcachedStatus</span>) && <span style="color: #008080">count</span>(<span style="color: #008080">array_unique</span>(<span style="color: #800080">$memcachedStatus</span>)) === 1<span style="color: #000000">) {
        </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('Could not establish Memcached connection.'<span style="color: #000000">);
    }

    </span><span style="color: #0000ff">return</span> <span style="color: #800080">$memcached</span><span style="color: #000000">;
}</span>

There are articles about laravel cache extension circulating on the Internet, in which configuration reading is not applicable in versions 5.2 and above.

Cache extension code requires creating a ServiceProvider to register the service provider. The service provider is the center of Laravel application startup. Your own application and all Laravel's core services are started through the service provider.

But what do we mean by “initiation”? Typically, this means registering things, including registering service container bindings, event listeners, middleware, and even routes. Service providers are the center of application configuration.

If you open the config/app.php file that comes with Laravel, you will see a providers array. Here are all the service provider classes to be loaded by the application. Of course, many of them are lazy loaded, which means that they are not loaded every time. Requests will be loaded, and they will only be loaded when they are actually used.

All service providers inherit from the IlluminateSupportServiceProvider class. Most service providers contain two methods: register and boot . In the register method, the only thing you have to do is bind the thing to the service container. Do not try to register event listeners, routes or any other functionality in it.

You can simply generate a new provider through the Artisan command make:provider:

php artisan <span style="color: #0000ff">make</span>:provider MemcachedExtendServiceProvider

All service providers are registered through the configuration file config/app.php. This file contains a providers array listing the names of all service providers. By default, all core service providers are listed. These Service providers start Laravel core components, such as mail, queues, cache, etc.

To register your own service provider, just append it to this array:

<span style="color: #800000">'</span><span style="color: #800000">providers</span><span style="color: #800000">'</span> =><span style="color: #000000"> [
    SmartWiki\Providers\MemcachedExtendServiceProvider::class </span><span style="color: #008000">//</span><span style="color: #008000">在providers节点添加实现的provider</span>
]

Also configure Memcached configuration in config/cache.php:

'MemcachedExtend' =><span style="color: #000000"> [
    </span>'driver' => 'MemcachedExtend',
    'servers' =><span style="color: #000000"> [
        [
            </span>'host' => env('MEMCACHED_EXTEND_HOST', '127.0.0.1'),
            'port' => env('MEMCACHED_EXTEND_PORT', 11211),
            'weight' => 100,<span style="color: #000000">
        ]</span>,<span style="color: #000000">
    ]</span>,
    'options' =><span style="color: #000000"> [
        \Memcached</span>::OPT_BINARY_PROTOCOL => <span style="color: #0000ff">true</span>,<span style="color: #000000">
        \Memcached</span>::OPT_COMPRESSION => <span style="color: #0000ff">false</span><span style="color: #000000">
    ]
]</span>

If you need to store the Session in our extended cache, you also need to call Session::extend to expand our Session storage:

Session::extend('MemcachedExtend',<span style="color: #0000ff">function</span> (<span style="color: #800080">$app</span><span style="color: #000000">){
    </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>->createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">);
    </span><span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> MemcachedSessionHandler(<span style="color: #800080">$memcached</span><span style="color: #000000">);
});</span>

Afterwards, we can configure our expanded cache in .env. The complete code is as follows:

<?<span style="color: #000000">php

namespace SmartWiki\Providers;

</span><span style="color: #0000ff">use</span><span style="color: #000000"> Illuminate\Cache\Repository;
</span><span style="color: #0000ff">use</span><span style="color: #000000"> Illuminate\Cache\MemcachedStore;
</span><span style="color: #0000ff">use</span><span style="color: #000000"> Illuminate\Support\ServiceProvider;

</span><span style="color: #0000ff">use</span><span style="color: #000000"> Cache;
</span><span style="color: #0000ff">use</span><span style="color: #000000"> Session;
</span><span style="color: #0000ff">use</span><span style="color: #000000"> Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler;
</span><span style="color: #0000ff">use</span><span style="color: #000000"> RuntimeException;

</span><span style="color: #0000ff">class</span> MemcachedExtendServiceProvider <span style="color: #0000ff">extends</span><span style="color: #000000"> ServiceProvider
{
    </span><span style="color: #008000">/*</span><span style="color: #008000">*
     * Bootstrap the application services.
     *
     * @return void
     </span><span style="color: #008000">*/</span>
    <span style="color: #0000ff">public</span> <span style="color: #0000ff">function</span><span style="color: #000000"> boot()
    {

        Cache</span>::extend('MemcachedExtend', <span style="color: #0000ff">function</span> (<span style="color: #800080">$app</span><span style="color: #000000">) {

            </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>->createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">);

            </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取缓存前缀</span>
            <span style="color: #800080">$prefix</span> = <span style="color: #800080">$app</span>['config']['cache.prefix'<span style="color: #000000">];

            </span><span style="color: #008000">//</span><span style="color: #008000"> 创建 MemcachedStore 对象</span>
            <span style="color: #800080">$store</span> = <span style="color: #0000ff">new</span> MemcachedStore(<span style="color: #800080">$memcached</span>, <span style="color: #800080">$prefix</span><span style="color: #000000">);

            </span><span style="color: #008000">//</span><span style="color: #008000"> 创建 Repository 对象,并返回</span>
            <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Repository(<span style="color: #800080">$store</span><span style="color: #000000">);
        });

        Session</span>::extend('MemcachedExtend',<span style="color: #0000ff">function</span> (<span style="color: #800080">$app</span><span style="color: #000000">){
            </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>->createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">);


            </span><span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> MemcachedSessionHandler(<span style="color: #800080">$memcached</span><span style="color: #000000">);
        });
    }

    </span><span style="color: #008000">/*</span><span style="color: #008000">*
     * Register the application services.
     *
     * @return void
     </span><span style="color: #008000">*/</span>
    <span style="color: #0000ff">public</span> <span style="color: #0000ff">function</span><span style="color: #000000"> register()
    {
        </span><span style="color: #008000">//
</span><span style="color: #000000">    }

    </span><span style="color: #008000">/*</span><span style="color: #008000">*
     * 创建Memcached对象
     * @param $app
     * @return mixed
     </span><span style="color: #008000">*/</span>
    <span style="color: #0000ff">protected</span> <span style="color: #0000ff">function</span> createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">)
    {
        </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 Memcached 服务器配置</span>
        <span style="color: #800080">$servers</span> = <span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.servers'<span style="color: #000000">];


        </span><span style="color: #008000">//</span><span style="color: #008000"> 利用 Illuminate\Cache\MemcachedConnector 类来创建新的 Memcached 对象</span>
        <span style="color: #800080">$memcached</span> = <span style="color: #0000ff">new</span><span style="color: #000000"> \Memcached;

        </span><span style="color: #0000ff">foreach</span> (<span style="color: #800080">$servers</span> <span style="color: #0000ff">as</span> <span style="color: #800080">$server</span><span style="color: #000000">) {
            </span><span style="color: #800080">$memcached</span>-><span style="color: #000000">addServer(
                </span><span style="color: #800080">$server</span>['host'], <span style="color: #800080">$server</span>['port'], <span style="color: #800080">$server</span>['weight'<span style="color: #000000">]
            );
        }

        </span><span style="color: #008000">//</span><span style="color: #008000"> 如果服务器上的 PHP Memcached 扩展支持 SASL 认证</span>
        <span style="color: #0000ff">if</span> (<span style="color: #008080">ini_get</span>('memcached.use_sasl') && <span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_user']) && <span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_pass'<span style="color: #000000">])) {

            </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 sasl 认证用户名</span>
            <span style="color: #800080">$user</span> = <span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_user'<span style="color: #000000">];

            </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 sasl 认证密码</span>
            <span style="color: #800080">$pass</span> = <span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_pass'<span style="color: #000000">];

            </span><span style="color: #008000">//</span><span style="color: #008000"> 指定用于 sasl 认证的账号密码</span>
            <span style="color: #800080">$memcached</span>->setSaslAuthData(<span style="color: #800080">$user</span>, <span style="color: #800080">$pass</span><span style="color: #000000">);
        }

        </span><span style="color: #008000">//</span><span style="color: #008000">扩展</span>
        <span style="color: #0000ff">if</span> (<span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.options'<span style="color: #000000">])) {
            </span><span style="color: #0000ff">foreach</span> (<span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.options'] <span style="color: #0000ff">as</span> <span style="color: #800080">$key</span> => <span style="color: #800080">$option</span><span style="color: #000000">) {
                </span><span style="color: #800080">$memcached</span>->setOption(<span style="color: #800080">$key</span>, <span style="color: #800080">$option</span><span style="color: #000000">);
            }
        }
        </span><span style="color: #800080">$memcachedStatus</span> = <span style="color: #800080">$memcached</span>-><span style="color: #000000">getVersion();

        </span><span style="color: #0000ff">if</span> (! <span style="color: #008080">is_array</span>(<span style="color: #800080">$memcachedStatus</span><span style="color: #000000">)) {
            </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('No Memcached servers added.'<span style="color: #000000">);
        }

        </span><span style="color: #0000ff">if</span> (<span style="color: #008080">in_array</span>('255.255.255', <span style="color: #800080">$memcachedStatus</span>) && <span style="color: #008080">count</span>(<span style="color: #008080">array_unique</span>(<span style="color: #800080">$memcachedStatus</span>)) === 1<span style="color: #000000">) {
            </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('Could not establish Memcached connection.'<span style="color: #000000">);
        }

        </span><span style="color: #0000ff">return</span> <span style="color: #800080">$memcached</span><span style="color: #000000">;
    }
}</span>
SmartWikiCode

SmartWiki official website: https://www.iminho.me

SmartWiki source code: https://github.com/lifei6671/SmartWiki

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn