Advertisement
  1. Code
  2. PHP
  3. Laravel

Laravel Unwrapped: Session, Auth and Cache

Scroll to top

In recent years, Laravel has become one of the most prominent frameworks software engineers use for building their web applications. Similar to the popularity that CodeIgniter enjoyed in its heyday, Laravel has been lauded for its ease-of-use, friendliness to beginners and its adherence to industry standards.

Introduction

One thing though that not a lot of programmers take advantage of is Laravel's component-based system. Since its conversion to composer-powered components, Laravel 4 has become a very modular system, similar to the verbosity of more mature frameworks like Symfony. This is called the Illuminate group of components, which in my opinion, is not the actual framework itself, but is a compilation of libraries that a framework can potentially use. Laravel's actual framework is represented by the Laravel skeleton application (found on the laravel/laravel GitHub repository) that makes use of these components to build a web application.

In this tutorial, we'll be diving into a group of these components, learning how they work, how they're used by the framework, and how we can extend their functionality.

The Session Component

The Laravel Session component handles sessions for the web application. It makes use of a driver-based system called the Laravel Manager, which acts as both a factory and a wrapper for whichever driver is set in the configuration file. As of this writing, the Session component has drivers for:

  • file - a file-based session driver where session data is saved in an encrypted file.
  • cookie - a cookie-based session driver where session data is encrypted in the user's cookies.
  • database - session data is saved in whichever database is configured for the application.
  • apc - session data is saved in APC.
  • memcached - session data is saved in Memcached.
  • redis - session data is saved in Redis.
  • array - session data is saved in a PHP array. Take note that the array session driver does not support persistence and is usually only used in console commands.

Service Providers

Most Laravel users don't realize but a big part of how Laravel works, is within its service providers. They are essentially bootstrap files for each component and they are abstracted enough so users can bootstrap any components, in any way.

A rough explanation of how this works is below:

  1. The Laravel Application component is initiated. This is the main driver of the whole framework, responsible for handling the HTTP Request, running the service providers, as well as acting as a dependency container for the framework.
  2. Once a service provider is ran, its register method is called. This allows us to instantiate whichever component we want.
    • Keep in mind that all service providers have access to the main Laravel application (via $this->app), which would let service providers push instances of the resolved classes into the dependency container.
  3. Once these dependencies are loaded, we should be free to use them by calling on the container, for example, via Laravel's Facade system, App::make.

Going back to Sessions, let's take a quick look at the SessionServiceProivider:

1
 /**

2
     * Register the session manager instance.

3
	 *

4
	 * @return void

5
	 */
6
	protected function registerSessionManager()
7
	{
8
		$this->app->bindShared('session', function($app)
9
		{
10
			return new SessionManager($app);
11
		});
12
	}
13
14
	/**

15
	 * Register the session driver instance.

16
	 *

17
	 * @return void

18
	 */
19
	protected function registerSessionDriver()
20
	{
21
		$this->app->bindShared('session.store', function($app)
22
		{
23
			// First, we will create the session manager which is responsible for the

24
			// creation of the various session drivers when they are needed by the

25
			// application instance, and will resolve them on a lazy load basis.

26
			$manager = $app['session'];
27
28
			return $manager->driver();
29
		});
30
	}

These two methods are called by the register() function. The first one, registerSessionManager(), is called to initially register the SessionManager. This class extends the Manager that I mentioned on top. The second one, registerSessionDriver() registers a session handler for the manager, based on what we have configured. This eventually calls this method in the Illuminate\Support\Manager class:

1
/**

2
     * Create a new driver instance.

3
	 *

4
	 * @param  string  $driver

5
	 * @return mixed

6
	 *

7
	 * @throws \InvalidArgumentException

8
	 */
9
	protected function createDriver($driver)
10
	{
11
		$method = 'create'.ucfirst($driver).'Driver';
12
13
		// We'll check to see if a creator method exists for the given driver. If not we

14
		// will check for a custom driver creator, which allows developers to create

15
		// drivers using their own customized driver creator Closure to create it.

16
		if (isset($this->customCreators[$driver]))
17
		{
18
			return $this->callCustomCreator($driver);
19
		}
20
		elseif (method_exists($this, $method))
21
		{
22
			return $this->$method();
23
		}
24
25
		throw new \InvalidArgumentException("Driver [$driver] not supported.");
26
	}

From here, we can see that based on the name of the driver, from the configuration file, a specific method is called. So, if we have it configured to use the file session handler, it will call this method in the SessionManager class:

1
/**

2
     * Create an instance of the file session driver.

3
	 *

4
	 * @return \Illuminate\Session\Store

5
	 */
6
	protected function createFileDriver()
7
	{
8
		return $this->createNativeDriver();
9
	}
10
11
	/**

12
	 * Create an instance of the file session driver.

13
	 *

14
	 * @return \Illuminate\Session\Store

15
	 */
16
	protected function createNativeDriver()
17
	{
18
		$path = $this->app['config']['session.files'];
19
20
		return $this->buildSession(new FileSessionHandler($this->app['files'], $path));
21
	}

The driver class is then injected into a Store class, which is responsible for calling the actual session methods. This lets us actually separate the implementation of the SessionHandlerInterface from the SPL into the drivers, the Store class facilitates it.

Creating Our Own Session Handler

Let's create our own Session Handler, a MongoDB Session handler. First off, we'll need to create a MongoSessionHandler inside a newly installed Laravel project instance. (We'll be borrowing heavily from Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler).:

1
<?php namespace Illuminate\Session;
2
3
    use Mongo;
4
    use MongoDate;
5
    use MongoBinData;
6
7
    class MongoSessionHandler implements \SessionHandlerInterface
8
    {
9
        /**

10
         * Mongo db config

11
         *

12
         * @var array

13
         */
14
        protected $config;
15
16
        /**

17
         * Mongo db connection

18
         * 

19
         * @var \Mongo

20
         */
21
        protected $connection;
22
23
        /**

24
         * Mongodb collection

25
         * 

26
         * @var \MongoCollection

27
         */
28
        protected $collection;
29
        /**

30
         * Create a new Mongo driven handler instance.

31
         *

32
         * @param  array $config

33
         *  - $config['host']       Mongodb host

34
         *  - $config['username']   Mongodb username

35
         *  - $config['password']   Mongodb password

36
         *  - $config['database']     Mongodb database

37
         *  - $config['collection'] Mongodb collection

38
         * @return void

39
         */
40
        public function __construct(array $config)
41
        {
42
            $this->config = $config;
43
44
            $connection_string = 'mongodb://';
45
46
            if (!empty($this->config['username']) && !empty($this->config['password'])) {
47
                $connection_string .= "{$this->config['user']}:{$this->config['password']}@";
48
            }
49
50
            $connection_string .= "{$this->config['host']}";
51
52
            $this->connection = new Mongo($connection_string);
53
54
            $this->collection = $this->connection->selectCollection($this->config['database'], $this->config['collection']);
55
        }
56
57
        /**

58
         * {@inheritDoc}

59
         */
60
        public function open($savePath, $sessionName)
61
        {
62
            return true;
63
        }
64
65
        /**

66
         * {@inheritDoc}

67
         */
68
        public function close()
69
        {
70
            return true;
71
        }
72
73
        /**

74
         * {@inheritDoc}

75
         */
76
        public function read($sessionId)
77
        {
78
            $session_data = $this->collection->findOne(array(
79
                '_id' => $sessionId,
80
            ));
81
82
            if (is_null($session_data)) {
83
                return '';
84
            } else {
85
                return $session_data['session_data']->bin;
86
            }
87
        }
88
89
        /**

90
         * {@inheritDoc}

91
         */
92
        public function write($sessionId, $data)
93
        {
94
            $this->collection->update(
95
                array(
96
                    '_id' => $sessionId
97
                ),
98
                array(
99
                    '$set' => array(
100
                        'session_data' => new MongoBinData($data, MongoBinData::BYTE_ARRAY),
101
                        'timestamp' => new MongoDate(),
102
                    )
103
                ),
104
                array(
105
                    'upsert' => true,
106
                    'multiple' => false
107
                )
108
            );
109
        }
110
111
        /**

112
         * {@inheritDoc}

113
         */
114
        public function destroy($sessionId)
115
        {
116
            $this->collection->remove(array(
117
                '_id' => $sessionId
118
            ));
119
120
            return true;
121
        }
122
123
        /**

124
         * {@inheritDoc}

125
         */
126
        public function gc($lifetime)
127
        {
128
            $time = new MongoDate(time() - $lifetime);
129
130
            $this->collection->remove(array(
131
                'timestamp' => array('$lt' => $time),
132
            ));
133
134
            return true;
135
        }
136
    }

You should save this in the vendor/laravel/framework/src/Illuminate/Session folder. For the purposes of this project, we'll put it here, but ideally this file should be within its own library namespace.

Next, we need to make sure that the Manager class can call this driver. We can do this by utilizing the Manager::extend method. Open vendor/laravel/framework/src/Illuminate/Session/SessionServiceProvider.php and add the following code. Ideally, we should be extending the service provider, but that is outside the scope of this tutorial.

1
/**

2
     * Setup the Mongo Driver callback

3
	 *

4
	 * @return  void

5
	 */
6
	public function setupMongoDriver()
7
	{
8
		$manager = $this->app['session'];
9
10
		$manager->extend('mongo', function($app) {
11
		    return new MongoSessionHandler(array(
12
		        'host'       => $app['config']->get('session.mongo.host'),
13
		        'username'   => $app['config']->get('session.mongo.username'),
14
		        'password'   => $app['config']->get('session.mongo.password'),
15
		        'database'   => $app['config']->get('session.mongo.database'),
16
		        'collection' => $app['config']->get('session.mongo.collection')
17
		    ));
18
		});
19
	}

Make sure to update the register() method to call this method:

1
/**

2
     * Register the service provider.

3
	 *

4
	 * @return void

5
	 */
6
	public function register()
7
	{
8
		$this->setupDefaultDriver();
9
10
		$this->registerSessionManager();
11
12
		$this->setupMongoDriver();
13
14
		$this->registerSessionDriver();
15
	}

Next, we need to define the Mongo DB configuration. Open app/config/session.php and define the following configuration settings:

1
/**

2
     * Mongo DB settings

3
	 */
4
	'mongo' => array(
5
		'host' => '127.0.0.1',
6
		'username' => '',
7
		'password' => '',
8
		'database' => 'laravel',
9
		'collection' => 'laravel_session_collection'
10
	)

While we're on this file, we should also update the driver configuration up top:

1
'driver' => 'mongo'

Now, try and access the main page (usually, localhost/somefolder/public). If this page loads without showing the WHOOPS page, then congratulations, we've successfully created a brand new session driver! Test it out by setting some dummy data on the session, via Session::set() and then echoing it back via Session::get().

The Auth Component

The Laravel Auth component handles user authentication for the framework, as well as password management. What the Laravel component has done here is to create an abstract interpretation of the typical user-management system which is usable in most web applications, which in turn helps the programmer easily implement a login system. Like the Session component, it also makes use of the Laravel Manager. Currently, the Auth component has drivers for:

  • eloquent - this makes use of Laravel's built-in ORM called Eloquent. It also utilizes the pre-made User.php class inside the models folder.
  • database - this uses whichever database connection is configured by default. It makes use of a GenericUser class for accessing the user data.

Since this follows the same implementation as the Session component, the service provider is very similar to what we've seen on top:

1
/**

2
     * Register the service provider.

3
	 *

4
	 * @return void

5
	 */
6
	public function register()
7
	{
8
		$this->app->bindShared('auth', function($app)
9
		{
10
			// Once the authentication service has actually been requested by the developer

11
			// we will set a variable in the application indicating such. This helps us

12
			// know that we need to set any queued cookies in the after event later.

13
			$app['auth.loaded'] = true;
14
15
			return new AuthManager($app);
16
		});
17
	}

Here, we can see that it basically creates an AuthManager class that wraps around whichever driver we're using, as well as acting as a factory for it. Inside the AuthManager, it again creates the appropriate driver, wrapped around a Guard class, which acts the same way as the Store class from Session.

Creating Our Own Auth Handler

Like before, let's start by creating a MongoUserProvider:

1
<?php namespace Illuminate\Auth;
2
3
    use Mongo;
4
    use Illuminate\Hashing\HasherInterface;
5
6
    class MongoUserProvider implements UserProviderInterface {
7
8
        /**

9
         * The mongo instance

10
         *

11
         * @param  \Mongo

12
         */
13
        protected $connection;
14
15
        /**

16
         * The mongo connection instance

17
         *

18
         * @param  \MongoConnection

19
         */
20
        protected $collection;
21
22
        /**

23
         * The Mongo config array

24
         *

25
         * @var array

26
         */
27
        protected $config;
28
29
        /**

30
         * Create a new Mongo user provider.

31
         *

32
         * @param  array $config

33
         *     - $config['host']       Mongodb host

34
         *     - $config['username']   Mongodb username

35
         *     - $config['password']   Mongodb password

36
         *     - $config['database']   Mongodb database

37
         *     - $config['collection'] Mongodb collection

38
         * @return void

39
         */
40
        public function __construct(array $config)
41
        {
42
            $this->config = $config;
43
44
            $connection_string = 'mongodb://';
45
46
            if (!empty($this->config['username']) && !empty($this->config['password'])) {
47
                $connection_string .= "{$this->config['user']}:{$this->config['password']}@";
48
            }
49
50
            $connection_string .= "{$this->config['host']}";
51
52
            $this->connection = new Mongo($connection_string);
53
54
            $this->collection = $this->connection->selectCollection($this->config['database'], $this->config['collection']);
55
        }
56
57
        /**

58
         * Retrieve a user by their unique identifier.

59
         *

60
         * @param  mixed  $identifier

61
         * @return \Illuminate\Auth\UserInterface|null

62
         */
63
        public function retrieveById($identifier)
64
        {
65
            $user_data = $this->collection->findOne(array(
66
                '_id' => $identifier,
67
            ));
68
69
            if (!is_null($user_data)) {
70
                return new GenericUser((array) $user_data);
71
            }
72
        }
73
74
        /**

75
         * Retrieve a user by the given credentials.

76
         *

77
         * @param  array  $credentials

78
         * @return \Illuminate\Auth\UserInterface|null

79
         */
80
        public function retrieveByCredentials(array $credentials)
81
        {
82
            // Attempt to look for the user first regardless of password

83
            // We'll do that in the validateCredentials method

84
            if (isset($credentials['password'])) {
85
                unset($credentials['password']);
86
            }
87
88
            $user_data = $this->collection->findOne($credentials);
89
90
            if (!is_null($user_data)) {
91
                return new GenericUser((array) $user_data);
92
            }
93
        }
94
95
        /**

96
         * Validate a user against the given credentials.

97
         *

98
         * @param  \Illuminate\Auth\UserInterface  $user

99
         * @param  array  $credentials

100
         * @return bool

101
         */
102
        public function validateCredentials(UserInterface $user, array $credentials)
103
        {
104
            if (!isset($credentials['password'])) {
105
                return false;
106
            }
107
            
108
            return ($credentials['password'] === $user->getAuthPassword());
109
        }
110
    }

It's important to take note here that I'm not checking against a hashed password, this was done for simplicity's sake to make it easier on our part to create dummy data and test this later. In production code, you need to make sure to hash the password. Check out the Illuminate\Auth\DatabaseUserProvider class for a great example on how to do this.

Afterwards, we need to register our custom driver callback on the AuthManager. To do so, we need to update the service provider's register method:

1
/**

2
     * Register the service provider.

3
	 *

4
	 * @return void

5
	 */
6
	public function register()
7
	{
8
		$this->app->bindShared('auth', function($app)
9
		{
10
			// Once the authentication service has actually been requested by the developer

11
			// we will set a variable in the application indicating such. This helps us

12
			// know that we need to set any queued cookies in the after event later.

13
			$app['auth.loaded'] = true;
14
15
			$auth_manager = new AuthManager($app);
16
17
			$auth_manager->extend('mongo', function($app) {
18
				return new MongoUserProvider(
19
					array(
20
						'host'       => $app['config']->get('auth.mongo.host'),
21
				        'username'   => $app['config']->get('auth.mongo.username'),
22
				        'password'   => $app['config']->get('auth.mongo.password'),
23
				        'database'   => $app['config']->get('auth.mongo.database'),
24
				        'collection' => $app['config']->get('auth.mongo.collection')
25
					)
26
				);
27
			});
28
29
			return $auth_manager;
30
		});
31
	}

Lastly, we also need to update the auth.php configuration file to make use of the Mongo driver, as well as provide it the proper Mongo configuration values:

1
'driver' => 'mongo',
2
    ...
3
    ...
4
    ...
5
    /**

6
     * Mongo DB settings

7
	 */
8
	'mongo' => array(
9
		'host' => '127.0.0.1',
10
		'username' => '',
11
		'password' => '',
12
		'database' => 'laravel',
13
		'collection' => 'laravel_auth_collection'
14
	)

Testing this is a little trickier, to do so, use the Mongo DB CLI to insert a new user into the collection:

1
mongo
2
3
    > use laravel_auth
4
    switched to db laravel_auth
5
    > db.laravel_auth_collection.insert({id: 1, email:"nikko@nikkobautista.com", password:"test_password"})
6
    > db.laravel_auth_collection.find()
7
    > { "_id" : ObjectId("530c609f2caac8c3a8e4814f"), "id" 1, "email" : "nikko@emailtest.com", "password" : "test_password" }

Now, test it out by trying an Auth::validate method call:

1
var_dump(Auth::validate(array('email' => 'nikko@emailtest.com', 'password' => 'test_password')));

This should dump a bool(true). If it does, then we've successfully created our own Auth driver!

The Cache Component

The Laravel Cache component handles caching mechanisms for use in the framework. Like both of the components that we've discussed, it also makes use of the Laravel Manager (Are you noticing a pattern?). The Cache component has drivers for:

  • apc
  • memcached
  • redis
  • file - a file-based cache. Data is saved into the app/storage/cache path.
  • database - database-based cache. Data is saved into rows into the database. The database schema is described in the Laravel Documentation.
  • array - data is "cached" in an array. Keep in mind that the array cache is not persistent and is cleared on every page load.

Since this follows the same implementation as both components that we've discussed, you can safely assume that the service provider is fairly similar:

1
/**

2
     * Register the service provider.

3
	 *

4
	 * @return void

5
	 */
6
	public function register()
7
	{
8
		$this->app->bindShared('cache', function($app)
9
		{
10
			return new CacheManager($app);
11
		});
12
13
		$this->app->bindShared('cache.store', function($app)
14
		{
15
			return $app['cache']->driver();
16
		});
17
18
		$this->app->bindShared('memcached.connector', function()
19
		{
20
			return new MemcachedConnector;
21
		});
22
23
		$this->registerCommands();
24
	}

The register() method here creates a CacheManager, that again acts as a wrapper and factory for the drivers. Within the manager, it wraps the driver around a Repository class, similar to the Store and Guard classes.

Creating Our Own Cache Handler

Create the MongoStore, which should extend the Illuminate\Cache\StoreInterface:

1
<?php namespace Illuminate\Cache;
2
3
    use Mongo;
4
5
    class MongoStore implements StoreInterface
6
    {
7
        /**

8
         * The mongo instance

9
         *

10
         * @param  \Mongo

11
         */
12
        protected $connection;
13
14
        /**

15
         * The mongo connection instance

16
         *

17
         * @param  \MongoConnection

18
         */
19
        protected $collection;
20
21
        /**

22
         * The Mongo config array

23
         *

24
         * @var array

25
         */
26
        protected $config;
27
28
        /**

29
         * Create a new Mongo cache store.

30
         *

31
         * @param  array $config

32
         *     - $config['host']       Mongodb host

33
         *     - $config['username']   Mongodb username

34
         *     - $config['password']   Mongodb password

35
         *     - $config['database']   Mongodb database

36
         *     - $config['collection'] Mongodb collection

37
         * @return void

38
         */
39
        public function __construct(array $config)
40
        {
41
            $this->config = $config;
42
43
            $connection_string = 'mongodb://';
44
45
            if (!empty($this->config['username']) && !empty($this->config['password'])) {
46
                $connection_string .= "{$this->config['user']}:{$this->config['password']}@";
47
            }
48
49
            $connection_string .= "{$this->config['host']}";
50
51
            $this->connection = new Mongo($connection_string);
52
53
            $this->collection = $this->connection->selectCollection($this->config['database'], $this->config['collection']);
54
        }
55
56
        /**

57
         * Retrieve an item from the cache by key.

58
         *

59
         * @param  string  $key

60
         * @return mixed

61
         */
62
        public function get($key)
63
        {
64
            $cache_data = $this->getObject($key);
65
66
            if (!$cache_data) {
67
                return null;
68
            }
69
70
            return unserialize($cache_data['cache_data']);
71
        }
72
73
        /**

74
         * Return the whole object instead of just the cache_data

75
         * 

76
         * @param  string  $key

77
         * @return array|null

78
         */
79
        protected function getObject($key)
80
        {
81
            $cache_data = $this->collection->findOne(array(
82
                'key' => $key,
83
            ));
84
85
            if (is_null($cache_data)) {
86
                return null;
87
            }
88
89
            if (isset($cache_data['expire']) && time() >= $cache_data['expire']) {
90
                $this->forget($key);
91
                return null;
92
            }
93
94
            return $cache_data;
95
        }
96
97
        /**

98
         * Store an item in the cache for a given number of minutes.

99
         *

100
         * @param  string  $key

101
         * @param  mixed   $value

102
         * @param  int     $minutes

103
         * @return void

104
         */
105
        public function put($key, $value, $minutes)
106
        {
107
            $expiry = $this->expiration($minutes);
108
109
            $this->collection->update(
110
                array(
111
                    'key' => $key
112
                ),
113
                array(
114
                    '$set' => array(
115
                        'cache_data' => serialize($value),
116
                        'expiry' => $expiry,
117
                        'ttl' => ($minutes * 60)
118
                    )
119
                ),
120
                array(
121
                    'upsert' => true,
122
                    'multiple' => false
123
                )
124
            );
125
        }
126
127
        /**

128
         * Increment the value of an item in the cache.

129
         *

130
         * @param  string  $key

131
         * @param  mixed   $value

132
         * @return void

133
         *

134
         * @throws \LogicException

135
         */
136
        public function increment($key, $value = 1)
137
        {
138
            $cache_data = $this->getObject($key);
139
140
            if (!$cache_data) {
141
                $new_data = array(
142
                    'cache_data' => serialize($value),
143
                    'expiry' => $this->expiration(0),
144
                    'ttl' => $this->expiration(0)
145
                );
146
            } else {
147
                $new_data = array(
148
                    'cache_data' => serialize(unserialize($cache_data['cache_data']) + $value),
149
                    'expiry' => $this->expiration((int) ($cache_data['ttl']/60)),
150
                    'ttl' => $cache_data['ttl']
151
                );
152
            }
153
154
            $this->collection->update(
155
                array(
156
                    'key' => $key
157
                ),
158
                array(
159
                    '$set' => $new_data
160
                ),
161
                array(
162
                    'upsert' => true,
163
                    'multiple' => false
164
                )
165
            );
166
        }
167
168
        /**

169
         * Decrement the value of an item in the cache.

170
         *

171
         * @param  string  $key

172
         * @param  mixed   $value

173
         * @return void

174
         *

175
         * @throws \LogicException

176
         */
177
        public function decrement($key, $value = 1)
178
        {
179
            $cache_data = $this->getObject($key);
180
181
            if (!$cache_data) {
182
                $new_data = array(
183
                    'cache_data' => serialize((0 - $value)),
184
                    'expiry' => $this->expiration(0),
185
                    'ttl' => $this->expiration(0)
186
                );
187
            } else {
188
                $new_data = array(
189
                    'cache_data' => serialize(unserialize($cache_data['cache_data']) - $value),
190
                    'expiry' => $this->expiration((int) ($cache_data['ttl']/60)),
191
                    'ttl' => $cache_data['ttl']
192
                );
193
            }
194
195
            $this->collection->update(
196
                array(
197
                    'key' => $key
198
                ),
199
                array(
200
                    '$set' => $new_data
201
                ),
202
                array(
203
                    'upsert' => true,
204
                    'multiple' => false
205
                )
206
            );
207
        }
208
209
        /**

210
         * Store an item in the cache indefinitely.

211
         *

212
         * @param  string  $key

213
         * @param  mixed   $value

214
         * @return void

215
         */
216
        public function forever($key, $value)
217
        {
218
            return $this->put($key, $value, 0);
219
        }
220
221
        /**

222
         * Remove an item from the cache.

223
         *

224
         * @param  string  $key

225
         * @return void

226
         */
227
        public function forget($key)
228
        {
229
            $this->collection->remove(array(
230
                'key' => $key
231
            ));
232
        }
233
234
        /**

235
         * Remove all items from the cache.

236
         *

237
         * @return void

238
         */
239
        public function flush()
240
        {
241
            $this->collection->remove();
242
        }
243
244
        /**

245
         * Get the expiration time based on the given minutes.

246
         *

247
         * @param  int  $minutes

248
         * @return int

249
         */
250
        protected function expiration($minutes)
251
        {
252
            if ($minutes === 0) return 9999999999;
253
254
            return time() + ($minutes * 60);
255
        }
256
257
        /**

258
         * Get the cache key prefix.

259
         *

260
         * @return string

261
         */
262
        public function getPrefix()
263
        {
264
            return '';
265
        }
266
    }

We'll also need to add the Mongo callback again to the manager:

1
/**

2
     * Register the service provider.

3
	 *

4
	 * @return void

5
	 */
6
	public function register()
7
	{
8
		$this->app->bindShared('cache', function($app)
9
		{
10
			$cache_manager = new CacheManager($app);
11
12
			$cache_manager->extend('mongo', function($app) {
13
				return new MongoStore(
14
					array(
15
						'host'       => $app['config']->get('cache.mongo.host'),
16
				        'username'   => $app['config']->get('cache.mongo.username'),
17
				        'password'   => $app['config']->get('cache.mongo.password'),
18
				        'database'   => $app['config']->get('cache.mongo.database'),
19
				        'collection' => $app['config']->get('cache.mongo.collection')
20
					)
21
				);
22
			});
23
24
			return $cache_manager;
25
		});
26
27
		$this->app->bindShared('cache.store', function($app)
28
		{
29
			return $app['cache']->driver();
30
		});
31
32
		$this->app->bindShared('memcached.connector', function()
33
		{
34
			return new MemcachedConnector;
35
		});
36
37
		$this->registerCommands();
38
	}

Lastly, we'll need to update the cache.php config file:

1
'driver' => 'mongo',
2
    ...
3
    ...
4
    ...
5
    /**

6
	 * Mongo DB settings

7
	 */
8
	'mongo' => array(
9
		'host' => '127.0.0.1',
10
		'username' => '',
11
		'password' => '',
12
		'database' => 'laravel',
13
		'collection' => 'laravel_cache_collection'
14
	)

Now, attempt to use the Cache::put() and Cache::get() methods. If done correctly, we should be able to use MongoDB to cache the data!

Conclusion

In this tutorial, we learned about the following:

  • Laravel's component-based system called Illuminate, which is used by the Laravel framework.
  • Laravel Service Providers and a little bit about how they work.
  • Laravel's Manager system, which acts as both a wrapper and factory for the drivers.
  • Session, Auth and Cache components and how to create new drivers for each.
  • Store, Guard and Repository libraries which utilize these drivers.

Hopefully this helps programmers create their own drivers and extend the current functionality of the Laravel framework.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.