├── .gitignore
├── composer.json
├── src
├── Handlers
│ ├── BaseHandler.php
│ └── EnvironmentIndexPrefixHandler.php
├── ServiceProvider.php
├── Manager.php
└── Client.php
├── LICENSE
├── config
└── elasticsearch-handlers.php
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | composer.lock
3 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cviebrock/laravel-elasticsearch-handlers",
3 | "description": "Further easiness when using Elasticsearch with Laravel",
4 | "license": "MIT",
5 | "authors": [
6 | {
7 | "name": "Colin Viebrock",
8 | "email": "colin@viebrock.ca"
9 | }
10 | ],
11 | "require": {
12 | "php": ">=5.4.0",
13 | "illuminate/support": "~4|~5",
14 | "cviebrock/laravel-elasticsearch": "~0.9"
15 | },
16 | "autoload": {
17 | "psr-4": {
18 | "Cviebrock\\LaravelElasticsearchHandlers\\": "src/"
19 | }
20 | },
21 | "minimum-stability": "beta",
22 | "prefer-stable": true
23 | }
24 |
--------------------------------------------------------------------------------
/src/Handlers/BaseHandler.php:
--------------------------------------------------------------------------------
1 | config = $config;
22 | }
23 |
24 | /**
25 | * Use the underlying client to make sure all the index templates are in place.
26 | *
27 | * @param Client $client
28 | */
29 | public function boot(Client $client) { }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/Handlers/EnvironmentIndexPrefixHandler.php:
--------------------------------------------------------------------------------
1 | app;
28 |
29 | if (version_compare($app::VERSION, '5.0') >= 0) {
30 | // Laravel 5
31 | $configPath = realpath(__DIR__ . '/../config/elasticsearch-handlers.php');
32 | $this->publishes([
33 | $configPath => config_path('elasticsearch-handlers.php')
34 | ]);
35 | }
36 | }
37 |
38 | /**
39 | * Register the service provider. This will rebind the base Elasticsearch Manager
40 | * with this package's version, that wraps the ES client ... allowing us to
41 | * modify the base functionality before sending data to ES or after reading it.
42 | *
43 | * @return void
44 | */
45 | public function register() {
46 |
47 | $this->app->bindShared('elasticsearch', function ($app) {
48 | return new Manager($app, $app['elasticsearch.factory']);
49 | });
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Manager.php:
--------------------------------------------------------------------------------
1 | getHandlerClass();
26 |
27 | // Load the handlers for this configuration.
28 | $handlers = $this->getConnectionHandlers($name);
29 |
30 | // Create a "wrapped" client passing in the appropriate configuration
31 | return new $handlerClass($baseClient, $handlers);
32 | }
33 |
34 | /**
35 | * Get the default handler class.
36 | *
37 | * @return string
38 | */
39 | public function getHandlerClass() {
40 | return $this->app['config']['elasticsearch-handlers.defaultClass'];
41 | }
42 |
43 | /**
44 | * Get the handlers for the given connection name.
45 | *
46 | * @param string $name
47 | * @return array
48 | */
49 | protected function getConnectionHandlers($name) {
50 |
51 | $connections = $this->app['config']['elasticsearch-handlers.connections'];
52 |
53 | return array_get($connections, $name, []);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/config/elasticsearch-handlers.php:
--------------------------------------------------------------------------------
1 | 'Cviebrock\LaravelElasticsearch\Handlers\Client',
13 |
14 | /**
15 | * This array should match the array defined in `app\elasticsearch.php`.
16 | * The key represents the connection name, and the value is an array of
17 | * handlers to apply to that connection's client. The elements of the array
18 | * can either classnames, or classname=>configurationArray pairs (for those
19 | * handlers that require configuration), i.e.:
20 | *
21 | * [
22 | * 'handlerClass1',
23 | * 'handlerClass2' => [ configurationArray ],
24 | * ...
25 | * ]
26 | */
27 |
28 | 'connections' => [
29 |
30 | /**
31 | * The following configuration applies to clients on the "default" connection:
32 | */
33 | 'default' => [
34 |
35 | /**
36 | * The "EnvironmentIndexPrefixHandler" prefixes the _index_ key with the
37 | * current Laravel environment when indexing documents.
38 | */
39 |
40 | // 'Cviebrock\LaravelElasticsearchHandlers\Handlers\EnvironmentIndexPrefixHandler',
41 |
42 | /**
43 | * The "IndexTemplateHandler" makes sure that the configured Elasticsearch
44 | * index templates are in place when the client is instantiated.
45 | */
46 |
47 | // 'Cviebrock\LaravelElasticsearchHandlers\Handlers\IndexTemplateHandler' => [
48 | //
49 | // ]
50 |
51 | ]
52 |
53 | ]
54 |
55 | ];
56 |
--------------------------------------------------------------------------------
/src/Client.php:
--------------------------------------------------------------------------------
1 | client = $client;
44 | $this->registerHandlers($handlers);
45 | }
46 |
47 | /**
48 | * Register the handlers for the client.
49 | *
50 | * @param array $handlers
51 | */
52 | public function registerHandlers(array $handlers = []) {
53 |
54 | foreach ($handlers as $handlerClass => $configuration) {
55 |
56 | // If the handler takes a configuration, load that from the array and
57 | // build the class. If not, then just build the class.
58 |
59 | if (is_numeric($handlerClass)) {
60 | $handlerClass = $configuration;
61 | $class = new $handlerClass;
62 | } else {
63 | $class = new $handlerClass($configuration);
64 | }
65 |
66 | // Use reflection to figure out what Elasticsearch methods the handler handles.
67 |
68 | $reflect = new ReflectionClass($class);
69 |
70 | // Find the handled methods and merge them into the client's list.
71 |
72 | $classMethods = $reflect->getMethods(ReflectionMethod::IS_PUBLIC);
73 |
74 | array_walk($classMethods, function ($classMethod) use ($handlerClass) {
75 | if (starts_with($classMethod->name, 'handle')) {
76 | $method = lcfirst(substr($classMethod->name, 6));
77 |
78 | $this->handledMethods[$method][] = $handlerClass;
79 | }
80 | });
81 |
82 | // Save the handler instance.
83 |
84 | $this->handlers[$handlerClass] = $class;
85 | }
86 |
87 | // Boot all the handlers with the client instance.
88 |
89 | foreach ($this->handlers as $handler) {
90 | $handler->boot($this);
91 | }
92 | }
93 |
94 | /**
95 | * Get the list of all handlers that should be run for the given method.
96 | *
97 | * @param $methodName
98 | * @return array
99 | */
100 | protected function getHandlers($methodName) {
101 | return array_get($this->handledMethods, $methodName, []);
102 | }
103 |
104 | /**
105 | * Magic method to pass commands through handlers before sending them to the base client.
106 | *
107 | * @param $method
108 | * @param $parameters
109 | * @return mixed
110 | */
111 | public function __call($method, $parameters) {
112 |
113 | $parameterCount = count($parameters);
114 |
115 | // First, find out which handlers are registered for this method.
116 |
117 | $handlers = $this->getHandlers($method);
118 |
119 | // And get the real class method name we will call.
120 |
121 | $classMethod = 'handle' . ucfirst($method);
122 |
123 | // Then run the parameters through any registered handlers.
124 |
125 | foreach ($handlers as $handler) {
126 | $parameters = call_user_func_array([$this->handlers[$handler], $classMethod], $parameters);
127 | if ($parameterCount == 1) {
128 | $parameters = [$parameters];
129 | }
130 | }
131 |
132 | // Finally, run the parameters through the base client.
133 | return call_user_func_array([$this->client, $method], $parameters);
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Laravel-Elasticsearch-Handlers
2 |
3 | An even easier way to use the official Elastic Search client in your Laravel applications.
4 |
5 | [](https://travis-ci.org/cviebrock/laravel-elasticsearch-handlers)
6 | [](https://packagist.org/packages/cviebrock/laravel-elasticsearch-handlers)
7 | [](https://packagist.org/packages/cviebrock/laravel-elasticsearch-handlers)
8 | [](https://packagist.org/packages/cviebrock/laravel-elasticsearch-handlers)
9 |
10 | * [Installation and Configuration](#installation)
11 | * [Usage](#usage)
12 | * [Creating Handlers](#creating-handlers)
13 | * [Special `boot` Method](#special-boot-method)
14 | * [Pre-Defined Handlers](#pre-defined-handlers)
15 | * [EnvironmentIndexPrefixHandler](#environment-index-prefix-handler)
16 | * [Bugs, Suggestions and Contributions](#bugs)
17 | * [Copyright and License](#copyright)
18 |
19 |
20 |
21 |
22 | ## Installation and Configuration
23 |
24 | 1. Install the `cviebrock/laravel-elasticsearch-handlers` package via composer:
25 |
26 | ```shell
27 | $ composer require cviebrock/laravel-elasticsearch-handlers
28 | ```
29 |
30 | 2. Publish the configuration file. For Laravel 5:
31 |
32 | ```shell
33 | php artisan vendor:publish cviebrock/laravel-elasticsearch-handlers
34 | ```
35 |
36 | In order to make this package also work with Laravel 4, we can't do the
37 | standard configuration publishing like most Laravel 4 packages do. You will
38 | need to simply copy the configuration file into your application's configuration folder:
39 |
40 | ```shell
41 | cp vendor/cviebrock/laravel-elasticsearch-handlers/config/elasticsearch-handlers.php app/config/
42 | ```
43 |
44 | 3. Add the service provider (`config/app.php` for Laravel 5 or `app/config/app.php` for Laravel 4).
45 | The service provider needs to come after the `LaravelElasticsearch` provider, since we "hijack"
46 | the Manager class from that package and use our own.
47 |
48 | ```php
49 | 'providers' => array(
50 | ...
51 | 'Cviebrock\LaravelElasticSearch\ServiceProvider',
52 | 'Cviebrock\LaravelElasticSearchHandlers\ServiceProvider',
53 | )
54 | ```
55 |
56 |
57 |
58 | ## Usage
59 |
60 | This package extends the `laravel-elasticsearch` package by returning a "decorated"
61 | Elasticsearch client class, instead of the default PHP client. You can configure
62 | how the client is decorated on a per-connection basis.
63 |
64 | Take the following example `elasticsearch-handlers.php` configuration:
65 |
66 | ```php
67 | [
71 | 'default' => [
72 | 'clientClass' => 'Cviebrock\LaravelElasticsearchHandlers\Client',
73 | 'handlers' => []
74 | ]
75 | ]
76 | ];
77 | ```
78 |
79 | When you instantiate an Elasticsearch client with:
80 |
81 | ```php
82 | $client = Elasticsearch::connection('default');
83 | ```
84 |
85 | the package will create a base client (using the base `elasticsearch.php`
86 | configuration) then wrap it in the class defined by the _clientClass_ setting,
87 | and inject the _handlers_ array. So, in this case, an instance of
88 | `Cviebrock\LaravelElasticsearchHandlers\Client` is returned.
89 |
90 | This class the bare minimum client wrapper. It doesn't do anything except
91 | pass-through all commands to the wrapped base Elasticsearch class.
92 |
93 | Let's make it more useful ...
94 |
95 |
96 |
97 | ## Creating Handlers
98 |
99 | Pretend you only have one Elasticsearch instance running, but you need it to
100 | support indices for several of your Laravel application environments (e.g.
101 | "beta", "live", etc.)..
102 |
103 | Instead of updating your code so that every time you index a document you make
104 | sure the right index name is specified, what if the client automatically
105 | prefixed the index name with the name of the current Laravel environment?
106 |
107 | First, set up the package configuration like so:
108 |
109 | ```php
110 | return [
111 |
112 | 'defaultClass' => 'Cviebrock\LaravelElasticsearchHandlers\Client',
113 |
114 | 'connections' => [
115 | 'default' => [
116 | 'MyEnvironmentIndexPrefixHandler'
117 | ]
118 |
119 | ]
120 |
121 | ];
122 | ```
123 |
124 | Then create the Handler class (extending the BaseHandler class):
125 |
126 | ```php
127 | class MyEnvironmentIndexPrefixHandler extends Cviebrock\LaravelElasticsearchHandlers\Handlers\BaseHandler {
128 |
129 | /**
130 | * Auto-prefix the document index name with the current Laravel
131 | * environment.
132 | *
133 | * @param array $parameters
134 | * @return array
135 | */
136 | public function handleIndex($parameters) {
137 |
138 | if ($index = array_get($parameters, 'index')) {
139 | $environment = mb_strtolower(preg_replace('/[^a-z0-9_\-]+/', '-', \App::environment()));
140 | $parameters['index'] = trim($environment, '-') . '-_' . $index;
141 | }
142 |
143 | return $parameters;
144 | }
145 | }
146 | ```
147 |
148 | Now, every time you index a document using the default Elasticsearch connection,
149 | the current Laravel environment name will be prefixed to the _index_ key of your
150 | data array.
151 |
152 | ```php
153 | $data = [
154 | 'index' => 'my-index',
155 | 'type' => 'my-doctype',
156 | 'body' => [
157 | 'content' => 'Lorem ipsum',
158 | ]
159 | ];
160 | $return = Elasticsearch::index($data);
161 | ```
162 |
163 | This returns:
164 |
165 | ```
166 | array (size=5)
167 | '_index' => string 'local-my-index' (length=14)
168 | '_type' => string 'my-doctype' (length=10)
169 | '_id' => string 'AU3U9R3kOpwouG512345' (length=20)
170 | '_version' => int 1
171 | 'created' => boolean true
172 | ```
173 |
174 | The _index_ was prepended automatically, so your application will work across
175 | all environments without checks or changes.
176 |
177 | Also, you can register more than one handler per connection, which means that
178 | the functionality is "chainable". E.g., prepend the environment to the _index_,
179 | and also add some default parameters to the _body_, etc..
180 |
181 |
182 |
183 |
184 |
185 | ### Special `boot` Method
186 |
187 | Handlers can also define a `boot` method with the following signature:
188 |
189 | ```php
190 | public function boot(\Cviebrock\LaravelElasticsearchHandlers\Client $client) {}
191 | ```
192 |
193 | This is method is run when the handler is registered so it could be used, for
194 | example, to alter the behaviour of the client upon instantiation. The client
195 | is passed in as the only parameter.
196 |
197 |
198 |
199 | ## Pre-Defined Handlers
200 |
201 | The package ships with a few pre-defined handlers, all of which are in the
202 | `Cviebrock\LaravelElasticsearchHandlers\Handlers` namespace.
203 |
204 |
205 | ### EnvironmentIndexPrefixHandler
206 |
207 | Operates on the follow methods:
208 |
209 | * index
210 |
211 | This is basically the same handler as used in the example above. It will take
212 | the current Laravel environment, mangles it a bit so it matches Elasticsearch's
213 | constraints for index names, and prepends it to the _index_ key in the given
214 | document.
215 |
216 |
217 |
218 |
219 |
220 | ## Bugs, Suggestions and Contributions
221 |
222 | Please use Github for bugs, comments, suggestions.
223 |
224 | 1. Fork the project.
225 | 2. Create your bugfix/feature branch and write your (well-commented) code.
226 | 3. Commit your changes (and your tests) and push to your branch.
227 | 4. Create a new pull request against the `master` branch.
228 |
229 |
230 |
231 | ## Copyright and License
232 |
233 | Laravel-Elasticsearch-Handlers was written by Colin Viebrock and released under the MIT License. See the LICENSE file for details.
234 |
235 | Copyright 2015 Colin Viebrock
236 |
--------------------------------------------------------------------------------