让 Laravel 完美支持 Memcache 及使用 zizaco/entrust 权限认证
今天想试着体验一下laravel下的rbac,
于是就找到了zizaco/entrust
由于我使用的是windows环境,根本用不了memcached,而entrust必须使用非file/database形式的缓存
所以我决定使用memcache来替代,以下是下解决办法。
Memcache完善部分
-
修改Vendor\Illuminate\Cache\CacheServiceProvider.php,添加以下代码:
$this->app->singleton('memcache.connector', function () { return new MemcacheConnector; });
-
修改Vendor\Illuminate\Cache\CacheManager.php,添加以下代码:
/** * Create an instance of the Memcache cache driver. * * @param array $config * @return \Illuminate\Cache\MemcachedStore */ protected function createMemcacheDriver(array $config) { $prefix = $this->getPrefix($config); $memcache = $this->app['memcache.connector']->connect($config['servers']); return $this->repository(new MemcacheStore($memcache, $prefix)); }
-
添加Vendor\Illuminate\Cache\MemcacheConnetcor.php,
这是因为memcache->getVersion不同于memCache,只会返回一个版本字符串。<?php namespace Illuminate\Cache; use Memcache; use RuntimeException; class MemcacheConnector { /** * Create a new Memcache connection. * * @param array $servers * @return \Memcache * * @throws \RuntimeException */ public function connect(array $servers) { $memcache = $this->getMemcache(); // For each server in the array, we'll just extract the configuration and add // the server to the Memcache connection. Once we have added all of these // servers we'll verify the connection is successful and return it back. foreach ($servers as $server) { $memcache->addServer( $server['host'], $server['port'], true, $server['weight'] ); } $memcachedStatus = $memcache->getVersion(); if (!($memcachedStatus)) { throw new RuntimeException('No Memcache servers added.'); } return $memcache; } /** * Get a new Memcache instance. * * @return \Memcache */ protected function getMemcache() { return new Memcache; } }
-
你还需要添加Vendor\Illuminate\Cache\MemcacheStore.php,这个文件是实现Cache的方法的,
由于memcached的很多方法在memcache中是不存在的,所以你需要重写这部分代码。<?php namespace Illuminate\Cache; use Memcache; use Illuminate\Contracts\Cache\Store; class MemcachedStore extends TaggableStore implements Store { /** * The Memcached instance. * * @var \Memcache */ protected $memcache; /** * A string that should be prepended to keys. * * @var string */ protected $prefix; /** * Create a new Memcache store. * * @param \Memcache $memcache * @param string $prefix * @return void */ public function __construct($memcache, $prefix = '') { $this->setPrefix($prefix); $this->memcache = $memcache; } /** * Retrieve an item from the cache by key. * * @param string|array $key * @return mixed */ public function get($key) { $value = $this->memcache->get($this->prefix.$key); if ($this->memcache->getResultCode() == 0) { return $value; } } /** * Retrieve multiple items from the cache by key. * * Items not found in the cache will have a null value. * * @param array $keys * @return array */ public function many(array $keys) { $prefixedKeys = array_map(function ($key) { return $this->prefix.$key; }, $keys); $values = $this->memcache->getMulti($prefixedKeys, null, Memcached::GET_PRESERVE_ORDER); if ($this->memcache->getResultCode() != 0) { return array_fill_keys($keys, null); } return array_combine($keys, $values); } /** * Store an item in the cache for a given number of minutes. * * @param string $key * @param mixed $value * @param int $minutes * @return void */ public function put($key, $value, $minutes) { $this->memcache->set($this->prefix.$key, $value, $minutes * 60); } /** * Store multiple items in the cache for a given number of minutes. * * @param array $values * @param int $minutes * @return void */ public function putMany(array $values, $minutes) { $prefixedValues = []; foreach ($values as $key => $value) { $prefixedValues[$this->prefix.$key] = $value; $this->put($this->prefix.$key, $value, $minutes * 60); } // $this->memcache->setMulti($prefixedValues, $minutes * 60); } /** * Store an item in the cache if the key doesn't exist. * * @param string $key * @param mixed $value * @param int $minutes * @return bool */ public function add($key, $value, $minutes) { return $this->memcache->add($this->prefix.$key, $value, $minutes * 60); } /** * Increment the value of an item in the cache. * * @param string $key * @param mixed $value * @return int|bool */ public function increment($key, $value = 1) { return $this->memcache->increment($this->prefix.$key, $value); } /** * Decrement the value of an item in the cache. * * @param string $key * @param mixed $value * @return int|bool */ public function decrement($key, $value = 1) { return $this->memcache->decrement($this->prefix.$key, $value); } /** * Store an item in the cache indefinitely. * * @param string $key * @param mixed $value * @return void */ public function forever($key, $value) { $this->put($key, $value, 0); } /** * Remove an item from the cache. * * @param string $key * @return bool */ public function forget($key) { return $this->memcache->delete($this->prefix.$key); } /** * Remove all items from the cache. * * @return void */ public function flush() { $this->memcache->flush(); } /** * Get the underlying Memcached connection. * * @return \Memcached */ public function getMemcache() { return $this->memcache; } /** * Get the cache key prefix. * * @return string */ public function getPrefix() { return $this->prefix; } /** * Set the cache key prefix. * * @param string $prefix * @return void */ public function setPrefix($prefix) { $this->prefix = ! empty($prefix) ? $prefix.':' : ''; } }
-
修改Vendor\Illuminate\Cache\Repository.php,主要问题是使用memcache时,如果不存在返回的是false,而不是null,所以你需要修改使用!empty($value)来判定。为了最小化的影响代码,if($this->getStore() instanceof MemcacheStore)来判定当前的cache是Memcache.
/** * Determine if an item exists in the cache. * * @param string $key * @return bool */ public function has($key) { if($this->getStore() instanceof MemcacheStore) { return ! empty($this->get($key)); } return ! is_null($this->get($key)); } </code> <code> public function remember($key, $minutes, Closure $callback) { // If the item exists in the cache we will just return this immediately // otherwise we will execute the given Closure and cache the result // of that execution for the given number of minutes in storage. //add by liuxc for memcache. if($this->getStore() instanceof MemcacheStore) { $value = $this->get($key); if(!empty($value)) return $value; $this->put($key, $value = $callback(), $minutes); return $value; } if (! is_null($value = $this->get($key))) { return $value; } $this->put($key, $value = $callback(), $minutes); return $value; }
至此laravel可以完美支持memcache了。接下来只要改少量代码就可以支持zizaco/entrust
zizaco/entrust修改部分
-
由于\vendor\zizaco\entrust\src\Traits\entrustUserTrait.php中调用了Config::get('cache.ttl')作为缓存时间,如下:
public function cachedRoles() { $userPrimaryKey = $this->primaryKey; $cacheKey = 'entrust_roles_for_user_'.$this->$userPrimaryKey; return Cache::tags(Config::get('entrust.role_user_table'))->remember($cacheKey, Config::get('cache.ttl'), function(){ return $this->roles()->get(); }); }
-
所以你可能需要修改Config/Cache.php并添加以下代码
//add for cache tag minutes; 'ttl' =>'60',
-
修改\vendor\laravel\framework\src\illuminate\Foundation\Auth\User.php
**注意,在修改之后使用Auth::user->may()而不是用can()方法。use Zizaco\Entrust\Traits\EntrustUserTrait; class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract { use Authenticatable, Authorizable, CanResetPassword,EntrustUserTrait { EntrustUserTrait::can as may; Authorizable::can insteadof EntrustUserTrait; } }
-
修改\vendor\zizaco\entrust\src\Entrust\Entrust.php 中的can 方法,这样你才可能是blade模版中愉快地使用@permission了。
/** * Check if the current user has a permission by its name * * @param string $permission Permission string. * * @return bool */ public function can($permission, $requireAll = false) { if ($user = $this->user()) { return $user->may($permission, $requireAll); } return false; }
推荐文章: