Showing preview only (269K chars total). Download the full file or copy to clipboard to get everything.
Repository: iverberk/larasearch
Branch: develop
Commit: d648243433b1
Files: 50
Total size: 253.2 KB
Directory structure:
gitextract_74xw7pf5/
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── composer.json
├── phpunit.xml
├── src/
│ ├── Iverberk/
│ │ └── Larasearch/
│ │ ├── Commands/
│ │ │ ├── PathsCommand.php
│ │ │ └── ReindexCommand.php
│ │ ├── Exceptions/
│ │ │ └── ImportException.php
│ │ ├── Index.php
│ │ ├── Jobs/
│ │ │ ├── DeleteJob.php
│ │ │ └── ReindexJob.php
│ │ ├── LarasearchServiceProvider.php
│ │ ├── Observer.php
│ │ ├── Proxy.php
│ │ ├── Query.php
│ │ ├── Response/
│ │ │ ├── Records.php
│ │ │ ├── Result.php
│ │ │ └── Results.php
│ │ ├── Response.php
│ │ ├── Traits/
│ │ │ ├── CallableTrait.php
│ │ │ ├── SearchableTrait.php
│ │ │ └── TransformableTrait.php
│ │ └── Utils.php
│ └── config/
│ └── larasearch.php
└── tests/
├── Iverberk/
│ └── Larasearch/
│ ├── Commands/
│ │ ├── PathsCommandTest.php
│ │ └── ReindexCommandTest.php
│ ├── IndexTest.php
│ ├── Jobs/
│ │ ├── DeleteJobTest.php
│ │ └── ReindexJobTest.php
│ ├── LarasearchServiceProviderTest.php
│ ├── ObserverTest.php
│ ├── ProxyTest.php
│ ├── QueryTest.php
│ ├── Response/
│ │ ├── RecordsTest.php
│ │ ├── ResultTest.php
│ │ └── ResultsTest.php
│ ├── ResponseTest.php
│ ├── Traits/
│ │ ├── CallableTraitTest.php
│ │ ├── SearchableTraitTest.php
│ │ └── TransformableTraitTest.php
│ └── UtilsTest.php
├── Support/
│ ├── Dummy.php
│ └── Stubs/
│ ├── Child.php
│ ├── Foo/
│ │ └── Bar.php
│ ├── Husband.php
│ ├── NamespaceDummy.php
│ ├── Toy.php
│ └── Wife.php
└── bootstrap.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/vendor
composer.phar
composer.lock
.DS_Store
tests/coverage/*
.idea/
atlassian-ide-plugin.xml
================================================
FILE: .travis.yml
================================================
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
before_script:
- composer self-update
- composer install --prefer-source --no-interaction --dev
script: phpunit
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Ivo Verberk
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
Introduction
------------
Larasearch is a Laravel package that aims to seamlessly integrate Elasticsearch functionality with the Eloquent ORM.
Features
--------
- Plug 'n Play searching functionality for Eloquent models
- Automatic creation/indexing based on Eloquent model properties and relations
- Aggregations, Suggestions, Autocomplete, Highlighting, etc. It's all there!
- Load Eloquent models based on Elasticsearch queries
- Automatic reindexing on updates of (related) Eloquent models
Installation
------------
*Laravel 5*
NB: This is preliminary support. When L5 compatibility is stable I will tag it with a version.
Add Larasearch to your composer.json file:
```"iverberk/larasearch": "dev-L5"```
Add the service provider to your Laravel application config:
```PHP
'Iverberk\Larasearch\LarasearchServiceProvider'
```
*Laravel 4*
Add Larasearch to your composer.json file:
```"iverberk/larasearch": "0.8.0"```
Add the service provider to your Laravel application config:
```PHP
'Iverberk\Larasearch\LarasearchServiceProvider'
```
Wiki
----
Please see the Github [wiki](https://github.com/iverberk/larasearch/wiki/Introduction) for the most up-to-date documentation.
Changelog
---------
All releases are tracked and documented in the [changelog](https://github.com/iverberk/larasearch/wiki/Changelog).
Credits
-------
This package is very much inspired by these excellent packages that already exist for the Ruby/Rails ecosystem.
* [Searchkick](https://github.com/ankane/searchkick)
* [Elasticsearch Rails](https://github.com/elasticsearch/elasticsearch-rails)
A lot of their ideas have been reused to work within a PHP/Laravel environment.
================================================
FILE: composer.json
================================================
{
"name": "iverberk/larasearch",
"description": "Elasticsearch enabled Eloquent models",
"keywords": ["search", "elasticsearch", "eloquent"],
"license": "MIT",
"authors": [
{
"name": "Ivo Verberk"
}
],
"require": {
"php": ">=5.4.0",
"illuminate/support": "~5.0",
"illuminate/database": "~5.0",
"illuminate/console": "~5.0",
"illuminate/config": "~5.0",
"doctrine/dbal": "2.5.1",
"elasticsearch/elasticsearch": "~1.0",
"nikic/php-parser": "*"
},
"autoload": {
"psr-0": {
"Iverberk\\Larasearch": "src/"
},
"classmap": [
"tests/Support/Stubs",
"tests/Support"
]
},
"require-dev": {
"mockery/mockery": "dev-master",
"phpunit/phpunit": "4.4.*",
"codeception/aspect-mock": "*"
}
}
================================================
FILE: phpunit.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="tests/bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<testsuites>
<testsuite name="Package Test Suite">
<directory suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src/Iverberk/Larasearch</directory>
</whitelist>
</filter>
</phpunit>
================================================
FILE: src/Iverberk/Larasearch/Commands/PathsCommand.php
================================================
<?php namespace Iverberk\Larasearch\Commands;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Facades\File;
use Iverberk\Larasearch\Utils;
use Symfony\Component\Console\Input\InputOption;
class PathsCommand extends Command {
/**
* The console command name.
*
* @var string
*/
protected $name = 'larasearch:paths';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate paths from Eloquent models';
/**
* @var array
*/
private $relationClassMethods = [];
/**
* @var array
*/
private $relatedModels = [];
/**
* @var array
*/
private $paths = [];
/**
* @var array
*/
private $reversedPaths = [];
/**
* Scan directories for Eloquent models that use the SearchableTrait.
* Generate paths for all these models so that we can (re)index these
* models.
*
* @return void
*/
public function fire()
{
$models = $this->argument('model');
foreach ($models as $model)
{
$this->compilePaths(new $model);
}
if ($directories = $this->option('dir'))
{
$directoryModels = array_diff(Utils::findSearchableModels($directories), $models);
foreach ($directoryModels as $model)
{
// Find paths for related models
$this->compilePaths(new $model);
}
}
if (!empty($models) || !empty($directoryModels))
{
$this->writeConfig();
} else
{
$this->info('No models found.');
}
}
/**
* @return array
*/
public function getPaths()
{
return $this->paths;
}
/**
* @return array
*/
public function getReversedPaths()
{
return $this->reversedPaths;
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return array(
array('model', InputOption::VALUE_OPTIONAL, 'Eloquent model to find paths for', null)
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
array('dir', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Directory to scan for searchable models', null, ''),
array('relations', null, InputOption::VALUE_NONE, 'Include related Eloquent models', null),
array('write-config', null, InputOption::VALUE_NONE, 'Include the compiled paths in the package configuration', null),
);
}
/**
* Inspect all relations and build a (reverse) path for every relation.
* This information is used to quickly determine which relations need to
* be eager loaded on a model when (re)indexing. It also defines the document
* structure for Elasticsearch.
*
* @param \Illuminate\Database\Eloquent\Model
* @param string $ancestor
* @param array $path
* @param array $reversedPath
* @param null $start
*/
protected function compilePaths(Model $model, $ancestor = null, $path = [], $reversedPath = [], $start = null)
{
// Initialize some variables if this is the first call
if ($ancestor == null) $ancestor = $model;
if ($start == null) $start = $model;
$modelClass = get_class($model);
// Initialize the found relations to an empty array
$relations = [];
if ($this->option('relations'))
{
// Find all related models
$relatedModels = $this->getRelatedModels($model);
foreach ($relatedModels as $related)
{
$newPath = $path;
$newPath[] = $related['method']->name;
// Check if we need to recurse for this related model
if (!$related['model'] instanceof $ancestor &&
!$related['model'] instanceof $start &&
$this->checkDocHints($related['method']->getDocComment(), $start)
)
{
// Get the relations of the related model here, so
// that we can build a reversed path for this relation
$this->getRelatedModels($related['model']);
$newReversedPath = $reversedPath;
// Check if a reciprocal relation is found back to the original model
if (!isset($this->relationClassMethods[get_class($related['model'])][$modelClass]))
{
// Check if we are possibly dealing with a polymorphic relation (reference to itself)
if (array_key_exists(get_class($related['model']), $this->relationClassMethods[get_class($related['model'])]))
{
$model = get_class($related['model']);
$newReversedPath[] = $this->relationClassMethods[$model][$model];
} else
{
throw new \RuntimeException("Reciprocal relation not found for model '" . get_class($related['model']) . "' from within '$modelClass' model");
}
} else
{
$newReversedPath[] = $this->relationClassMethods[get_class($related['model'])][$modelClass];
}
// Add this relation
$relations[] = $related;
$this->reversedPaths[$modelClass][] = implode('.', array_reverse($reversedPath));
$this->reversedPaths[$modelClass] = array_values(array_unique($this->reversedPaths[$modelClass]));
$this->compilePaths($related['model'], $model, $newPath, $newReversedPath, $start);
}
}
}
// Found no more relations for this model so build the final path
// and add the last inverse path segment
if (empty($relations))
{
if (!empty($path))
{
$this->paths[get_class($start)][] = implode('.', $path);
} else
{
$this->paths[get_class($start)] = [];
}
$this->reversedPaths[$modelClass][] = implode('.', array_reverse($reversedPath));
$this->reversedPaths[$modelClass] = array_values(array_unique($this->reversedPaths[$modelClass]));
}
}
/**
* Inspect the relation method annotations to see if we need to follow the relation
*
* @param string $docComment
* @param $model
* @return bool
*/
protected function checkDocHints($docComment, $model)
{
// Check if we never follow this relation
if (preg_match('/@follow\s+NEVER/', $docComment)) return false;
// Check if we follow the relation from the 'base' model
if (preg_match('/@follow\s+UNLESS\s+' . str_replace('\\', '\\\\', get_class($model)) . '\b/', $docComment))
{
return false;
}
if (preg_match('/@follow\s+FROM\b/', $docComment) && !preg_match('/@follow\s+FROM\s+' . str_replace('\\', '\\\\', get_class($model)) . '\b/', $docComment))
{
return false;
}
// We follow the relation
return true;
}
/**
* Find related models from a base model
*
* @param $model
* @return array
*/
protected function getRelatedModels(Model $model)
{
// Store the class name
$modelClass = get_class($model);
// Check if we already know the related models for this model
if (!isset($this->relatedModels[$modelClass]))
{
$relatedModels = [];
$methods = with(new \ReflectionClass($model))->getMethods();
// Iterate all class methods
foreach ($methods as $method)
{
// Check if this method returns an Eloquent relation
if ($method->class == $modelClass &&
preg_match('/@return\s+\\\\Illuminate\\\\Database\\\\Eloquent\\\\Relations/', $method->getDocComment())
)
{
// Get the method name, so that we can call it on the model
$relationMethod = $method->name;
// Find the relation
$relation = $model->$relationMethod();
if ($relation instanceof Relation)
{
// Find the related model
$related = $relation->getRelated();
// Store the method to help build the inverse path
$this->relationClassMethods[$modelClass][get_class($related)] = $relationMethod;
$relatedModels[] = ['model' => $related, 'method' => $method];
}
}
}
// Cache related models for this model
$this->relatedModels[$modelClass] = $relatedModels;
// Return the related models
return $relatedModels;
} else
{
// Return from cache
return $this->relatedModels[$modelClass];
}
}
/**
* Write the paths config to a file or to standard output
*
* @return void
*/
private function writeConfig()
{
if ($this->option('write-config'))
{
$configFile = base_path() . '/config/larasearch.php';
if ($this->getLaravel())
{
if ( ! File::exists($configFile))
{
if ($this->confirm('It appears that you have not yet published the larasearch config. Would you like to do this now?', false))
{
$this->call('vendor:publish', ['--provider' => 'Iverberk\\Larasearch\LarasearchServiceProvider', '--tag' => 'config']);
}
else
{
return;
}
}
}
else
{
if ( ! File::exists($configFile))
{
$this->info('Lumen application detected. Please copy the config manually to config/larasearch.php.');
}
}
File::put(dirname($configFile) . "/paths.json", json_encode(['paths' => $this->paths, 'reversedPaths' => $this->reversedPaths], JSON_PRETTY_PRINT));
$this->info('Paths file written to local package configuration');
}
else
{
$this->info(json_encode(['paths' => $this->paths, 'reversedPaths' => $this->reversedPaths], JSON_PRETTY_PRINT));
}
}
}
================================================
FILE: src/Iverberk/Larasearch/Commands/ReindexCommand.php
================================================
<?php namespace Iverberk\Larasearch\Commands;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\File;
use Iverberk\Larasearch\Utils;
use Symfony\Component\Console\Input\InputOption;
class ReindexCommand extends Command {
/**
* The console command name.
*
* @var string
*/
protected $name = 'larasearch:reindex';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Reindex Eloquent models to Elasticsearch.';
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
$directoryModels = [];
$models = $this->argument('model');
foreach ($models as $model)
{
$instance = $this->getModelInstance($model);
$this->reindexModel($instance);
}
if ($directories = $this->option('dir'))
{
$directoryModels = array_diff(Utils::findSearchableModels($directories), $models);
foreach ($directoryModels as $model)
{
$instance = $this->getModelInstance($model);
$this->reindexModel($instance);
}
}
if (empty($models) && empty($directoryModels))
{
$this->info('No models found.');
}
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return array(
array('model', InputOption::VALUE_OPTIONAL, 'Eloquent model to reindex', null)
);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return array(
array('relations', null, InputOption::VALUE_NONE, 'Reindex related Eloquent models', null),
array('mapping', null, InputOption::VALUE_REQUIRED, 'A file containing custom mappings', null),
array('dir', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Directory to scan for searchable models', null),
array('batch', null, InputOption::VALUE_OPTIONAL, 'The number of records to index in a single batch', 750),
array('force', null, InputOption::VALUE_NONE, 'Overwrite existing indices and documents', null),
);
}
/**
* Reindex a model to Elasticsearch
*
* @param Model $model
*/
protected function reindexModel(Model $model)
{
$mapping = $this->option('mapping') ? json_decode(File::get($this->option('mapping')), true) : null;
$this->info('---> Reindexing ' . get_class($model));
$model->reindex(
$this->option('relations'),
$this->option('batch'),
$mapping,
function ($batch)
{
$this->info("* Batch ${batch}");
}
);
}
/**
* Simple method to create instances of classes on the fly
* It's primarily here to enable unit-testing
*
* @param string $model
*/
protected function getModelInstance($model)
{
return new $model;
}
}
================================================
FILE: src/Iverberk/Larasearch/Exceptions/ImportException.php
================================================
<?php namespace Iverberk\Larasearch\Exceptions;
use Exception;
class ImportException extends Exception {
// Redefine the exception so message isn't optional
public function __construct($message, $code = 0, $errorItems = [])
{
// make sure everything is assigned properly
parent::__construct($message, $code);
}
}
================================================
FILE: src/Iverberk/Larasearch/Index.php
================================================
<?php namespace Iverberk\Larasearch;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Str;
use Iverberk\Larasearch\Exceptions\ImportException;
class Index {
/**
* Index name
*
* @var string
*/
private $name;
/**
* Elasticsearch client
*
* @var \Elasticsearch\Client
*/
private static $client;
/**
* Index parameters
*
* @var array
*/
private $params;
/**
* Larasearch Eloquent proxy
*
* @var Proxy
*/
private $proxy;
/**
* Retrieve the ElasticSearch Client
*
* @return \Elasticsearch\Client
*/
private static function getClient()
{
return self::$client;
}
/**
* @param Proxy $proxy
* @param string $name
*/
public function __construct(Proxy $proxy, $name = '')
{
self::$client = App::make('Elasticsearch');
$this->setProxy($proxy);
$this->setName($name ?: $proxy->getModel()->getTable());
}
/**
* Import an Eloquent
*
* @param Model $model
* @param array $relations
* @param int $batchSize
* @param callable $callback
* @internal param $type
*/
public function import(Model $model, $relations = [], $batchSize = 750, Callable $callback = null)
{
$batch = 0;
while (true)
{
// Increase the batch number
$batch += 1;
// Load records from the database
$records = $model
->with($relations)
->skip($batchSize * ($batch - 1))
->take($batchSize)
->get();
// Break out of the loop if we are out of records
if (count($records) == 0) break;
// Call the callback function to provide feedback on the import process
if ($callback)
{
$callback($batch);
}
// Transform each record before sending it to Elasticsearch
$data = [];
foreach ($records as $record)
{
$data[] = [
'index' => [
'_id' => $record->getEsId()
]
];
$data[] = $record->transform(!empty($relations));
}
// Bulk import the data to Elasticsearch
$this->bulk($data);
}
}
/**
* Set index name
*
* @param string
* @return Index
*/
public function setName($name)
{
$index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');
if ($index_prefix && !Str::startsWith($name, $index_prefix)) $name = $index_prefix . $name;
$this->name = $name;
return $this;
}
/**
* Get index name
*
* @return string
*/
public function getName()
{
return strtolower($this->name);
}
/**
* Set ElasticSearch Proxy for the index
*
* @param Proxy $proxy
* @return \Iverberk\Larasearch\Proxy
* @author Chris Nagle
*/
public function setProxy(Proxy $proxy)
{
$this->proxy = $proxy;
return $proxy;
}
/**
* Get ElasticSearch Proxy for the index
*
* @return \Iverberk\Larasearch\Proxy
*/
public function getProxy()
{
return $this->proxy;
}
/**
* Create a new index
*
* @param array $options
*/
public function create($options = [])
{
$body = empty($options) ? $this->getDefaultIndexParams() : $options;
self::getClient()->indices()->create(['index' => $this->getName(), 'body' => $body]);
}
/**
* Delete an index
*/
public function delete()
{
self::getClient()->indices()->delete(['index' => $this->getName()]);
}
/**
* Check if an index exists
*
* @return bool
*/
public function exists()
{
return self::getClient()->indices()->exists(['index' => $this->getName()]);
}
/**
* Check if an alias exists
*
* @param $alias
* @return bool
*/
public function aliasExists($alias)
{
$index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');
if ($index_prefix && !Str::startsWith($alias, $index_prefix)) $alias = $index_prefix . $alias;
return self::getClient()->indices()->existsAlias(['name' => $alias]);
}
/**
* Store a record in the index
*
* @param $record
*/
public function store($record)
{
$params['index'] = $this->getName();
$params['type'] = $record['type'];
$params['id'] = $record['id'];
$params['body'] = $record['data'];
self::getClient()->index($params);
}
/**
* Retrieve a record from the index
*
* @param $record
*/
public function retrieve($record)
{
$params['index'] = $this->getName();
$params['type'] = $record['type'];
$params['id'] = $record['id'];
self::getClient()->get($params);
}
/**
* Remove a record from the index
*
* @param $record
*/
public function remove($record)
{
$params['index'] = $this->getName();
$params['type'] = $record['type'];
$params['id'] = $record['id'];
self::getClient()->delete($params);
}
/**
* Inspect tokens returned from the analyzer
*
* @param string $text
* @param array $options
*/
public function tokens($text, $options = [])
{
self::getClient()->indices()->analyze(array_merge(['index' => $this->getName(), 'text' => $text], $options));
}
/**
* @return array
*/
public function getParams()
{
return $this->params;
}
/**
* @param $params
*/
public function setParams($params)
{
$this->params = $params;
}
/**
* @param $records
* @throws ImportException
*/
public function bulk($records)
{
$params['index'] = $this->getName();
$params['type'] = $this->getProxy()->getType();
$params['body'] = $records;
$results = self::getClient()->bulk($params);
if ($results['errors'])
{
$errorItems = [];
foreach ($results['items'] as $item)
{
if (array_key_exists('error', $item['index']))
{
$errorItems[] = $item;
}
}
throw new ImportException('Bulk import with errors', 1, $errorItems);
}
}
/**
* Clean old indices that start with $name
*
* @param $name
*/
public static function clean($name)
{
$index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');
if ($index_prefix && !Str::startsWith($name, $index_prefix)) $name = $index_prefix . $name;
$indices = self::getClient()->indices()->getAliases();
foreach ($indices as $index => $value)
{
if (empty($value['aliases']) && preg_match("/^${name}_\\d{14,17}$/", $index))
{
self::getClient()->indices()->delete(['index' => $index]);
}
}
}
/**
* Retrieve aliases
*
* @param $name
* @return array
*/
public static function getAlias($name)
{
$index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');
if ($index_prefix && !Str::startsWith($name, $index_prefix)) $name = $index_prefix . $name;
return self::getClient()->indices()->getAlias(['name' => $name]);
}
/**
* @param array $actions
* @return array
*/
public static function updateAliases(array $actions)
{
if (isset($actions['actions']) && ($index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '')))
{
foreach ($actions['actions'] as &$action)
{
list($verb, $data) = each($action);
if (!Str::startsWith($data['index'], $index_prefix)) $action[$verb]['index'] = $index_prefix . $data['index'];
if (!Str::startsWith($data['alias'], $index_prefix)) $action[$verb]['alias'] = $index_prefix . $data['alias'];
}
}
return self::getClient()->indices()->updateAliases(['body' => $actions]);
}
/**
* Refresh an index
*
* @param $index
* @return array
*/
public static function refresh($index)
{
$index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');
if ($index_prefix && !Str::startsWith($index, $index_prefix)) $index = $index_prefix . $index;
return self::getClient()->indices()->refresh(['index' => $index]);
}
/**
* Initialize the default index settings and mappings
*
* @return array
*/
private function getDefaultIndexParams()
{
$analyzers = Config::get('larasearch.elasticsearch.analyzers');
$params = Config::get('larasearch.elasticsearch.defaults.index');
$mapping = [];
$mapping_options = array_combine(
$analyzers,
array_map(function ($type)
{
$config = $this->getProxy()->getConfig();
// Maintain backwards compatibility by allowing a plain array of analyzer => fields
$field_mappings = Utils::findKey($config, $type, false) ?: [];
// Also read from a dedicated array key called 'analyzers'
if (isset($config['analyzers']))
{
$field_mappings = array_merge($field_mappings, Utils::findKey($config['analyzers'], $type, false) ?: []);
}
return $field_mappings;
},
$analyzers
)
);
foreach (array_unique(array_flatten(array_values($mapping_options))) as $field)
{
// Extract path segments from dot separated field
$pathSegments = explode('.', $field);
// Last element is the field name
$fieldName = array_pop($pathSegments);
// Apply default field mapping
$fieldMapping = [
'type' => "multi_field",
'fields' => [
$fieldName => [
'type' => 'string',
'index' => 'not_analyzed'
],
'analyzed' => [
'type' => 'string',
'index' => 'analyzed'
]
]
];
// Check if we need to add additional mappings
foreach ($mapping_options as $type => $fields)
{
if (in_array($field, $fields))
{
$fieldMapping['fields'][$type] = [
'type' => 'string',
'index' => 'analyzed',
'analyzer' => "larasearch_${type}_index"
];
}
}
if (!empty($pathSegments))
{
$mapping = Utils::array_merge_recursive_distinct(
$mapping,
$this->getNestedFieldMapping($fieldName, $fieldMapping, $pathSegments)
);
} else
{
$mapping[$fieldName] = $fieldMapping;
}
}
if (!empty($mapping)) $params['mappings']['_default_']['properties'] = $mapping;
$params['index'] = $this->getName();
$params['type'] = $this->getProxy()->getType();
return $params;
}
/**
* @param $fieldName
* @param $fieldMapping
* @param $pathSegments
* @return array
*/
private function getNestedFieldMapping($fieldName, $fieldMapping, $pathSegments)
{
$nested = [];
$current = array_pop($pathSegments);
// Create the first level
$nested[$current] = [
'type' => 'object',
'properties' => [
$fieldName => $fieldMapping
]
];
// Add any additional levels
foreach (array_reverse($pathSegments) as $pathSegment)
{
$nested[$pathSegment] = [
'type' => 'object',
'properties' => $nested
];
unset($nested[$current]);
$current = $pathSegment;
}
return $nested;
}
}
================================================
FILE: src/Iverberk/Larasearch/Jobs/DeleteJob.php
================================================
<?php namespace Iverberk\Larasearch\Jobs;
use Iverberk\Larasearch\Config;
use Illuminate\Foundation\Application;
use Illuminate\Queue\Jobs\Job;
/**
* Class DeleteJob
*
* @package Iverberk\Larasearch\Jobs
*/
class DeleteJob {
/**
* @var Application
*/
private $app;
/**
* @var Config
*/
private $config;
/**
* @param Application $app
* @param Config
*/
public function __construct(Application $app, Config $config)
{
$this->app = $app;
$this->config = $config;
}
/**
* @param Job $job
* @param mixed $models
*/
public function fire(Job $job, $models)
{
$loggerContainerBinding = $this->config->get('logger', 'iverberk.larasearch.logger');
$logger = $this->app->make($loggerContainerBinding);
foreach ($models as $model)
{
list($class, $id) = explode(':', $model);
$logger->info('Deleting ' . $class . ' with ID: ' . $id . ' from Elasticsearch');
$model = new $class;
$model->deleteDoc($id);
}
$job->delete();
}
}
================================================
FILE: src/Iverberk/Larasearch/Jobs/ReindexJob.php
================================================
<?php namespace Iverberk\Larasearch\Jobs;
use Illuminate\Config\Repository;
use Illuminate\Foundation\Application;
use Illuminate\Queue\Jobs\Job;
use Exception;
/**
* Class ReindexJob
*
* @package Iverberk\Larasearch\Jobs
*/
class ReindexJob {
/**
* @var Application
*/
private $app;
/**
* @var Config
*/
private $config;
/**
* @param Application $app
* @param Repository $config
*/
public function __construct(Application $app, Repository $config)
{
$this->app = $app;
$this->config = $config;
}
public function fire(Job $job, $models)
{
$loggerContainerBinding = $this->config->get('larasearch.logger');
$logger = $this->app->make($loggerContainerBinding);
foreach ($models as $model)
{
list($class, $id) = explode(':', $model);
$logger->info('Indexing ' . $class . ' with ID: ' . $id);
try
{
$model = $class::findOrFail($id);
$model->refreshDoc($model);
} catch (Exception $e)
{
$logger->error('Indexing ' . $class . ' with ID: ' . $id . ' failed: ' . $e->getMessage());
$job->release(60);
}
}
$job->delete();
}
}
================================================
FILE: src/Iverberk/Larasearch/LarasearchServiceProvider.php
================================================
<?php namespace Iverberk\Larasearch;
use Elasticsearch\Client;
use Illuminate\Support\ServiceProvider;
use Iverberk\Larasearch\Commands\PathsCommand;
use Iverberk\Larasearch\Commands\ReindexCommand;
use Iverberk\Larasearch\Response\Result;
use Monolog\Handler\NullHandler;
use Monolog\Logger;
class LarasearchServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
public function boot()
{
$this->bootContainerBindings();
$this->publishes([
__DIR__ . '/../../config/larasearch.php' => base_path('config/larasearch.php'),
], 'config');
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerCommands();
if (file_exists(base_path('config/larasearch.php')))
{
$this->mergeConfigFrom(base_path('config/larasearch.php'), 'larasearch');
}
else
{
$this->mergeConfigFrom(__DIR__ . '/../../config/larasearch.php', 'larasearch');
}
}
/**
* Boot the container bindings.
*
* @return void
*/
public function bootContainerBindings()
{
$this->bindElasticsearch();
$this->bindLogger();
$this->bindIndex();
$this->bindQuery();
$this->bindProxy();
$this->bindResult();
}
/**
* Bind a Larasearch log handler to the container
*/
protected function bindLogger()
{
$this->app->singleton('iverberk.larasearch.logger', function ($app)
{
return new Logger('larasearch', [new NullHandler()]);
});
}
/**
* Bind the Elasticsearch client to the container
*/
protected function bindElasticsearch()
{
$this->app->singleton('Elasticsearch', function ($app)
{
return new Client(\Illuminate\Support\Facades\Config::get('larasearch.elasticsearch.params'));
});
}
/**
* Bind the Larasearch index to the container
*/
protected function bindIndex()
{
$this->app->bind('iverberk.larasearch.index', function ($app, $params)
{
$name = isset($params['name']) ? $params['name'] : '';
return new Index($params['proxy'], $name);
});
}
/**
* Bind the Larasearch Query to the container
*/
protected function bindQuery()
{
$this->app->bind('iverberk.larasearch.query', function ($app, $params)
{
return new Query($params['proxy'], $params['term'], $params['options']);
});
}
/**
* Bind the Larasearch proxy to the container
*/
protected function bindProxy()
{
$this->app->bind('iverberk.larasearch.proxy', function ($app, $model)
{
return new Proxy($model);
});
}
/**
* Bind the Larasearch result to the container
*/
protected function bindResult()
{
$this->app->bind('iverberk.larasearch.response.result', function ($app, array $hit)
{
return new Result($hit);
});
}
/**
* Register the commands.
*
* @return void
*/
protected function registerCommands()
{
$this->app['iverberk.larasearch.commands.reindex'] = $this->app->share(function ($app)
{
return new ReindexCommand();
});
$this->app['iverberk.larasearch.commands.paths'] = $this->app->share(function ($app)
{
return new PathsCommand();
});
$this->commands('iverberk.larasearch.commands.reindex');
$this->commands('iverberk.larasearch.commands.paths');
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array();
}
}
================================================
FILE: src/Iverberk/Larasearch/Observer.php
================================================
<?php namespace Iverberk\Larasearch;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Queue;
class Observer {
/**
* Model delete event handler
*
* @param Model $model
*/
public function deleted(Model $model)
{
// Delete corresponding $model document from Elasticsearch
Queue::push('Iverberk\Larasearch\Jobs\DeleteJob', [get_class($model) . ':' . $model->getKey()]);
// Update all related model documents to reflect that $model has been removed
Queue::push('Iverberk\Larasearch\Jobs\ReindexJob', $this->findAffectedModels($model, true));
}
/**
* Model save event handler
*
* @param Model $model
*/
public function saved(Model $model)
{
if ($model::$__es_enable && $model->shouldIndex())
{
Queue::push('Iverberk\Larasearch\Jobs\ReindexJob', $this->findAffectedModels($model));
}
}
/**
* Find all searchable models that are affected by the model change
*
* @param Model $model
* @return array
*/
private function findAffectedModels(Model $model, $excludeCurrent = false)
{
// Temporary array to store affected models
$affectedModels = [];
$paths = Config::get('larasearch.reversedPaths.' . get_class($model), []);
foreach ((array)$paths as $path)
{
if (!empty($path))
{
$model = $model->load($path);
// Explode the path into an array
$path = explode('.', $path);
// Define a little recursive function to walk the relations of the model based on the path
// Eventually it will queue all affected searchable models for reindexing
$walk = function ($relation, array $path) use (&$walk, &$affectedModels)
{
$segment = array_shift($path);
$relation = $relation instanceof Collection ? $relation : new Collection([$relation]);
foreach ($relation as $record)
{
if ($record instanceof Model)
{
if (!empty($segment))
{
if (array_key_exists($segment, $record->getRelations()))
{
$walk($record->getRelation($segment), $path);
} else
{
// Apparently the relation doesn't exist on this model, so skip the rest of the path as well
return;
}
} else
{
if (in_array('Iverberk\Larasearch\Traits\SearchableTrait', class_uses($record)))
{
$affectedModels[] = get_class($record) . ':' . $record->getKey();
}
}
}
}
};
$walk($model->getRelation(array_shift($path)), $path);
} else if (!$excludeCurrent)
{
if (in_array('Iverberk\Larasearch\Traits\SearchableTrait', class_uses($model)))
{
$affectedModels[] = get_class($model) . ':' . $model->getKey();
}
}
}
return array_unique($affectedModels);
}
}
================================================
FILE: src/Iverberk/Larasearch/Proxy.php
================================================
<?php namespace Iverberk\Larasearch;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
class Proxy {
/**
* @var array
*/
private $config;
/**
* Construct the Elasticsearch proxy based on an Eloquent model
*
* @param Model $model
*/
public function __construct(Model $model)
{
$class = get_class($model);
$this->config = property_exists($class, '__es_config') ? $class::$__es_config : [];
$this->config['model'] = $model;
$this->config['type'] = str_singular($model->getTable());
$this->config['client'] = App::make('Elasticsearch');
$this->config['index'] = App::make('iverberk.larasearch.index', array('proxy' => $this));
}
/**
* @return array
*/
public function getConfig()
{
return $this->config;
}
/**
* @return Model
*/
public function getModel()
{
return $this->config['model'];
}
/**
* @return Index
*/
public function getIndex()
{
return $this->config['index'];
}
/**
* @return mixed
*/
public function getType()
{
return $this->config['type'];
}
/**
* @return \Elasticsearch\Client
*/
public function getClient()
{
return $this->config['client'];
}
/**
* @param $term
* @param array $options
* @return \Iverberk\Larasearch\Response
*/
public function search($term, $options = [])
{
return App::make('iverberk.larasearch.query', ['proxy' => $this, 'term' => $term, 'options' => $options])->execute();
}
/**
* Performs a search based on a custom Elasticsearch query
*
* @param array $query
* @param array $options
* @return \Iverberk\Larasearch\Response
*/
public function searchByQuery($query, $options = [])
{
$options = array_merge(['query' => $query], $options);
return App::make('iverberk.larasearch.query', ['proxy' => $this, 'term' => null, 'options' => $options])->execute();
}
/**
* Retrieves a single document by identifier
*
* @param $id
* @return Result
*/
public function searchById($id)
{
return App::make('iverberk.larasearch.response.result', $this->config['client']->get(
[
'index' => $this->getIndex()->getName(),
'type' => $this->getType(),
'id' => $id
]
)
);
}
/**
* @param bool $relations
* @param int $batchSize
* @param array $mapping
* @param callable $callback
* @internal param bool $force
* @internal param array $params
*/
public function reindex($relations = false, $batchSize = 750, $mapping = [], Callable $callback = null)
{
$model = $this->config['model'];
$name = $this->config['index']->getName();
$newName = $name . '_' . date("YmdHis");
$relations = $relations ? Config::get('larasearch.paths.' . get_class($model)) : [];
Index::clean($name);
$index = App::make('iverberk.larasearch.index', array('name' => $newName, 'proxy' => $this));
$index->create($mapping);
if ($index->aliasExists($name))
{
$index->import($model, $relations, $batchSize, $callback);
$remove = [];
foreach (Index::getAlias($name) as $index => $aliases)
{
$remove = [
'remove' => [
'index' => $index,
'alias' => $name
]
];
}
$add = [
'add' => [
'index' => $newName,
'alias' => $name
]
];
$actions[] = array_merge($remove, $add);
Index::updateAliases(['actions' => $actions]);
Index::clean($name);
} else
{
if ($this->config['index']->exists()) $this->config['index']->delete();
$actions[] =
[
'add' => [
'index' => $newName,
'alias' => $name
]
];
Index::updateAliases([
'actions' => $actions
]);
$index->import($model, $relations, $batchSize, $callback);
}
Index::refresh($name);
}
/**
* Determine if the model requires a (re)index. Defaults to 'true' but can
* be overridden by user-defined logic.
*
* @return bool
*/
public function shouldIndex()
{
return true;
}
/**
* Reindex a specific database record to Elasticsearch
*/
public function refreshDoc($model)
{
$this->config['client']->index(
[
'id' => $model->getEsId(),
'index' => $this->getIndex()->getName(),
'type' => $this->getType(),
'body' => $model->transform(true)
]
);
}
/**
* Delete a specific database record within Elasticsearch
*
* @param $id Eloquent id of model object
*/
public function deleteDoc($id)
{
$this->config['client']->delete(
[
'id' => $id,
'index' => $this->getIndex()->getName(),
'type' => $this->getType()
]
);
}
/**
* Globally enable (re)indexing for this model
*/
public function enableIndexing()
{
$class = get_class($this->config['model']);
$class::$__es_enable = true;
}
/**
* Globally disable (re)indexing for this model
*/
public function disableIndexing()
{
$class = get_class($this->config['model']);
$class::$__es_enable = false;
}
}
================================================
FILE: src/Iverberk/Larasearch/Query.php
================================================
<?php namespace Iverberk\Larasearch;
use stdClass;
class Query {
/**
* @var Proxy
*/
private $proxy;
/**
* @var string
*/
private $term;
/**
* @var array
*/
private $options;
/**
* @var array
*/
private $fields;
/**
* @var array
*/
private $payload;
/**
* @var array
*/
private $pagination;
/**
* @param Proxy $proxy
* @param $term
* @param array $options
*/
public function __construct(Proxy $proxy, $term, $options = [])
{
$this->proxy = $proxy;
$this->term = $term;
$this->options = $options;
}
/**
*
*/
private function getAggregations()
{
if ($aggregations = Utils::findKey($this->options, 'aggs', false))
{
foreach ($aggregations as $name => $aggregation)
{
switch ($aggregation['type'])
{
case 'terms':
$this->payload['aggs'][$name]['terms'] = ['field' => $aggregation['field'], 'size' => 0];
break;
}
}
}
}
/**
*
*/
private function getFields()
{
if (array_key_exists('fields', $this->options))
{
if (array_key_exists('autocomplete', $this->options))
{
$this->fields = array_map(function ($field)
{
return "${field}.autocomplete";
},
$this->options['fields']
);
} else
{
foreach ($this->options['fields'] as $key => $value)
{
if (is_string($key))
{
$k = $key;
$v = $value;
} else
{
// $key is the numerical index, so use $value as key
$k = $value;
$v = 'word';
}
$this->fields[] = "$k." . (($v == 'word') ? 'analyzed' : $v);
}
}
} else
{
if (array_key_exists('autocomplete', $this->options))
{
$this->fields = array_map(function ($field)
{
return "${field}.autocomplete";
},
Utils::findKey($this->proxy->getConfig(), 'autocomplete', []));
} else
{
$this->fields = ['_all'];
}
}
}
/**
* Add requested pagination parameters to the payload
*/
private function getPagination()
{
# pagination
$this->pagination['page'] = 1;
$this->pagination['per_page'] = Utils::findKey($this->options, 'limit', 50);
$this->pagination['padding'] = Utils::findKey($this->options, 'padding', 0);
$this->pagination['offset'] = Utils::findKey($this->options, 'offset', 0);
$this->payload['size'] = $this->pagination['per_page'];
$this->payload['from'] = $this->pagination['offset'];
}
/**
* Add requested highlights to the payload
*/
private function getHighlight()
{
if (Utils::findKey($this->options, 'highlight', false))
{
foreach ($this->fields as $field)
{
$this->payload['highlight']['fields'][$field] = new StdClass();
}
if ($tag = Utils::findKey($this->options['highlight'], 'tag', false))
{
$this->payload['highlight']['pre_tags'] = [$tag];
$this->payload['highlight']['post_tags'] = [preg_replace('/\A</', '</', $tag)];
}
}
}
/**
* Add requested suggestions to the payload
*/
private function getSuggest()
{
if ($suggestions = Utils::findKey($this->options, 'suggest', false))
{
$suggest_fields = Utils::findKey($this->proxy->getConfig(), 'suggest', []);
if ($fields = Utils::findKey($this->options, 'fields', false))
{
$suggest_fields = array_intersect($suggest_fields, $fields);
}
if (!empty($suggest_fields))
{
$this->payload['suggest'] = ['text' => $this->term];
foreach ($suggest_fields as $field)
{
$this->payload['suggest'][$field] = ['phrase' => ['field' => "${field}.suggest"]];
}
}
}
}
/**
* Allow sorting of results
*/
private function getSort()
{
if ($sort = Utils::findKey($this->options, 'sort', false))
{
$this->payload['sort'] = $sort;
}
}
/**
* Construct the payload from the options
*/
private function getPayload()
{
$payloads = [
'json' => Utils::findKey($this->options, 'json', false),
'query' => Utils::findKey($this->options, 'query', false),
'similar' => [
'query' => [
'more_like_this' => [
'fields' => $this->fields,
'like_text' => $this->term,
'min_doc_freq' => 1,
'min_term_freq' => 1,
'analyzer' => "larasearch_search2"
]
]
],
'autocomplete' => [
'query' => [
'multi_match' => [
'fields' => $this->fields,
'query' => $this->term,
'analyzer' => "larasearch_autocomplete_search"
]
]
]
];
// Find the correct payload based on the options
$payload_key = array_intersect_key($this->options, $payloads);
$operator = Utils::findKey($this->options, 'operator', 'and');
if (count($payload_key) == 1)
{
$this->payload = array_merge($this->payload, $payloads[key($payload_key)]);
} elseif (count($payload_key) == 0)
{
if ($this->term == '*')
{
$payload = ['match_all' => []];
} else
{
$queries = [];
foreach ($this->fields as $field)
{
$qs = [];
$shared_options = [
'query' => $this->term,
'operator' => $operator,
'boost' => 1
];
if ($field == '_all' || substr_compare($field, '.analyzed', -9, 9) === 0)
{
$qs = array_merge($qs, [
array_merge($shared_options, ['boost' => 10, 'analyzer' => "larasearch_search"]),
array_merge($shared_options, ['boost' => 10, 'analyzer' => "larasearch_search2"])
]
);
if ($misspellings = Utils::findKey($this->options, 'misspellings', false))
{
$distance = 1;
$qs = array_merge($qs, [
array_merge($shared_options, ['fuzziness' => $distance, 'max_expansions' => 3, 'analyzer' => "larasearch_search"]),
array_merge($shared_options, ['fuzziness' => $distance, 'max_expansions' => 3, 'analyzer' => "larasearch_search2"])
]
);
}
} elseif (substr_compare($field, '.exact', -6, 6) === 0)
{
$f = substr($field, 0, -6);
$queries[] = [
'match' => [
$f => array_merge($shared_options, ['analyzer' => 'keyword'])
]
];
} else
{
$analyzer = preg_match('/\.word_(start|middle|end)\z/', $field) ? "larasearch_word_search" : "larasearch_autocomplete_search";
$qs[] = array_merge($shared_options, ['analyzer' => $analyzer]);
}
$queries = array_merge($queries, array_map(function ($q) use ($field)
{
return ['match' => [$field => $q]];
}, $qs));
}
$payload = ['dis_max' => ['queries' => $queries]];
}
$this->payload['query'] = $payload;
} else
{
// We have multiple query definitions, so abort
throw new \InvalidArgumentException('Cannot use multiple query definitions.');
}
if ($load = Utils::findKey($this->options, 'load', false))
{
$this->payload['fields'] = is_array($load) ? $load : [];
} elseif ($select = Utils::findKey($this->options, 'select', false))
{
$this->payload['fields'] = $select;
}
}
/**
* Execute the query and return the response in a rich wrapper class
*
* @return Response
*/
public function execute()
{
$this->getFields();
$this->getPagination();
$this->getHighlight();
$this->getSuggest();
$this->getAggregations();
$this->getSort();
$this->getPayload();
$params = [
'index' => Utils::findKey($this->options, 'index', false) ?: $this->proxy->getIndex()->getName(),
'type' => Utils::findKey($this->options, 'type', false) ?: $this->proxy->getType(),
'body' => $this->payload
];
return new Response($this->proxy->getModel(), $this->proxy->getClient()->search($params));
}
}
================================================
FILE: src/Iverberk/Larasearch/Response/Records.php
================================================
<?php namespace Iverberk\Larasearch\Response;
use Illuminate\Support\Collection;
use Iverberk\Larasearch\Response;
class Records extends Collection {
/**
* Contains an Elasticsearch response wrapper
*
* @var \Iverberk\Larasearch\Response
*/
private $response;
/**
* Construct a collection of Eloquent models based on the search result
*
* @access public
* @param Response $response
*/
public function __construct(Response $response)
{
$this->response = $response;
$ids = array_map(function ($hit)
{
return $hit['_id'];
}, $this->response->getHits());
$model = $response->getModel();
parent::__construct($model::whereIn('id', $ids)->get()->toArray());
}
}
================================================
FILE: src/Iverberk/Larasearch/Response/Result.php
================================================
<?php namespace Iverberk\Larasearch\Response;
use Illuminate\Contracts\Support\Arrayable;
class Result implements \ArrayAccess, Arrayable {
/**
* Contains an Elasticsearch hit response
*
* @access private
* @var array
*/
private $hit;
/**
* Construct the result with the an Elasticsearch hit array
*
* @access public
* @param array $hit
*/
public function __construct(array $hit)
{
$this->hit = $hit;
}
/**
* Return the hit id
*
* @acccess public
* @return integer
*/
public function getId()
{
return (int)$this->hit['_id'];
}
/**
* Return the hit document type
*
* @access public
* @return string
*/
public function getType()
{
return $this->hit['_type'];
}
/**
* Return the hit index
*
* @access public
* @return string
*/
public function getIndex()
{
return $this->hit['_index'];
}
/**
* Return the hit score
*
* @access public
* @return float
*/
public function getScore()
{
return (float)$this->hit['_score'];
}
/**
* Return the _source object
*
* @access public
* @return array
*/
public function getSource()
{
return $this->hit['_source'];
}
/**
* @param array $fields
* @return array
*/
public function getFields($fields = [])
{
$results = [];
foreach ($fields as $field)
{
$results[$field] = $this->hit['fields'][$field];
}
return empty($fields) ? $this->hit['fields'] : $results;
}
/**
* Return the hit object
*
* @access public
* @return array
*/
public function getHit()
{
return $this->hit;
}
/**
* @param array $fields
* @return array
*/
public function getHighlights($fields = [])
{
if (!empty($fields))
{
$results = [];
foreach ($fields as $field)
{
foreach ($this->hit['highlight'] as $key => $value)
{
if (preg_match("/^${field}.*/", $key) === 1)
{
$results[$field] = $value;
}
}
}
return $results;
} else
{
return $this->hit['highlight'];
}
}
/**
* Get data by key
*
* @param string The key data to retrieve
* @return mixed
* @access public
*/
public function __get($key)
{
$item = array_get($this->hit, $this->getPath($key));
return $item;
}
/**
* Whether or not an offset exists
*
* @param mixed $offset
* @access public
* @return boolean
* @abstracting ArrayAccess
*/
public function offsetExists($offset)
{
return (array_get($this->hit, $this->getPath($offset)) !== null);
}
/**
* Returns the value at specified offset
*
* @param mixed $offset
* @access public
* @return mixed
* @abstracting ArrayAccess
*/
public function offsetGet($offset)
{
return $this->offsetExists($offset) ? array_get($this->hit, $this->getPath($offset)) : null;
}
/**
* Assigns a value to the specified offset
*
* @param mixed $offset
* @param mixed $value
* @access public
* @abstracting ArrayAccess
*/
public function offsetSet($offset, $value)
{
// Not allowed for Elasticsearch responses, update the Eloquent model instead.
}
/**
* Unsets an offset
*
* @param mixed $offset
* @access public
* @abstracting ArrayAccess
*/
public function offsetUnset($offset)
{
// Not allowed for Elasticsearch responses, update the Eloquent model instead.
}
/**
* Check if the $offset parameter contains a dot and return the appropriate path
* in the array
*
* @access private
* @param $offset
* @return string
*/
private function getPath($offset)
{
return (strpos($offset, '.') !== false) ? $path = $offset : "_source.${offset}";
}
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray()
{
return isset($this->hit['fields']) ? $this->hit['fields'] : $this->hit['_source'];
}
}
================================================
FILE: src/Iverberk/Larasearch/Response/Results.php
================================================
<?php namespace Iverberk\Larasearch\Response;
use Illuminate\Support\Collection;
use Iverberk\Larasearch\Response;
class Results extends Collection {
/**
* Contains an Elasticsearch response wrapper
*
* @var \Iverberk\Larasearch\Response
*/
private $response;
/**
* Construct a collection of Result objects based on the hits
* in the Elasticsearch response
*
* @param Response $response
*/
public function __construct(Response $response)
{
$this->response = $response;
parent::__construct(
array_map(
function ($hit)
{
return new Result($hit);
},
$this->response->getHits()
)
);
}
}
================================================
FILE: src/Iverberk/Larasearch/Response.php
================================================
<?php namespace Iverberk\Larasearch;
use Illuminate\Database\Eloquent\Model;
use Iverberk\Larasearch\Response\Results;
class Response {
/**
* @var \Illuminate\Database\Eloquent\Model
*/
private $model;
/**
* Elasticsearch response
*
* @var array
*/
private $response;
/**
* @param Model $model
* @param array $response
*/
public function __construct(Model $model, Array $response)
{
$this->model = $model;
$this->response = $response;
}
/**
* @return Model
*/
public function getModel()
{
return $this->model;
}
/**
* @return array
*/
public function getResponse()
{
return $this->response;
}
/**
* @return Results
*/
public function getResults()
{
return new Results($this);
}
/**
* @return \Illuminate\Database\Eloquent\Collection|static[]
*/
public function getRecords()
{
if (count($this->getHits()) > 0)
{
$ids = array_map(function ($hit)
{
return $hit['_id'];
}, $this->getHits());
return call_user_func_array(array($this->model, 'whereIn'), array('id', $ids))->get();
} else
{
return call_user_func(array($this->model, 'newCollection'));
}
}
/**
* @return mixed
*/
public function getTook()
{
return $this->response['took'];
}
/**
* @return mixed
*/
public function getHits()
{
return $this->response['hits']['hits'];
}
/**
* @return mixed
*/
public function getTimedOut()
{
return $this->response['timed_out'];
}
/**
* @return mixed
*/
public function getShards()
{
return $this->response['_shards'];
}
/**
* @return mixed
*/
public function getMaxScore()
{
return $this->response['hits']['max_score'];
}
/**
* @return mixed
*/
public function getTotal()
{
return $this->response['hits']['total'];
}
/**
* @param array $fields
* @return mixed
*/
public function getSuggestions($fields = [])
{
if (!empty($fields))
{
$results = [];
foreach ($fields as $field)
{
foreach ($this->response['suggest'] as $key => $value)
{
if (preg_match("/^${field}.*/", $key) !== false)
{
$results[$field] = $value;
}
}
}
return $results;
} else
{
return $this->response['suggest'];
}
}
/**
* @param string $name
* @return array
*/
public function getAggregations($name = '')
{
return empty($name) ? $this->response['aggregations'] : $this->response['aggregations'][$name];
}
}
================================================
FILE: src/Iverberk/Larasearch/Traits/CallableTrait.php
================================================
<?php namespace Iverberk\Larasearch\Traits;
use Illuminate\Database\Eloquent\Model;
use Iverberk\Larasearch\Observer;
trait CallableTrait {
/**
* Boot the trait by registering the Larasearch observer with the model
*/
public static function bootCallableTrait()
{
if (new static instanceof Model)
{
static::observe(new Observer);
} else
{
throw new \Exception("This trait can ony be used in Eloquent models.");
}
}
}
================================================
FILE: src/Iverberk/Larasearch/Traits/SearchableTrait.php
================================================
<?php namespace Iverberk\Larasearch\Traits;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\App;
trait SearchableTrait {
use TransformableTrait;
use CallableTrait;
/**
* The Elasticsearch proxy class
*
* @var \Iverberk\Larasearch\Proxy
*/
protected static $__es_proxy = null;
/**
* Related Eloquent models as dot separated paths
*
* @var array
*/
private static $__es_paths = [];
/**
* Boolean variable to globally enable/disable (re)indexing
*
* @var bool
*/
public static $__es_enable = true;
/**
* Return an instance of the Elasticsearch proxy
*
* @throws \Exception
* @return \Iverberk\Larasearch\Proxy | bool
*/
public static function getProxy()
{
if (!static::$__es_proxy)
{
$instance = new static;
if ($instance instanceof Model)
{
static::$__es_proxy = App::make('iverberk.larasearch.proxy', $instance);
return static::$__es_proxy;
} else
{
throw new \Exception("This trait can ony be used in Eloquent models.");
}
}
return static::$__es_proxy;
}
/**
* Clear the Elasticsearch proxy
*/
public static function clearProxy()
{
static::$__es_proxy = null;
}
/**
* Catch dynamic method calls intended for the Elasticsearch proxy
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
$proxy = static::getProxy();
if (is_callable([$proxy, $method]))
{
return call_user_func_array(array($proxy, $method), $parameters);
}
return parent::__call($method, $parameters);
}
/**
* Catch dynamic static method calls intended for the Elasticsearch proxy
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public static function __callStatic($method, $parameters)
{
$proxy = static::getProxy();
if (is_callable([$proxy, $method]))
{
return call_user_func_array(array($proxy, $method), $parameters);
}
return parent::__callStatic($method, $parameters);
}
/**
* Allow custom generation of Elasticsearch document id
*
* @return mixed
*/
public function getEsId()
{
return $this->getKey();
}
}
================================================
FILE: src/Iverberk/Larasearch/Traits/TransformableTrait.php
================================================
<?php namespace Iverberk\Larasearch\Traits;
use Illuminate\Support\Facades\Config;
trait TransformableTrait {
/**
* Transform the Person model and its relations to an Elasticsearch document.
*
* @param bool $relations
* @return array
*/
public function transform($relations = false)
{
$relations = $relations ? Config::get('larasearch.paths.' . get_class($this)) : [];
$doc = $this->load($relations)->toArray();
return $doc;
}
}
================================================
FILE: src/Iverberk/Larasearch/Utils.php
================================================
<?php namespace Iverberk\Larasearch;
use PHPParser_Parser;
use PHPParser_Lexer;
use PHPParser_Node_Stmt_Namespace;
Use PHPParser_Node_Stmt_Class;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RegexIterator;
class Utils {
/**
* Read and return parameters from an array.
*
* @param array $params
* @param string $arg
*
* @param null $default
* @return null|mixed
*/
public static function findKey($params, $arg, $default = null)
{
if (is_object($params) === true)
{
$params = (array)$params;
}
if (isset($params[$arg]) === true)
{
$val = $params[$arg];
unset($params[$arg]);
return $val;
} else
{
return $default;
}
}
/**
* Taken from http://php.net/manual/en/function.array-merge-recursive.php#92195
* Removed the pass-by-reference to accomdate unit-testing
*
* @param array $array1
* @param array $array2
* @return array
*/
public static function array_merge_recursive_distinct(array $array1, array $array2)
{
$merged = $array1;
foreach ($array2 as $key => &$value)
{
if (is_array($value) && isset ($merged[$key]) && is_array($merged[$key]))
{
$merged[$key] = self::array_merge_recursive_distinct($merged[$key], $value);
} else
{
$merged[$key] = $value;
}
}
return $merged;
}
public static function findSearchableModels($directories)
{
$models = [];
$parser = new PHPParser_Parser(new PHPParser_Lexer);
// Iterate over each directory and inspect files for models
foreach ($directories as $directory)
{
// iterate over all .php files in the directory
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
$files = new RegexIterator($files, '/\.php$/');
foreach ($files as $file)
{
// read the file that should be converted
$code = file_get_contents($file);
// parse
$stmts = $parser->parse($code);
$walk = function ($stmt, $key, $ns) use (&$models, &$walk)
{
if ($stmt instanceof PHPParser_Node_Stmt_Namespace)
{
$new_ns = implode('\\', $stmt->name->parts);
if ($ns && strpos($new_ns, $ns) !== 0) $new_ns = $ns . $new_ns;
array_walk($stmt->stmts, $walk, $new_ns);
} else if ($stmt instanceof PHPParser_Node_Stmt_Class)
{
$class = $stmt->name;
if ($ns) $class = $ns . '\\' . $class;
if (in_array('Iverberk\\Larasearch\\Traits\\SearchableTrait', class_uses($class)))
{
$models[] = $class;
}
}
};
array_walk($stmts, $walk, '');
}
}
return $models;
}
}
================================================
FILE: src/config/larasearch.php
================================================
<?php
use Psr\Log\LogLevel;
$compiled = __DIR__ . '/paths.json';
// Check for a json file that contains the compiled paths for model relations
$pathConfig = file_exists($compiled) ? json_decode(file_get_contents($compiled), true) : [];
return array_merge($pathConfig, array(
'elasticsearch' => [
/**
* Configuration array for the low-level Elasticsearch client. See
* http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/_configuration.html
* for additional options.
*/
'params' => [
'hosts' => [ 'localhost:9200' ],
'connectionClass' => '\Elasticsearch\Connections\GuzzleConnection',
'connectionFactoryClass'=> '\Elasticsearch\Connections\ConnectionFactory',
'connectionPoolClass' => '\Elasticsearch\ConnectionPool\StaticNoPingConnectionPool',
'selectorClass' => '\Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector',
'serializerClass' => '\Elasticsearch\Serializers\SmartSerializer',
'sniffOnStart' => false,
'connectionParams' => [],
'logging' => false,
'logObject' => null,
'logPath' => 'elasticsearch.log',
'logLevel' => LogLevel::WARNING,
'traceObject' => null,
'tracePath' => 'elasticsearch.log',
'traceLevel' => LogLevel::WARNING,
'guzzleOptions' => [],
'connectionPoolParams' => ['randomizeHosts' => true],
'retries' => null,
],
'analyzers' => [
'autocomplete',
'suggest',
'text_start',
'text_middle',
'text_end',
'word_start',
'word_middle',
'word_end'
],
/**
* Default configuration array for Elasticsearch indices based on Eloquent models
* CREDIT: Analyzers, Tokenizers and Filters are copied and renamed from the Searchkick
* project to get started quickly.
*/
'defaults' => [
'index' => [
'settings' => [
'number_of_shards' => 1,
'number_of_replicas' => 0,
'analysis' => [
'analyzer' => [
'larasearch_keyword' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "larasearch_stemmer"]
],
'default_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["standard", "lowercase", "asciifolding", "larasearch_index_shingle", "larasearch_stemmer"]
],
'larasearch_search' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["standard", "lowercase", "asciifolding", "larasearch_search_shingle", "larasearch_stemmer"]
],
'larasearch_search2' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["standard", "lowercase", "asciifolding", "larasearch_stemmer"]
],
'larasearch_autocomplete_index' => [
'type' => "custom",
'tokenizer' => "larasearch_autocomplete_ngram",
'filter' => ["lowercase", "asciifolding"]
],
'larasearch_autocomplete_search' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding"]
],
'larasearch_word_search' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding"]
],
'larasearch_suggest_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "larasearch_suggest_shingle"]
],
'larasearch_text_start_index' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding", "larasearch_edge_ngram"]
],
'larasearch_text_middle_index' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding", "larasearch_ngram"]
],
'larasearch_text_end_index' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding", "reverse", "larasearch_edge_ngram", "reverse"]
],
'larasearch_word_start_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "larasearch_edge_ngram"]
],
'larasearch_word_middle_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "larasearch_ngram"]
],
'larasearch_word_end_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "reverse", "larasearch_edge_ngram", "reverse"]
]
],
'filter' => [
'larasearch_index_shingle' => [
'type' => "shingle",
'token_separator' => ""
],
'larasearch_search_shingle' => [
'type' => "shingle",
'token_separator' => "",
'output_unigrams' => false,
'output_unigrams_if_no_shingles' => true
],
'larasearch_suggest_shingle' => [
'type' => "shingle",
'max_shingle_size' => 5
],
'larasearch_edge_ngram' => [
'type' => "edgeNGram",
'min_gram' => 1,
'max_gram' => 50
],
'larasearch_ngram' => [
'type' => "nGram",
'min_gram' => 1,
'max_gram' => 50
],
'larasearch_stemmer' => [
'type' => "snowball",
'language' => "English"
]
],
'tokenizer' => [
'larasearch_autocomplete_ngram' => [
'type' => "edgeNGram",
'min_gram' => 1,
'max_gram' => 50
]
]
]
],
'mappings' => [
'_default_' => [
# https://gist.github.com/kimchy/2898285
'dynamic_templates' => [
[
'string_template' => [
'match' => '*',
'match_mapping_type' => 'string',
'mapping' => [
# http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/
'type' => 'multi_field',
'fields' => [
# analyzed field must be the default field for include_in_all
# http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/
# however, we can include the not_analyzed field in _all
# and the _all index analyzer will take care of it
'{name}' => ['type' => 'string', 'index' => 'not_analyzed'],
'analyzed' => ['type' => 'string', 'index' => 'analyzed']
]
]
]
]
]
]
]
]
],
'index_prefix' => ''
],
'logger' => 'iverberk.larasearch.logger'
));
================================================
FILE: tests/Iverberk/Larasearch/Commands/PathsCommandTest.php
================================================
<?php namespace Iverberk\Larasearch\Commands;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\File;
use Symfony\Component\Console\Input\InputOption;
use Mockery as m;
/**
* Global function mocks
*/
function app_path()
{
return PathsCommandTest::$functions->app_path();
}
function constant($const)
{
return PathsCommandTest::$functions->constant($const);
}
function base_path()
{
return PathsCommandTest::$functions->base_path();
}
/**
* Class PathsCommandTest
* @package Iverberk\Larasearch\Commands
* @preserveGlobalState disabled
*/
class PathsCommandTest extends \PHPUnit_Framework_TestCase {
/**
* @var \Mockery\Mock $functions
*/
public static $functions;
/**
*
*/
public function setUp()
{
parent::setUp();
self::$functions = m::mock();
}
/**
*
*/
protected function tearDown()
{
m::close();
}
/**
* @test
*/
public function it_should_get_options()
{
/**
*
* Set
*
**/
$command = m::mock('Iverberk\Larasearch\Commands\PathsCommand');
$options = array(
array('dir', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Directory to scan for searchable models', null, ''),
array('relations', null, InputOption::VALUE_NONE, 'Include related Eloquent models', null),
array('write-config', null, InputOption::VALUE_NONE, 'Include the compiled paths in the package configuration', null),
);
/**
*
* Assertion
*
**/
$this->assertEquals($options, $command->getOptions());
}
/**
* @test
*/
public function it_should_get_arguments()
{
/**
*
* Set
*
**/
$command = m::mock('Iverberk\Larasearch\Commands\PathsCommand');
$arguments = array(
array('model', InputOption::VALUE_OPTIONAL, 'Eloquent model to find paths for', null)
);
/**
*
* Assertion
*
**/
$this->assertEquals($arguments, $command->getArguments());
}
/**
* @test
*/
public function it_should_fire_with_models_and_config()
{
/**
*
* Set
*
* @var \Mockery\Mock $command
*/
$command = m::mock('Iverberk\Larasearch\Commands\PathsCommand')->makePartial();
$command->shouldAllowMockingProtectedMethods();
File::clearResolvedInstance('files');
File::shouldReceive('put')->once()->andReturn(true);
File::shouldReceive('exists')->once()->andReturn(true);
App::shouldReceive('make')->andReturn(true);
self::$functions->shouldReceive('base_path')->once()->andReturn('');
/**
*
* Expectation
*
*/
$command->shouldReceive('argument')
->with('model')
->once()
->andReturn(['Husband']);
$command->shouldReceive('option')
->with('dir')
->once()
->andReturn([__DIR__ . '/../../../Support/Stubs']);
$command->shouldReceive('option')
->with('write-config')
->once()
->andReturn(true);
$command->shouldReceive('option')
->with('relations')
->times(17)
->andReturn(true);
$command->shouldReceive('error', 'confirm', 'call', 'info')
->andReturn(true);
/**
*
* Assertion
*
*/
$command->fire();
$expected = [
'Husband' => ['wife.children.toys'],
'Child' => ['mother', 'father', 'toys'],
'Toy' => ['children.mother', 'children.father'],
'Wife' => ['husband', 'children.toys'],
'House\\Item' => []
];
$actual = $command->getPaths();
foreach ($expected as $model => $paths)
{
$this->assertArrayHasKey($model, $actual);
foreach ($paths as $path)
{
$this->assertContains($path, $actual[$model]);
}
}
$expected = [
'Husband' => ['', 'wife', 'children', 'children.toys'],
'Child' => ['mother.husband', 'mother', '', 'toys'],
'Toy' => ['children.mother.husband', 'children.mother', 'children', ''],
'Wife' => ['husband', '', 'children', 'children.toys'],
'House\\Item' => ['']
];
$actual = $command->getReversedPaths();
foreach ($expected as $model => $paths)
{
$this->assertArrayHasKey($model, $actual);
foreach ($paths as $path)
{
$this->assertContains($path, $actual[$model]);
}
}
}
/**
* @test
*/
public function it_should_fire_without_models()
{
/**
* Set
*
* @var \Mockery\Mock $command
*/
$command = m::mock('Iverberk\Larasearch\Commands\PathsCommand')->makePartial();
$command->shouldAllowMockingProtectedMethods();
App::shouldReceive('make')->andReturn(true);
/**
*
* Expectation
*
*/
$command->shouldReceive('argument')
->with('model')
->once()
->andReturn([]);
$command->shouldReceive('option')
->with('dir')
->once()
->andReturn([]);
$command->shouldReceive('compilePaths', 'error', 'confirm', 'call', 'info')
->andReturn(true);
/**
*
* Assertion
*
*/
$command->fire();
$this->assertEquals(
[],
$command->getPaths()
);
$this->assertEquals(
[],
$command->getReversedPaths()
);
}
/**
* @test
*/
public function it_should_fire_without_config()
{
/**
* Set
*
* @var \Mockery\Mock $command
*/
$command = m::mock('Iverberk\Larasearch\Commands\PathsCommand')->makePartial();
$command->shouldAllowMockingProtectedMethods();
App::shouldReceive('make')->andReturn(true);
/**
*
* Expectation
*
*/
$command->shouldReceive('argument')
->with('model')
->once()
->andReturn(['Husband']);
$command->shouldReceive('option')
->with('dir')
->once()
->andReturn([__DIR__ . '/../../../Support/Stubs']);
$command->shouldReceive('option')
->with('write-config')
->once()
->andReturn(false);
$command->shouldReceive('compilePaths', 'error', 'confirm', 'call', 'info')
->andReturn(true);
/**
*
* Assertion
*
*/
$command->fire();
}
/**
* @test
*/
public function it_should_fire_with_laravel_and_config_confirmed()
{
/**
*
* Set
*
* @var \Mockery\Mock $command
*/
$command = m::mock('Iverberk\Larasearch\Commands\PathsCommand')->makePartial();
$command->shouldAllowMockingProtectedMethods();
File::clearResolvedInstance('files');
File::shouldReceive('put')->once()->andReturn(true);
File::shouldReceive('exists')->once()->andReturn(false);
App::shouldReceive('make')->andReturn(true);
self::$functions->shouldReceive('base_path')->once()->andReturn('');
/**
*
* Expectation
*
*/
$command->shouldReceive('getLaravel')
->once()
->andReturn(true);
$command->shouldReceive('argument')
->with('model')
->once()
->andReturn(['Husband']);
$command->shouldReceive('option')
->with('dir')
->once()
->andReturn([__DIR__ . '/../../../Support/Stubs']);
$command->shouldReceive('option')
->with('write-config')
->once()
->andReturn(true);
$command->shouldReceive('confirm')
->once()
->andReturn(true);
$command->shouldReceive('compilePaths', 'error', 'call', 'info')
->andReturn(true);
/**
*
* Assertion
*
*/
$command->fire();
}
/**
* @test
*/
public function it_should_fire_with_config_not_confirmed()
{
/**
* Set
*
* @var \Mockery\Mock $command
*/
$command = m::mock('Iverberk\Larasearch\Commands\PathsCommand')->makePartial();
$command->shouldAllowMockingProtectedMethods();
File::clearResolvedInstance('files');
File::shouldReceive('exists')->once()->andReturn(false);
App::shouldReceive('make')->andReturn(true);
self::$functions->shouldReceive('base_path')->once()->andReturn('');
/**
* Expectation
*/
$command->shouldReceive('getLaravel')
->once()
->andReturn(true);
$command->shouldReceive('argument')
->with('model')
->once()
->andReturn(['Husband']);
$command->shouldReceive('option')
->with('dir')
->once()
->andReturn([__DIR__ . '/../../../Support/Stubs']);
$command->shouldReceive('option')
->with('write-config')
->once()
->andReturn(true);
$command->shouldReceive('confirm')
->once()
->andReturn(false);
$command->shouldReceive('compilePaths', 'error', 'call', 'info')
->andReturn(true);
/*
|------------------------------------------------------------
| Assertion
|------------------------------------------------------------
*/
$command->fire();
}
}
================================================
FILE: tests/Iverberk/Larasearch/Commands/ReindexCommandTest.php
================================================
<?php namespace Iverberk\Larasearch\Commands;
use Symfony\Component\Console\Input\InputOption;
use Mockery as m;
class ReindexCommandTest extends \PHPUnit_Framework_TestCase {
/**
*
*/
protected function tearDown()
{
m::close();
}
/**
* @test
*/
public function it_should_get_options()
{
/**
*
* Set
*
**/
$command = m::mock('Iverberk\Larasearch\Commands\ReindexCommand');
$options = array(
array('relations', null, InputOption::VALUE_NONE, 'Reindex related Eloquent models', null),
array('mapping', null, InputOption::VALUE_REQUIRED, 'A file containing custom mappings', null),
array('dir', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Directory to scan for searchable models', null),
array('batch', null, InputOption::VALUE_OPTIONAL, 'The number of records to index in a single batch', 750),
array('force', null, InputOption::VALUE_NONE, 'Overwrite existing indices and documents', null)
);
/**
*
* Assertion
*
**/
$this->assertEquals($options, $command->getOptions());
}
/**
* @test
*/
public function it_should_get_arguments()
{
/**
*
* Set
*
**/
$command = m::mock('Iverberk\Larasearch\Commands\ReindexCommand');
$arguments = array(
array('model', InputOption::VALUE_OPTIONAL, 'Eloquent model to reindex', null)
);
/**
*
* Assertion
*
**/
$this->assertEquals($arguments, $command->getArguments());
}
/**
* @test
*/
public function it_should_fire_without_models()
{
/**
*
* Set
*
**/
/* @var \Mockery\Mock $command */
$command = m::mock('Iverberk\Larasearch\Commands\ReindexCommand')->makePartial();
/**
*
* Expectation
*
*/
$command->shouldReceive('argument')
->with('model')
->once()
->andReturn([]);
$command->shouldReceive('option')
->with('dir')
->once()
->andReturn([]);
$command->shouldReceive('info')
->once()
->andReturn(true);
/**
*
* Assertion
*
*/
$command->fire();
}
/**
* @test
*/
public function it_should_fire_with_models()
{
/**
*
* Set
*
*/
/* @var \Mockery\Mock $command */
$command = m::mock('Iverberk\Larasearch\Commands\ReindexCommand')->makePartial();
$command->shouldAllowMockingProtectedMethods();
$model = m::mock('Husband');
/**
*
* Expectation
*
*/
$model->shouldReceive('reindex')
->with(true, 750, null, \Mockery::type('closure'))
->times(5)
->andReturnUsing(function ($relations, $batch, $mapping, $callback)
{
$callback(1);
});
$command->shouldReceive('argument')
->with('model')
->once()
->andReturn(['Husband']);
$command->shouldReceive('option')
->with('dir')
->once()
->andReturn([__DIR__ . '/../../../Support/Stubs']);
$command->shouldReceive('option')
->with('mapping')
->times(5)
->andReturn(false);
$command->shouldReceive('option')
->with('relations')
->times(5)
->andReturn(true);
$command->shouldReceive('option')
->with('batch')
->times(5)
->andReturn(750);
$command->shouldReceive('info')->andReturn(true);
$command->shouldReceive('getModelInstance')->times(5)->andReturn($model);
/**
*
* Assertion
*
*/
$command->fire();
}
/**
* @test
*/
public function it_should_get_a_model_instance()
{
/**
*
* Set
*
*/
$command = m::mock('Iverberk\Larasearch\Commands\ReindexCommand')->makePartial();
$command->shouldAllowMockingProtectedMethods();
/**
*
* Assertion
*
*/
$model = $command->getModelInstance('Husband');
$this->assertInstanceOf('Husband', $model);
}
}
================================================
FILE: tests/Iverberk/Larasearch/IndexTest.php
================================================
<?php namespace Iverberk\Larasearch;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Facade;
use Illuminate\Support\Facades\Config;
use Mockery as m;
use AspectMock\Test as am;
class IndexTest extends \PHPUnit_Framework_TestCase {
protected function tearDown()
{
m::close();
am::clean();
}
/**
* @test
*/
public function it_should_import()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
*/
list($index) = $this->getMocks();
$test = $this;
/**
*
* Expectation
*
*/
/* @var \Mockery\Mock $model */
$model = m::mock('Illuminate\Database\Eloquent\Model')->makePartial();
$model->shouldReceive('with->skip->take->get')
->twice()
->andReturn([
$model, $model, $model
], []);
$model->shouldReceive('getEsId')
->times(3)
->andReturn(1);
$model->shouldReceive('transform')
->times(3)
->andReturn(['mock', 'data']);
$index->shouldReceive('bulk')
->andReturn();
/**
*
* Assertion
*
*/
$index->import($model, [], 750, function ($batch) use ($test)
{
$test->assertEquals(1, $batch);
});
}
/**
* @test
*/
public function it_should_set_name()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
*/
list($index) = $this->getMocks('bar_');
/**
*
* Assertion
*
*/
$this->assertEquals($index, $index->setName('Mock'));
$this->assertEquals('bar_mock', $index->getName());
}
/**
* @test
*/
public function it_should_only_prepend_prefix_once()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
*/
list($index) = $this->getMocks('baz_');
/**
* Assertions
*/
$this->assertEquals($index, $index->setName('baz_MockMe'));
$this->assertEquals('baz_mockme', $index->getName());
}
/**
* @test
*/
public function it_should_get_name()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
*/
list($index) = $this->getMocks();
/**
*
* Assertion
*
*/
$this->assertEquals('husband', $index->getName());
}
/**
* @test
*/
public function it_should_create_an_index()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
$test = $this;
/**
*
* Expectation
*
*/
Config::shouldReceive('get')
->with('larasearch.elasticsearch.analyzers')
->andReturn([
'autocomplete',
'suggest',
'text_start',
'text_middle',
'text_end',
'word_start',
'word_middle',
'word_end'
]);
Config::shouldReceive('get')
->with('larasearch.elasticsearch.defaults.index')
->andReturn([
'settings' => [
'number_of_shards' => 1,
'number_of_replicas' => 0,
'analysis' => [
'analyzer' => [
'larasearch_keyword' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "larasearch_stemmer"]
],
'default_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["standard", "lowercase", "asciifolding", "larasearch_index_shingle", "larasearch_stemmer"]
],
'larasearch_search' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["standard", "lowercase", "asciifolding", "larasearch_search_shingle", "larasearch_stemmer"]
],
'larasearch_search2' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["standard", "lowercase", "asciifolding", "larasearch_stemmer"]
],
'larasearch_autocomplete_index' => [
'type' => "custom",
'tokenizer' => "larasearch_autocomplete_ngram",
'filter' => ["lowercase", "asciifolding"]
],
'larasearch_autocomplete_search' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding"]
],
'larasearch_word_search' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding"]
],
'larasearch_suggest_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "larasearch_suggest_shingle"]
],
'larasearch_text_start_index' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding", "larasearch_edge_ngram"]
],
'larasearch_text_middle_index' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding", "larasearch_ngram"]
],
'larasearch_text_end_index' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding", "reverse", "larasearch_edge_ngram", "reverse"]
],
'larasearch_word_start_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "larasearch_edge_ngram"]
],
'larasearch_word_middle_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "larasearch_ngram"]
],
'larasearch_word_end_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "reverse", "larasearch_edge_ngram", "reverse"]
]
],
'filter' => [
'larasearch_index_shingle' => [
'type' => "shingle",
'token_separator' => ""
],
'larasearch_search_shingle' => [
'type' => "shingle",
'token_separator' => "",
'output_unigrams' => false,
'output_unigrams_if_no_shingles' => true
],
'larasearch_suggest_shingle' => [
'type' => "shingle",
'max_shingle_size' => 5
],
'larasearch_edge_ngram' => [
'type' => "edgeNGram",
'min_gram' => 1,
'max_gram' => 50
],
'larasearch_ngram' => [
'type' => "nGram",
'min_gram' => 1,
'max_gram' => 50
],
'larasearch_stemmer' => [
'type' => "snowball",
'language' => "English"
]
],
'tokenizer' => [
'larasearch_autocomplete_ngram' => [
'type' => "edgeNGram",
'min_gram' => 1,
'max_gram' => 50
]
]
]
]]);
$client->shouldReceive('indices->create')
->andReturnUsing(function ($params) use ($test)
{
$test->assertEquals(json_decode(
'{
"index": "husband",
"body": {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"analysis": {
"analyzer": {
"larasearch_keyword": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"larasearch_stemmer"
]
},
"default_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"standard",
"lowercase",
"asciifolding",
"larasearch_index_shingle",
"larasearch_stemmer"
]
},
"larasearch_search": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"standard",
"lowercase",
"asciifolding",
"larasearch_search_shingle",
"larasearch_stemmer"
]
},
"larasearch_search2": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"standard",
"lowercase",
"asciifolding",
"larasearch_stemmer"
]
},
"larasearch_autocomplete_index": {
"type": "custom",
"tokenizer": "larasearch_autocomplete_ngram",
"filter": [
"lowercase",
"asciifolding"
]
},
"larasearch_autocomplete_search": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"asciifolding"
]
},
"larasearch_word_search": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding"
]
},
"larasearch_suggest_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"larasearch_suggest_shingle"
]
},
"larasearch_text_start_index": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"asciifolding",
"larasearch_edge_ngram"
]
},
"larasearch_text_middle_index": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"asciifolding",
"larasearch_ngram"
]
},
"larasearch_text_end_index": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"asciifolding",
"reverse",
"larasearch_edge_ngram",
"reverse"
]
},
"larasearch_word_start_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"larasearch_edge_ngram"
]
},
"larasearch_word_middle_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"larasearch_ngram"
]
},
"larasearch_word_end_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"reverse",
"larasearch_edge_ngram",
"reverse"
]
}
},
"filter": {
"larasearch_index_shingle": {
"type": "shingle",
"token_separator": ""
},
"larasearch_search_shingle": {
"type": "shingle",
"token_separator": "",
"output_unigrams": false,
"output_unigrams_if_no_shingles": true
},
"larasearch_suggest_shingle": {
"type": "shingle",
"max_shingle_size": 5
},
"larasearch_edge_ngram": {
"type": "edgeNGram",
"min_gram": 1,
"max_gram": 50
},
"larasearch_ngram": {
"type": "nGram",
"min_gram": 1,
"max_gram": 50
},
"larasearch_stemmer": {
"type": "snowball",
"language": "English"
}
},
"tokenizer": {
"larasearch_autocomplete_ngram": {
"type": "edgeNGram",
"min_gram": 1,
"max_gram": 50
}
}
}
},
"mappings": {
"_default_": {
"properties": {
"name": {
"type": "multi_field",
"fields": {
"name": {
"type": "string",
"index": "not_analyzed"
},
"analyzed": {
"type": "string",
"index": "analyzed"
},
"autocomplete": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_autocomplete_index"
},
"suggest": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_suggest_index"
},
"text_start": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_start_index"
},
"text_middle": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_middle_index"
},
"text_end": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_end_index"
},
"word_start": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_start_index"
},
"word_middle": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_middle_index"
},
"word_end": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_end_index"
}
}
},
"wife": {
"type": "object",
"properties": {
"name": {
"type": "multi_field",
"fields": {
"name": {
"type": "string",
"index": "not_analyzed"
},
"analyzed": {
"type": "string",
"index": "analyzed"
},
"autocomplete": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_autocomplete_index"
}
}
},
"children": {
"type": "object",
"properties": {
"name": {
"type": "multi_field",
"fields": {
"name": {
"type": "string",
"index": "not_analyzed"
},
"analyzed": {
"type": "string",
"index": "analyzed"
},
"text_start": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_start_index"
},
"text_middle": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_middle_index"
},
"text_end": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_end_index"
},
"word_start": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_start_index"
},
"word_middle": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_middle_index"
},
"word_end": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_end_index"
}
}
}
}
}
}
}
}
}
},
"index": "husband",
"type": "Husband"
}
}', true)
,
$params);
});
$proxy->shouldReceive('getType')->andReturn('Husband');
$proxy->shouldReceive('getConfig')->andReturn([
'autocomplete' => ['name', 'wife.name'],
'suggest' => ['name'],
'text_start' => ['name', 'wife.children.name'],
'text_middle' => ['name', 'wife.children.name'],
'text_end' => ['name', 'wife.children.name'],
'word_start' => ['name', 'wife.children.name'],
'word_middle' => ['name', 'wife.children.name'],
'word_end' => ['name', 'wife.children.name']
]);
/**
*
* Assertion
*
*/
$index->create();
}
/**
* @test
*/
public function it_should_create_an_index_with_a_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
$test = $this;
/**
*
* Expectation
*
*/
Config::shouldReceive('get')
->with('larasearch.elasticsearch.analyzers')
->andReturn([
'autocomplete',
'suggest',
'text_start',
'text_middle',
'text_end',
'word_start',
'word_middle',
'word_end'
]);
Config::shouldReceive('get')
->with('larasearch.elasticsearch.defaults.index')
->andReturn([
'settings' => [
'number_of_shards' => 1,
'number_of_replicas' => 0,
'analysis' => [
'analyzer' => [
'larasearch_keyword' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "larasearch_stemmer"]
],
'default_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["standard", "lowercase", "asciifolding", "larasearch_index_shingle", "larasearch_stemmer"]
],
'larasearch_search' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["standard", "lowercase", "asciifolding", "larasearch_search_shingle", "larasearch_stemmer"]
],
'larasearch_search2' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["standard", "lowercase", "asciifolding", "larasearch_stemmer"]
],
'larasearch_autocomplete_index' => [
'type' => "custom",
'tokenizer' => "larasearch_autocomplete_ngram",
'filter' => ["lowercase", "asciifolding"]
],
'larasearch_autocomplete_search' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding"]
],
'larasearch_word_search' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding"]
],
'larasearch_suggest_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "larasearch_suggest_shingle"]
],
'larasearch_text_start_index' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding", "larasearch_edge_ngram"]
],
'larasearch_text_middle_index' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding", "larasearch_ngram"]
],
'larasearch_text_end_index' => [
'type' => "custom",
'tokenizer' => "keyword",
'filter' => ["lowercase", "asciifolding", "reverse", "larasearch_edge_ngram", "reverse"]
],
'larasearch_word_start_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "larasearch_edge_ngram"]
],
'larasearch_word_middle_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "larasearch_ngram"]
],
'larasearch_word_end_index' => [
'type' => "custom",
'tokenizer' => "standard",
'filter' => ["lowercase", "asciifolding", "reverse", "larasearch_edge_ngram", "reverse"]
]
],
'filter' => [
'larasearch_index_shingle' => [
'type' => "shingle",
'token_separator' => ""
],
'larasearch_search_shingle' => [
'type' => "shingle",
'token_separator' => "",
'output_unigrams' => false,
'output_unigrams_if_no_shingles' => true
],
'larasearch_suggest_shingle' => [
'type' => "shingle",
'max_shingle_size' => 5
],
'larasearch_edge_ngram' => [
'type' => "edgeNGram",
'min_gram' => 1,
'max_gram' => 50
],
'larasearch_ngram' => [
'type' => "nGram",
'min_gram' => 1,
'max_gram' => 50
],
'larasearch_stemmer' => [
'type' => "snowball",
'language' => "English"
]
],
'tokenizer' => [
'larasearch_autocomplete_ngram' => [
'type' => "edgeNGram",
'min_gram' => 1,
'max_gram' => 50
]
]
]
]]);
$client->shouldReceive('indices->create')
->andReturnUsing(function ($params) use ($test)
{
$test->assertEquals(json_decode(
'{
"index": "bar_husband",
"body": {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"analysis": {
"analyzer": {
"larasearch_keyword": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"larasearch_stemmer"
]
},
"default_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"standard",
"lowercase",
"asciifolding",
"larasearch_index_shingle",
"larasearch_stemmer"
]
},
"larasearch_search": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"standard",
"lowercase",
"asciifolding",
"larasearch_search_shingle",
"larasearch_stemmer"
]
},
"larasearch_search2": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"standard",
"lowercase",
"asciifolding",
"larasearch_stemmer"
]
},
"larasearch_autocomplete_index": {
"type": "custom",
"tokenizer": "larasearch_autocomplete_ngram",
"filter": [
"lowercase",
"asciifolding"
]
},
"larasearch_autocomplete_search": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"asciifolding"
]
},
"larasearch_word_search": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding"
]
},
"larasearch_suggest_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"larasearch_suggest_shingle"
]
},
"larasearch_text_start_index": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"asciifolding",
"larasearch_edge_ngram"
]
},
"larasearch_text_middle_index": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"asciifolding",
"larasearch_ngram"
]
},
"larasearch_text_end_index": {
"type": "custom",
"tokenizer": "keyword",
"filter": [
"lowercase",
"asciifolding",
"reverse",
"larasearch_edge_ngram",
"reverse"
]
},
"larasearch_word_start_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"larasearch_edge_ngram"
]
},
"larasearch_word_middle_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"larasearch_ngram"
]
},
"larasearch_word_end_index": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"reverse",
"larasearch_edge_ngram",
"reverse"
]
}
},
"filter": {
"larasearch_index_shingle": {
"type": "shingle",
"token_separator": ""
},
"larasearch_search_shingle": {
"type": "shingle",
"token_separator": "",
"output_unigrams": false,
"output_unigrams_if_no_shingles": true
},
"larasearch_suggest_shingle": {
"type": "shingle",
"max_shingle_size": 5
},
"larasearch_edge_ngram": {
"type": "edgeNGram",
"min_gram": 1,
"max_gram": 50
},
"larasearch_ngram": {
"type": "nGram",
"min_gram": 1,
"max_gram": 50
},
"larasearch_stemmer": {
"type": "snowball",
"language": "English"
}
},
"tokenizer": {
"larasearch_autocomplete_ngram": {
"type": "edgeNGram",
"min_gram": 1,
"max_gram": 50
}
}
}
},
"mappings": {
"_default_": {
"properties": {
"name": {
"type": "multi_field",
"fields": {
"name": {
"type": "string",
"index": "not_analyzed"
},
"analyzed": {
"type": "string",
"index": "analyzed"
},
"autocomplete": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_autocomplete_index"
},
"suggest": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_suggest_index"
},
"text_start": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_start_index"
},
"text_middle": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_middle_index"
},
"text_end": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_end_index"
},
"word_start": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_start_index"
},
"word_middle": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_middle_index"
},
"word_end": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_end_index"
}
}
},
"wife": {
"type": "object",
"properties": {
"name": {
"type": "multi_field",
"fields": {
"name": {
"type": "string",
"index": "not_analyzed"
},
"analyzed": {
"type": "string",
"index": "analyzed"
},
"autocomplete": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_autocomplete_index"
}
}
},
"children": {
"type": "object",
"properties": {
"name": {
"type": "multi_field",
"fields": {
"name": {
"type": "string",
"index": "not_analyzed"
},
"analyzed": {
"type": "string",
"index": "analyzed"
},
"text_start": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_start_index"
},
"text_middle": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_middle_index"
},
"text_end": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_text_end_index"
},
"word_start": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_start_index"
},
"word_middle": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_middle_index"
},
"word_end": {
"type": "string",
"index": "analyzed",
"analyzer": "larasearch_word_end_index"
}
}
}
}
}
}
}
}
}
},
"index": "bar_husband",
"type": "Husband"
}
}', true)
,
$params);
});
$proxy->shouldReceive('getType')->andReturn('Husband');
$proxy->shouldReceive('getConfig')->andReturn([
'autocomplete' => ['name', 'wife.name'],
'suggest' => ['name'],
'text_start' => ['name', 'wife.children.name'],
'text_middle' => ['name', 'wife.children.name'],
'text_end' => ['name', 'wife.children.name'],
'word_start' => ['name', 'wife.children.name'],
'word_middle' => ['name', 'wife.children.name'],
'word_end' => ['name', 'wife.children.name']
]);
/**
*
* Assertion
*
*/
$index->create();
}
/**
* @test
*/
public function it_should_delete_an_index()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->delete')
->with(['index' => 'husband'])
->andReturn();
/**
*
* Assertion
*
*/
$index->delete();
}
/**
* @test
*/
public function it_should_delete_an_index_with_a_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->delete')
->with(['index' => 'bar_husband'])
->andReturn();
/**
*
* Assertion
*
*/
$index->delete();
}
/**
* @test
*/
public function it_should_check_that_an_index_exists()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->exists')
->with(['index' => 'husband'])
->andReturn();
/**
*
* Assertion
*
*/
$index->exists();
}
/**
* @test
*/
public function it_should_check_that_an_index_exists_with_a_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->exists')
->with(['index' => 'bar_husband'])
->andReturn();
/**
*
* Assertion
*
*/
$index->exists();
}
/**
* @test
*/
public function it_should_check_that_an_alias_exists()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->existsAlias')
->with(['name' => 'Alias'])
->andReturn();
/**
*
* Assertion
*
*/
$index->aliasExists('Alias');
}
/**
* @test
*/
public function it_should_check_that_an_alias_exists_with_a_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->existsAlias')
->twice()
->with(['name' => 'bar_alias'])
->andReturn();
/**
*
* Assertion
*
*/
$index->aliasExists('alias');
$index->aliasExists('bar_alias');
}
/**
* @test
*/
public function it_should_store_a_record()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
/**
*
* Expectation
*
*/
$client->shouldReceive('index')
->with([
'index' => 'husband',
'type' => 'Husband',
'id' => 1,
'body' => 'data'
])
->andReturn();
/**
*
* Assertion
*
*/
$index->store([
'type' => 'Husband',
'id' => 1,
'data' => 'data'
]);
}
/**
* @test
*/
public function it_should_store_a_record_with_an_index_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$client->shouldReceive('index')
->twice()
->with([
'index' => 'bar_husband',
'type' => 'Husband',
'id' => 1,
'body' => 'data'
])
->andReturn();
/**
*
* Assertion
*
*/
$index->store([
'type' => 'Husband',
'id' => 1,
'data' => 'data'
]);
$index->setName('bar_Husband');
$index->store([
'type' => 'Husband',
'id' => 1,
'data' => 'data'
]);
}
/**
* @test
*/
public function it_should_retrieve_a_record()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
/**
*
* Expectation
*
*/
$client->shouldReceive('get')
->with([
'index' => 'husband',
'type' => 'Husband',
'id' => 1,
])
->andReturn();
/**
*
* Assertion
*
*/
$index->retrieve([
'type' => 'Husband',
'id' => 1,
'data' => 'data'
]);
}
/**
* @test
*/
public function it_should_retrieve_a_record_iwth_an_index_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$client->shouldReceive('get')
->twice()
->with([
'index' => 'bar_husband',
'type' => 'Husband',
'id' => 1,
])
->andReturn();
/**
*
* Assertion
*
*/
$index->retrieve([
'type' => 'Husband',
'id' => 1,
'data' => 'data'
]);
$index->setName('bar_Husband');
$index->retrieve([
'type' => 'Husband',
'id' => 1,
'data' => 'data'
]);
}
/**
* @test
*/
public function it_should_remove_a_record()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
/**
*
* Expectation
*
*/
$client->shouldReceive('delete')
->with([
'index' => 'husband',
'type' => 'Husband',
'id' => 1
])
->andReturn();
/**
*
* Assertion
*
*/
$index->remove([
'type' => 'Husband',
'id' => 1
]);
}
/**
* @test
*/
public function it_should_remove_a_record_with_an_index_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$client->shouldReceive('delete')
->twice()
->with([
'index' => 'bar_husband',
'type' => 'Husband',
'id' => 1
])
->andReturn();
/**
*
* Assertion
*
*/
$index->remove([
'type' => 'Husband',
'id' => 1
]);
$index->setName('bar_Husband');
$index->remove([
'type' => 'Husband',
'id' => 1
]);
}
/**
* @test
*/
public function it_should_inspect_tokens()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->analyze')
->with([
'index' => 'husband',
'text' => 'text',
'option1' => 1,
'option2' => 2
])
->andReturn();
/**
*
* Assertion
*
*/
$index->tokens('text', [
'option1' => 1,
'option2' => 2
]);
}
/**
* @test
*/
public function it_should_inspect_tokens_with_an_index_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->analyze')
->twice()
->with([
'index' => 'bar_husband',
'text' => 'text',
'option1' => 1,
'option2' => 2
])
->andReturn();
/**
*
* Assertion
*
*/
$index->tokens('text', [
'option1' => 1,
'option2' => 2
]);
$index->setName('bar_Husband');
$index->tokens('text', [
'option1' => 1,
'option2' => 2
]);
}
/**
* @test
*/
public function it_should_get_and_set_params()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
$index->setParams(['mock' => 'data']);
$this->assertEquals(['mock' => 'data'], $index->getParams());
}
/**
* @test
* @expectedException \Iverberk\Larasearch\Exceptions\ImportException
*/
public function it_should_store_a_records_in_bulk_with_errors()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$proxy->shouldReceive('getType')->andReturn('Husband');
$client->shouldReceive('bulk')
->with([
'index' => 'bar_husband',
'type' => 'Husband',
'body' => 'records'
])
->andReturn([
'errors' => true,
'items' => [
[
'index' => [
'error' => true
]
]
]
]);
/**
*
* Assertion
*
*/
$index->bulk('records');
}
/**
* @test
* @expectedException \Iverberk\Larasearch\Exceptions\ImportException
*/
public function it_should_store_records_having_prefix_in_bulk_with_errors()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$proxy->shouldReceive('getType')->andReturn('Husband');
$client->shouldReceive('bulk')
->with([
'index' => 'bar_husband',
'type' => 'Husband',
'body' => 'records'
])
->andReturn([
'errors' => true,
'items' => [
[
'index' => [
'error' => true
]
]
]
]);
/**
*
* Assertion
*
*/
$index->bulk('records');
$index->setName('bar_Husband');
$index->bulk('records');;
}
/**
* @test
* @expectedException \Iverberk\Larasearch\Exceptions\ImportException
*/
public function it_should_store_records_having_explicit_prefix_in_bulk_with_errors()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$proxy->shouldReceive('getType')->andReturn('Husband');
$client->shouldReceive('bulk')
->with([
'index' => 'bar_husband',
'type' => 'Husband',
'body' => 'records'
])
->andReturn([
'errors' => true,
'items' => [
[
'index' => [
'error' => true
]
]
]
]);
/**
*
* Assertion
*
*/
$index->setName('bar_Husband');
$index->bulk('records');;
}
/**
* @test
*/
public function it_should_store_a_records_in_bulk_without_errors()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
/**
*
* Expectation
*
*/
$proxy->shouldReceive('getType')->andReturn('Husband');
$client->shouldReceive('bulk')
->with([
'index' => 'husband',
'type' => 'Husband',
'body' => 'records'
])
->andReturn([
'errors' => false
]);
/**
*
* Assertion
*
*/
$index->bulk('records');
}
/**
* @test
*/
public function it_should_store_a_records_having_index_prefix_in_bulk_without_errors()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
/**
*
* Expectation
*
*/
$proxy->shouldReceive('getType')->andReturn('Husband');
$client->shouldReceive('bulk')
->twice()
->with([
'index' => 'bar_husband',
'type' => 'Husband',
'body' => 'records'
])
->andReturn([
'errors' => false
]);
/**
*
* Assertion
*
*/
$index->bulk('records');
$index->setName('bar_Husband');
$index->bulk('records');
}
/**
* @test
*/
public function it_should_clean_old_indices()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
// Mock the self::$client variable
am::double('Iverberk\Larasearch\Index', ['self::$client' => $client]);
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->getAliases')
->andReturn([
'index_123456789101112' => [
'aliases' => []
]
]);
$client->shouldReceive('indices->delete')
->with([
'index' => 'index_123456789101112'
]);
/**
*
* Assertion
*
*/
Index::clean('index');
}
/**
* @test
*/
public function it_should_clean_old_indices_with_index_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
// Mock the self::$client variable
am::double('Iverberk\Larasearch\Index', ['self::$client' => $client]);
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->getAliases')
->twice()
->andReturn([
'bar_index_123456789101112' => [
'aliases' => []
]
]);
$client->shouldReceive('indices->delete')
->twice()
->with([
'index' => 'bar_index_123456789101112'
]);
/**
*
* Assertion
*
*/
Index::clean('index');
Index::clean('bar_index');
}
/**
* @test
*/
public function it_should_update_aliases()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
// Mock the self::$client variable
am::double('Iverberk\Larasearch\Index', ['self::$client' => $client]);
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->updateAliases')
->with([
'body' => ['actions' => []]
]);
/**
*
* Assertion
*
*/
Index::updateAliases(['actions' => []]);
}
/**
* @test
*/
public function it_should_update_aliases_with_index_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
// Mock the self::$client variable
am::double('Iverberk\Larasearch\Index', ['self::$client' => $client]);
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->updateAliases')
->twice()
->with([
'body' => ['actions' => [['add' => ['index' => 'bar_Husband', 'alias' => 'bar_Father']]]]
]);
/**
*
* Assertion
*
*/
Index::updateAliases(['actions' => [['add' => ['index' => 'Husband', 'alias' => 'Father']]]]);
Index::updateAliases(['actions' => [['add' => ['index' => 'bar_Husband', 'alias' => 'bar_Father']]]]);
}
/**
* @test
*/
public function it_should_get_aliases()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
// Mock the self::$client variable
am::double('Iverberk\Larasearch\Index', ['self::$client' => $client]);
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->getAlias')
->with([
'name' => 'mock'
]);
/**
*
* Assertion
*
*/
Index::getAlias('mock');
}
/**
* @test
*/
public function it_should_get_aliases_with_an_index_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
// Mock the self::$client variable
am::double('Iverberk\Larasearch\Index', ['self::$client' => $client]);
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->getAlias')
->twice()
->with([
'name' => 'bar_mock'
]);
/**
*
* Assertion
*
*/
Index::getAlias('mock');
Index::getAlias('bar_mock');
}
/**
* @test
*/
public function it_should_refresh()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks();
// Mock the self::$client variable
am::double('Iverberk\Larasearch\Index', ['self::$client' => $client]);
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->refresh')
->with([
'index' => 'mock'
]);
/**
*
* Assertion
*
*/
Index::refresh('mock');
}
/**
* @test
*/
public function it_should_refresh_with_an_index_prefix()
{
/**
*
* Set
*
* @var \Mockery\Mock $index
* @var \Mockery\Mock $proxy
* @var \Mockery\Mock $client
*/
list($index, $proxy, $client) = $this->getMocks('bar_');
// Mock the self::$client variable
am::double('Iverberk\Larasearch\Index', ['self::$client' => $client]);
/**
*
* Expectation
*
*/
$client->shouldReceive('indices->refresh')
->twice()
->with([
'index' => 'bar_mock'
]);
/**
*
* Assertion
*
*/
Index::refresh('mock');
Index::refresh('bar_mock');
}
/**
* Construct an Index mock
*
* @return array
*/
private function getMocks($index_prefix = '')
{
/**
*
* Expectation
*
*/
Facade::clearResolvedInstances();
$client = m::mock('Elasticsearch\Client');
App::shouldReceive('make')
->with('Elasticsearch')
->andReturn($client);
Config::shouldReceive('get')
->with('larasearch.elasticsearch.index_prefix', '')
->andReturn($index_prefix);
$proxy = m::mock('Iverberk\Larasearch\Proxy');
$proxy->shouldReceive('getModel->getTable')
->andReturn('Husband');
$index = m::mock('Iverberk\Larasearch\Index', [$proxy], [m::BLOCKS => ['setName', 'setProxy']])->makePartial();
return [$index, $proxy, $client];
}
}
================================================
FILE: tests/Iverberk/Larasearch/Jobs/DeleteJobTest.php
================================================
<?php namespace Iverberk\Larasearch\Jobs;
use Mockery as m;
use AspectMock\Test as am;
class DeleteJobTest extends \PHPUnit_Framework_TestCase {
protected function tearDown()
{
m::close();
am::clean();
}
/**
* @test
*/
public function it_should_fire_job()
{
/**
*
* Set
*
*/
$app = m::mock('Illuminate\Foundation\Application');
$config = m::mock('Iverberk\Larasearch\Config');
$logger = m::mock('Monolog\Logger');
am::double('Husband', ['deleteDoc' => true]);
$job = m::mock('Illuminate\Queue\Jobs\Job');
$models = [
'Husband:999'
];
/**
*
* Expectation
*
*/
$logger->shouldReceive('info')->with('Deleting Husband with ID: 999 from Elasticsearch');
$config->shouldReceive('get')->with('logger', 'iverberk.larasearch.logger')->andReturn('iverberk.larasearch.logger');
$app->shouldReceive('make')->with('iverberk.larasearch.logger')->andReturn($logger);
$job->shouldReceive('delete')->once();
/**
*
* Assertion
*
*/
with(new DeleteJob($app, $config))->fire($job, $models);
}
}
================================================
FILE: tests/Iverberk/Larasearch/Jobs/ReindexJobTest.php
================================================
<?php namespace Iverberk\Larasearch\Jobs;
use Illuminate\Support\Facades\App;
use Mockery as m;
use AspectMock\Test as am;
use Mockery;
class ReindexJobTest extends \PHPUnit_Framework_TestCase {
protected function tearDown()
{
m::close();
am::clean();
}
/**
* @test
*/
public function it_should_fire_job_with_unresolvable_models()
{
/**
*
* Set
*
*/
App::shouldReceive('make')
->with('iverberk.larasearch.proxy', Mockery::any())
->once()
->andReturn('mock');
$app = m::mock('Illuminate\Foundation\Application');
$config = m::mock('Illuminate\Config\Repository');
$logger = m::mock('Monolog\Logger');
$job = m::mock('Illuminate\Queue\Jobs\Job');
$models = [
'Husband:99999'
];
/**
*
* Expectation
*
*/
$logger->shouldReceive('info')->with('Indexing Husband with ID: 99999');
$logger->shouldReceive('error')->with('Indexing Husband with ID: 99999 failed: No query results for model [Husband].');
$config->shouldReceive('get')->with('larasearch.logger')->andReturn('iverberk.larasearch.logger');
$app->shouldReceive('make')->with('iverberk.larasearch.logger')->andReturn($logger);
$job->shouldReceive('delete')->once();
$job->shouldReceive('release')->with(60)->once();
/**
*
* Assertion
*
*/
with(new ReindexJob($app, $config))->fire($job, $models);
}
/**
* @test
*/
public function it_should_fire_job_with_resolvable_models()
{
/**
*
* Set
*
*/
$app = m::mock('Illuminate\Foundation\Application');
$config = m::mock('Illuminate\Config\Repository');
$logger = m::mock('Monolog\Logger');
$model = m::mock('Husband');
$model->shouldReceive('refreshDoc')->with($model)->once();
$husband = am::double('Husband', ['findOrFail' => $model]);
$models = [
'Husband:999'
];
/**
*
* Expectation
*
*/
$logger->shouldReceive('info')->with('Indexing Husband with ID: 999');
$config->shouldReceive('get')->with('larasearch.logger')->andReturn('iverberk.larasearch.logger');
$app->shouldReceive('make')->with('iverberk.larasearch.logger')->andReturn($logger);
$job = m::mock('Illuminate\Queue\Jobs\Job');
$job->shouldReceive('delete')->once();
/**
*
* Assertion
*
*/
with(new ReindexJob($app, $config))->fire($job, $models);
// $husband->verifyInvoked('findOrFail');
}
}
================================================
FILE: tests/Iverberk/Larasearch/LarasearchServiceProviderTest.php
================================================
<?php namespace Iverberk\Larasearch;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Mockery as m;
function base_path($path = null)
{
return LarasearchServiceProviderTest::$functions->base_path($path);
}
/**
* Class LarasearchServiceProviderTest
*/
class LarasearchServiceProviderTest extends \PHPUnit_Framework_TestCase {
public static $functions;
protected static $providers_real_path;
protected function setup()
{
self::$functions = m::mock();
self::$functions->shouldReceive('base_path')->andReturn('');
self::$providers_real_path = realpath(__DIR__ . '/../../../src/Iverberk/Larasearch');
}
protected function tearDown()
{
m::close();
}
/**
* @test
*/
public function it_should_boot()
{
/**
* Set
*/
$sp = m::mock('Iverberk\Larasearch\LarasearchServiceProvider[bootContainerBindings, publishes]', ['something']);
$sp->shouldAllowMockingProtectedMethods();
/**
* Expectation
*/
$sp->shouldReceive('publishes')
->with([
self::$providers_real_path . '/../../config/larasearch.php' => base_path('config/larasearch.php'),
], 'config')
->once();
$sp->shouldReceive('bootContainerBindings')
->once();
/**
* Assertion
*/
$sp->boot();
}
/**
* @test
*/
public function it_should_boot_container_bindings()
{
/**
* Set
*/
$sp = m::mock('Iverberk\Larasearch\LarasearchServiceProvider[' .
'bindProxy, bindIndex, bindLogger, bindElasticsearch, bindQuery, bindResult]', ['something']);
$sp->shouldAllowMockingProtectedMethods();
/**
* Expectation
*/
$sp->shouldReceive('bindElasticsearch')->once()->andReturn(true);
$sp->shouldReceive('bindLogger')->once()->andReturn(true);
$sp->shouldReceive('bindProxy')->once()->andReturn(true);
$sp->shouldReceive('bindIndex')->once()->andReturn(true);
$sp->shouldReceive('bindQuery')->once()->andReturn(true);
$sp->shouldReceive('bindResult')->once()->andReturn(true);
/**
* Assertions
*/
$sp->bootContainerBindings();
}
/**
* @test
*/
public function it_should_bind_elasticsearch()
{
/**
* Set
*/
$app = m::mock('LaravelApp');
$sp = m::mock('Iverberk\Larasearch\LarasearchServiceProvider[bindElasticsearch]', [$app]);
/**
* Expectation
*/
Config::shouldReceive('get')
->with('larasearch.elasticsearch.params')
->once()
->andReturn([]);
$app->shouldReceive('singleton')
->once()
->andReturnUsing(
function ($name, $closure) use ($app)
{
$this->assertEquals('Elasticsearch', $name);
$this->assertInstanceOf('Elasticsearch\Client', $closure($app));
}
);
$sp->bindElasticsearch();
}
/**
* @test
*/
public function it_should_bind_logger()
{
/**
* Set
*/
$app = m::mock('LaravelApp');
$sp = m::mock('Iverberk\Larasearch\LarasearchServiceProvider[bindLogger]', [$app]);
/**
* Expectation
*/
$app->shouldReceive('singleton')
->once()
->andReturnUsing(
function ($name, $closure) use ($app)
{
$this->assertEquals('iverberk.larasearch.logger', $name);
$this->assertInstanceOf('Monolog\Logger', $closure($app));
}
);
$sp->bindLogger();
}
/**
* @test
*/
public function it_should_bind_index()
{
/**
* Set
*/
App::clearResolvedInstances();
Config::clearResolvedInstances();
App::shouldReceive('make')
->with('iverberk.larasearch.index', m::any())
->once()
->andReturn('mock');
App::shouldReceive('make')
->with('Elasticsearch')
->twice()
->andReturn('mock');
Config::shouldReceive('get')
->with('larasearch.elasticsearch.index_prefix', '')
->andReturn('');
$model = m::mock('Illuminate\Database\Eloquent\Model');
$model->shouldReceive('getTable')
->once()
->andReturn('mockType');
$app = m::mock('LaravelApp');
$proxy = m::mock('Iverberk\Larasearch\Proxy', [$model]);
$sp = m::mock('Iverberk\Larasearch\LarasearchServiceProvider[bindIndex]', [$app]);
/**
* Expectation
*/
$app->shouldReceive('bind')
->once()
->andReturnUsing(
function ($name, $closure) use ($app, $proxy)
{
$this->assertEquals('iverberk.larasearch.index', $name);
$this->assertInstanceOf('Iverberk\Larasearch\Index',
$closure($app, ['proxy' => $proxy, 'name' => 'name']));
}
);
/**
* Assertion
*/
$sp->bindIndex();
}
/**
* @test
*/
public function it_should_bind_query()
{
/**
* Set
*/
$model = m::mock('Illuminate\Database\Eloquent\Model');
$model->shouldReceive('getTable')
->once()
->andReturn('mockType');
$app = m::mock('LaravelApp');
$proxy = m::mock('Iverberk\Larasearch\Proxy', [$model]);
$sp = m::mock('Iverberk\Larasearch\LarasearchServiceProvider[bindQuery]', [$app]);
/**
* Expectation
*/
$app->shouldReceive('bind')
->once()
->andReturnUsing(
function ($name, $closure) use ($app, $proxy)
{
$this->assertEquals('iverberk.larasearch.query', $name);
$this->assertInstanceOf('Iverberk\Larasearch\Query',
$closure($app, ['proxy' => $proxy, 'term' => 'term', 'options' => []]));
}
);
/**
* Assertion
*/
$sp->bindQuery();
}
/**
* @test
*/
public function it_should_bind_proxy()
{
/**
* Set
*/
$model = m::mock('Illuminate\Database\Eloquent\Model');
$model->shouldReceive('getTable')
->once()
->andReturn('mockType');
$app = m::mock('LaravelApp');
$sp = m::mock('Iverberk\Larasearch\LarasearchServiceProvider[bindProxy]', [$app]);
/**
* Expectation
*/
$app->shouldReceive('bind')
->once()
->andReturnUsing(
function ($name, $closure) use ($app, $model)
{
$this->assertEquals('iverberk.larasearch.proxy', $name);
$this->assertInstanceOf('Iverberk\Larasearch\Proxy',
$closure($app, $model));
}
);
/**
* Assertion
*/
$sp->bindProxy();
}
/**
* @test
*/
public function it_should_bind_result()
{
/**
* Set
*/
$app = m::mock('LaravelApp');
$sp = m::mock('Iverberk\Larasearch\LarasearchServiceProvider[bindResult]', [$app]);
/**
* Expectation
*/
$app->shouldReceive('bind')
->once()
->andReturnUsing(
function ($name, $closure) use ($app)
{
$this->assertEquals('iverberk.larasearch.response.result', $name);
$this->assertInstanceOf('Iverberk\Larasearch\Response\Result',
$closure($app, []));
}
);
/**
* Assertion
*/
$sp->bindResult();
}
/**
* @test
*/
public function it_should_register_commands()
{
/**
* Set
*/
$app = m::mock('Illuminate\Container\Container');
$sp = m::mock('Iverberk\Larasearch\LarasearchServiceProvider[commands, mergeConfigFrom]', [$app]);
$sp->shouldAllowMockingProtectedMethods();
/**
* Expectation
*/
$app->shouldReceive('offsetSet')->andReturn(true);
$app->shouldReceive('offsetGet')->andReturn(true);
$app->shouldReceive('share')
->once()
->andReturnUsing(function ($closure) use ($app)
{
$this->assertInstanceOf('Iverberk\Larasearch\Commands\ReindexCommand', $closure($app));
});
$app->shouldReceive('share')
->once()
->andReturnUsing(function ($closure) use ($app)
{
$this->assertInstanceOf('Iverberk\Larasearch\Commands\PathsCommand', $closure($app));
});
$sp->shouldReceive('commands')
->with('iverberk.larasearch.commands.reindex')
->once()
->andReturn(true);
$sp->shouldReceive('commands')
->with('iverberk.larasearch.commands.paths')
->once()
->andReturn(true);
$sp->shouldReceive('mergeConfigFrom')
->with(self::$providers_real_path . '/../../config/larasearch.php', 'larasearch')
->once();
/**
* Assertion
*/
$sp->register();
}
/**
* @test
*/
public function it_should_provide_services()
{
/**
* Set
*/
$app = m::mock('LaravelApp');
/**
* Assertion
*/
$sp = new LarasearchServiceProvider($app);
$this->assertEquals([], $sp->provides());
}
}
================================================
FILE: tests/Iverberk/Larasearch/ObserverTest.php
================================================
<?php namespace Iverberk\Larasearch;
use Husband;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Facade;
use Illuminate\Support\Facades\Queue;
use Mockery as m;
use AspectMock\Test as am;
class ObserverTest extends \PHPUnit_Framework_TestCase {
protected function tearDown()
{
m::close();
am::clean();
}
/**
* @test
*/
public function it_should_not_reindex_on_model_save()
{
/**
*
* Expectation
*
*/
$queue = am::double('Illuminate\Support\Facades\Queue', ['push' => null]);
$husband = m::mock('Husband');
$husband->shouldReceive('shouldIndex')->andReturn(false);
/**
*
*
* Assertion
*
*/
with(new Observer)->saved($husband);
$queue->verifyNeverInvoked('push');
}
/**
* @test
*/
public function it_should_reindex_on_model_save()
{
/**
*
* Expectation
*
*/
Facade::clearResolvedInstances();
$proxy = m::mock('Iverberk\Larasearch\Proxy');
$proxy->shouldReceive('shouldIndex')->andReturn(true);
App::shouldReceive('make')
->with('iverberk.larasearch.proxy', m::type('Illuminate\Database\Eloquent\Model'))
->andReturn($proxy);
Config::shouldReceive('get')
->with('larasearch.reversedPaths.Husband', [])
->once()
->andReturn(['', 'wife', 'children', 'children.toys']);
Queue::shouldReceive('push')
->with('Iverberk\Larasearch\Jobs\ReindexJob', [
'Husband:2',
'Wife:2',
'Child:2',
'Toy:2'
])->once();
/**
*
*
* Assertion
*
*/
$husband = \Husband::find(2);
$husband->clearProxy();
with(new Observer)->saved($husband);
/**
*
* Expectation
*
*/
Facade::clearResolvedInstances();
$proxy = m::mock('Iverberk\Larasearch\Proxy');
$proxy->shouldReceive('shouldIndex')->andReturn(true);
App::shouldReceive('make')
->with('iverberk.larasearch.proxy', m::type('Illuminate\Database\Eloquent\Model'))
->andReturn($proxy);
Config::shouldReceive('get')
->with('larasearch.reversedPaths.Toy', [])
->once()
->andReturn(['', 'children', 'children.mother.husband', 'children.mother']);
Queue::shouldReceive('push')
->with('Iverberk\Larasearch\Jobs\ReindexJob', [
'Toy:2',
'Child:8',
'Child:2',
'Husband:8',
'Husband:2',
'Wife:8',
'Wife:2'
])->once();
/**
*
*
* Assertion
*
*/
$toy = \Toy::find(2);
with(new Observer)->saved($toy);
}
/**
* @test
*/
public function it_should_reindex_on_model_delete()
{
/**
*
* Expectation
*
*/
Facade::clearResolvedInstances();
Queue::shouldReceive('push')
->with('Iverberk\Larasearch\Jobs\DeleteJob', ['Husband:2'])
->once();
Queue::shouldReceive('push')
->with('Iverberk\Larasearch\Jobs\ReindexJob', ['Wife:2', 'Child:2', 'Toy:2'])
->once();
Config::shouldReceive('get')
->with('/^larasearch.reversedPaths\..*$/', [])
->once()
->andReturn(['', 'wife', 'children', 'children.toys']);
$husband = \Husband::find(2);
with(new Observer)->deleted($husband);
}
}
================================================
FILE: tests/Iverberk/Larasearch/ProxyTest.php
================================================
<?php namespace Iverberk\Larasearch;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Facade;
use Mockery as m;
use AspectMock\Test as am;
function date()
{
return ProxyTest::$functions->date();
}
class ProxyTest extends \PHPUnit_Framework_TestCase {
/**
* @var \Mockery\Mock
*/
private $proxy;
/**
* @var \Mockery\Mock
*/
private $model;
/**
* @var \Mockery\Mock
*/
private $index;
/**
* @var \Mockery\Mock
*/
private $client;
/**
* @var \Mockery\Mock
*/
public static $functions;
protected function setUp()
{
parent::setUp();
self::$functions = m::mock();
$this->index = m::mock('Iverberk\Larasearch\Index');
$this->model = m::mock('Husband')->makePartial();
gitextract_74xw7pf5/
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── composer.json
├── phpunit.xml
├── src/
│ ├── Iverberk/
│ │ └── Larasearch/
│ │ ├── Commands/
│ │ │ ├── PathsCommand.php
│ │ │ └── ReindexCommand.php
│ │ ├── Exceptions/
│ │ │ └── ImportException.php
│ │ ├── Index.php
│ │ ├── Jobs/
│ │ │ ├── DeleteJob.php
│ │ │ └── ReindexJob.php
│ │ ├── LarasearchServiceProvider.php
│ │ ├── Observer.php
│ │ ├── Proxy.php
│ │ ├── Query.php
│ │ ├── Response/
│ │ │ ├── Records.php
│ │ │ ├── Result.php
│ │ │ └── Results.php
│ │ ├── Response.php
│ │ ├── Traits/
│ │ │ ├── CallableTrait.php
│ │ │ ├── SearchableTrait.php
│ │ │ └── TransformableTrait.php
│ │ └── Utils.php
│ └── config/
│ └── larasearch.php
└── tests/
├── Iverberk/
│ └── Larasearch/
│ ├── Commands/
│ │ ├── PathsCommandTest.php
│ │ └── ReindexCommandTest.php
│ ├── IndexTest.php
│ ├── Jobs/
│ │ ├── DeleteJobTest.php
│ │ └── ReindexJobTest.php
│ ├── LarasearchServiceProviderTest.php
│ ├── ObserverTest.php
│ ├── ProxyTest.php
│ ├── QueryTest.php
│ ├── Response/
│ │ ├── RecordsTest.php
│ │ ├── ResultTest.php
│ │ └── ResultsTest.php
│ ├── ResponseTest.php
│ ├── Traits/
│ │ ├── CallableTraitTest.php
│ │ ├── SearchableTraitTest.php
│ │ └── TransformableTraitTest.php
│ └── UtilsTest.php
├── Support/
│ ├── Dummy.php
│ └── Stubs/
│ ├── Child.php
│ ├── Foo/
│ │ └── Bar.php
│ ├── Husband.php
│ ├── NamespaceDummy.php
│ ├── Toy.php
│ └── Wife.php
└── bootstrap.php
SYMBOL INDEX (329 symbols across 42 files)
FILE: src/Iverberk/Larasearch/Commands/PathsCommand.php
class PathsCommand (line 10) | class PathsCommand extends Command {
method fire (line 53) | public function fire()
method getPaths (line 85) | public function getPaths()
method getReversedPaths (line 93) | public function getReversedPaths()
method getArguments (line 103) | protected function getArguments()
method getOptions (line 115) | protected function getOptions()
method compilePaths (line 136) | protected function compilePaths(Model $model, $ancestor = null, $path ...
method checkDocHints (line 222) | protected function checkDocHints($docComment, $model)
method getRelatedModels (line 248) | protected function getRelatedModels(Model $model)
method writeConfig (line 304) | private function writeConfig()
FILE: src/Iverberk/Larasearch/Commands/ReindexCommand.php
class ReindexCommand (line 9) | class ReindexCommand extends Command {
method fire (line 30) | public function fire()
method getArguments (line 63) | protected function getArguments()
method getOptions (line 75) | protected function getOptions()
method reindexModel (line 91) | protected function reindexModel(Model $model)
method getModelInstance (line 114) | protected function getModelInstance($model)
FILE: src/Iverberk/Larasearch/Exceptions/ImportException.php
class ImportException (line 5) | class ImportException extends Exception {
method __construct (line 8) | public function __construct($message, $code = 0, $errorItems = [])
FILE: src/Iverberk/Larasearch/Index.php
class Index (line 9) | class Index {
method getClient (line 44) | private static function getClient()
method __construct (line 54) | public function __construct(Proxy $proxy, $name = '')
method import (line 71) | public function import(Model $model, $relations = [], $batchSize = 750...
method setName (line 121) | public function setName($name)
method getName (line 136) | public function getName()
method setProxy (line 148) | public function setProxy(Proxy $proxy)
method getProxy (line 160) | public function getProxy()
method create (line 170) | public function create($options = [])
method delete (line 180) | public function delete()
method exists (line 190) | public function exists()
method aliasExists (line 201) | public function aliasExists($alias)
method store (line 214) | public function store($record)
method retrieve (line 229) | public function retrieve($record)
method remove (line 243) | public function remove($record)
method tokens (line 258) | public function tokens($text, $options = [])
method getParams (line 266) | public function getParams()
method setParams (line 274) | public function setParams($params)
method bulk (line 283) | public function bulk($records)
method clean (line 312) | public static function clean($name)
method getAlias (line 333) | public static function getAlias($name)
method updateAliases (line 345) | public static function updateAliases(array $actions)
method refresh (line 366) | public static function refresh($index)
method getDefaultIndexParams (line 379) | private function getDefaultIndexParams()
method getNestedFieldMapping (line 468) | private function getNestedFieldMapping($fieldName, $fieldMapping, $pat...
FILE: src/Iverberk/Larasearch/Jobs/DeleteJob.php
class DeleteJob (line 12) | class DeleteJob {
method __construct (line 28) | public function __construct(Application $app, Config $config)
method fire (line 38) | public function fire(Job $job, $models)
FILE: src/Iverberk/Larasearch/Jobs/ReindexJob.php
class ReindexJob (line 13) | class ReindexJob {
method __construct (line 29) | public function __construct(Application $app, Repository $config)
method fire (line 35) | public function fire(Job $job, $models)
FILE: src/Iverberk/Larasearch/LarasearchServiceProvider.php
class LarasearchServiceProvider (line 11) | class LarasearchServiceProvider extends ServiceProvider
method boot (line 21) | public function boot()
method register (line 35) | public function register()
method bootContainerBindings (line 54) | public function bootContainerBindings()
method bindLogger (line 67) | protected function bindLogger()
method bindElasticsearch (line 78) | protected function bindElasticsearch()
method bindIndex (line 89) | protected function bindIndex()
method bindQuery (line 102) | protected function bindQuery()
method bindProxy (line 113) | protected function bindProxy()
method bindResult (line 124) | protected function bindResult()
method registerCommands (line 137) | protected function registerCommands()
method provides (line 158) | public function provides()
FILE: src/Iverberk/Larasearch/Observer.php
class Observer (line 8) | class Observer {
method deleted (line 15) | public function deleted(Model $model)
method saved (line 29) | public function saved(Model $model)
method findAffectedModels (line 43) | private function findAffectedModels(Model $model, $excludeCurrent = fa...
FILE: src/Iverberk/Larasearch/Proxy.php
class Proxy (line 7) | class Proxy {
method __construct (line 19) | public function __construct(Model $model)
method getConfig (line 35) | public function getConfig()
method getModel (line 43) | public function getModel()
method getIndex (line 51) | public function getIndex()
method getType (line 59) | public function getType()
method getClient (line 67) | public function getClient()
method search (line 77) | public function search($term, $options = [])
method searchByQuery (line 89) | public function searchByQuery($query, $options = [])
method searchById (line 102) | public function searchById($id)
method reindex (line 122) | public function reindex($relations = false, $batchSize = 750, $mapping...
method shouldIndex (line 189) | public function shouldIndex()
method refreshDoc (line 197) | public function refreshDoc($model)
method deleteDoc (line 214) | public function deleteDoc($id)
method enableIndexing (line 228) | public function enableIndexing()
method disableIndexing (line 238) | public function disableIndexing()
FILE: src/Iverberk/Larasearch/Query.php
class Query (line 5) | class Query {
method __construct (line 42) | public function __construct(Proxy $proxy, $term, $options = [])
method getAggregations (line 52) | private function getAggregations()
method getFields (line 71) | private function getFields()
method getPagination (line 120) | private function getPagination()
method getHighlight (line 135) | private function getHighlight()
method getSuggest (line 155) | private function getSuggest()
method getSort (line 181) | private function getSort()
method getPayload (line 192) | private function getPayload()
method execute (line 307) | public function execute()
FILE: src/Iverberk/Larasearch/Response.php
class Response (line 6) | class Response {
method __construct (line 24) | public function __construct(Model $model, Array $response)
method getModel (line 33) | public function getModel()
method getResponse (line 41) | public function getResponse()
method getResults (line 49) | public function getResults()
method getRecords (line 57) | public function getRecords()
method getTook (line 76) | public function getTook()
method getHits (line 84) | public function getHits()
method getTimedOut (line 92) | public function getTimedOut()
method getShards (line 100) | public function getShards()
method getMaxScore (line 108) | public function getMaxScore()
method getTotal (line 116) | public function getTotal()
method getSuggestions (line 125) | public function getSuggestions($fields = [])
method getAggregations (line 152) | public function getAggregations($name = '')
FILE: src/Iverberk/Larasearch/Response/Records.php
class Records (line 6) | class Records extends Collection {
method __construct (line 21) | public function __construct(Response $response)
FILE: src/Iverberk/Larasearch/Response/Result.php
class Result (line 5) | class Result implements \ArrayAccess, Arrayable {
method __construct (line 21) | public function __construct(array $hit)
method getId (line 32) | public function getId()
method getType (line 43) | public function getType()
method getIndex (line 54) | public function getIndex()
method getScore (line 65) | public function getScore()
method getSource (line 76) | public function getSource()
method getFields (line 85) | public function getFields($fields = [])
method getHit (line 102) | public function getHit()
method getHighlights (line 111) | public function getHighlights($fields = [])
method __get (line 141) | public function __get($key)
method offsetExists (line 156) | public function offsetExists($offset)
method offsetGet (line 169) | public function offsetGet($offset)
method offsetSet (line 182) | public function offsetSet($offset, $value)
method offsetUnset (line 194) | public function offsetUnset($offset)
method getPath (line 207) | private function getPath($offset)
method toArray (line 217) | public function toArray()
FILE: src/Iverberk/Larasearch/Response/Results.php
class Results (line 6) | class Results extends Collection {
method __construct (line 21) | public function __construct(Response $response)
FILE: src/Iverberk/Larasearch/Traits/CallableTrait.php
type CallableTrait (line 6) | trait CallableTrait {
method bootCallableTrait (line 11) | public static function bootCallableTrait()
FILE: src/Iverberk/Larasearch/Traits/SearchableTrait.php
type SearchableTrait (line 6) | trait SearchableTrait {
method getProxy (line 38) | public static function getProxy()
method clearProxy (line 61) | public static function clearProxy()
method __call (line 73) | public function __call($method, $parameters)
method __callStatic (line 92) | public static function __callStatic($method, $parameters)
method getEsId (line 109) | public function getEsId()
FILE: src/Iverberk/Larasearch/Traits/TransformableTrait.php
type TransformableTrait (line 5) | trait TransformableTrait {
method transform (line 13) | public function transform($relations = false)
FILE: src/Iverberk/Larasearch/Utils.php
class Utils (line 11) | class Utils {
method findKey (line 22) | public static function findKey($params, $arg, $default = null)
method array_merge_recursive_distinct (line 49) | public static function array_merge_recursive_distinct(array $array1, a...
method findSearchableModels (line 67) | public static function findSearchableModels($directories)
FILE: tests/Iverberk/Larasearch/Commands/PathsCommandTest.php
function app_path (line 11) | function app_path()
function constant (line 16) | function constant($const)
function base_path (line 21) | function base_path()
class PathsCommandTest (line 31) | class PathsCommandTest extends \PHPUnit_Framework_TestCase {
method setUp (line 41) | public function setUp()
method tearDown (line 51) | protected function tearDown()
method it_should_get_options (line 59) | public function it_should_get_options()
method it_should_get_arguments (line 84) | public function it_should_get_arguments()
method it_should_fire_with_models_and_config (line 107) | public function it_should_fire_with_models_and_config()
method it_should_fire_without_models (line 204) | public function it_should_fire_without_models()
method it_should_fire_without_config (line 257) | public function it_should_fire_without_config()
method it_should_fire_with_laravel_and_config_confirmed (line 303) | public function it_should_fire_with_laravel_and_config_confirmed()
method it_should_fire_with_config_not_confirmed (line 364) | public function it_should_fire_with_config_not_confirmed()
FILE: tests/Iverberk/Larasearch/Commands/ReindexCommandTest.php
class ReindexCommandTest (line 6) | class ReindexCommandTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 11) | protected function tearDown()
method it_should_get_options (line 19) | public function it_should_get_options()
method it_should_get_arguments (line 46) | public function it_should_get_arguments()
method it_should_fire_without_models (line 69) | public function it_should_fire_without_models()
method it_should_fire_with_models (line 109) | public function it_should_fire_with_models()
method it_should_get_a_model_instance (line 175) | public function it_should_get_a_model_instance()
FILE: tests/Iverberk/Larasearch/IndexTest.php
class IndexTest (line 9) | class IndexTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 11) | protected function tearDown()
method it_should_import (line 20) | public function it_should_import()
method it_should_set_name (line 70) | public function it_should_set_name()
method it_should_only_prepend_prefix_once (line 92) | public function it_should_only_prepend_prefix_once()
method it_should_get_name (line 112) | public function it_should_get_name()
method it_should_create_an_index (line 133) | public function it_should_create_an_index()
method it_should_create_an_index_with_a_prefix (line 627) | public function it_should_create_an_index_with_a_prefix()
method it_should_delete_an_index (line 1122) | public function it_should_delete_an_index()
method it_should_delete_an_index_with_a_prefix (line 1154) | public function it_should_delete_an_index_with_a_prefix()
method it_should_check_that_an_index_exists (line 1186) | public function it_should_check_that_an_index_exists()
method it_should_check_that_an_index_exists_with_a_prefix (line 1218) | public function it_should_check_that_an_index_exists_with_a_prefix()
method it_should_check_that_an_alias_exists (line 1250) | public function it_should_check_that_an_alias_exists()
method it_should_check_that_an_alias_exists_with_a_prefix (line 1282) | public function it_should_check_that_an_alias_exists_with_a_prefix()
method it_should_store_a_record (line 1316) | public function it_should_store_a_record()
method it_should_store_a_record_with_an_index_prefix (line 1357) | public function it_should_store_a_record_with_an_index_prefix()
method it_should_retrieve_a_record (line 1404) | public function it_should_retrieve_a_record()
method it_should_retrieve_a_record_iwth_an_index_prefix (line 1444) | public function it_should_retrieve_a_record_iwth_an_index_prefix()
method it_should_remove_a_record (line 1491) | public function it_should_remove_a_record()
method it_should_remove_a_record_with_an_index_prefix (line 1530) | public function it_should_remove_a_record_with_an_index_prefix()
method it_should_inspect_tokens (line 1575) | public function it_should_inspect_tokens()
method it_should_inspect_tokens_with_an_index_prefix (line 1615) | public function it_should_inspect_tokens_with_an_index_prefix()
method it_should_get_and_set_params (line 1661) | public function it_should_get_and_set_params()
method it_should_store_a_records_in_bulk_with_errors (line 1681) | public function it_should_store_a_records_in_bulk_with_errors()
method it_should_store_records_having_prefix_in_bulk_with_errors (line 1729) | public function it_should_store_records_having_prefix_in_bulk_with_err...
method it_should_store_records_having_explicit_prefix_in_bulk_with_errors (line 1779) | public function it_should_store_records_having_explicit_prefix_in_bulk...
method it_should_store_a_records_in_bulk_without_errors (line 1827) | public function it_should_store_a_records_in_bulk_without_errors()
method it_should_store_a_records_having_index_prefix_in_bulk_without_errors (line 1867) | public function it_should_store_a_records_having_index_prefix_in_bulk_...
method it_should_clean_old_indices (line 1910) | public function it_should_clean_old_indices()
method it_should_clean_old_indices_with_index_prefix (line 1953) | public function it_should_clean_old_indices_with_index_prefix()
method it_should_update_aliases (line 1999) | public function it_should_update_aliases()
method it_should_update_aliases_with_index_prefix (line 2035) | public function it_should_update_aliases_with_index_prefix()
method it_should_get_aliases (line 2073) | public function it_should_get_aliases()
method it_should_get_aliases_with_an_index_prefix (line 2109) | public function it_should_get_aliases_with_an_index_prefix()
method it_should_refresh (line 2147) | public function it_should_refresh()
method it_should_refresh_with_an_index_prefix (line 2183) | public function it_should_refresh_with_an_index_prefix()
method getMocks (line 2223) | private function getMocks($index_prefix = '')
FILE: tests/Iverberk/Larasearch/Jobs/DeleteJobTest.php
class DeleteJobTest (line 6) | class DeleteJobTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 8) | protected function tearDown()
method it_should_fire_job (line 17) | public function it_should_fire_job()
FILE: tests/Iverberk/Larasearch/Jobs/ReindexJobTest.php
class ReindexJobTest (line 8) | class ReindexJobTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 10) | protected function tearDown()
method it_should_fire_job_with_unresolvable_models (line 19) | public function it_should_fire_job_with_unresolvable_models()
method it_should_fire_job_with_resolvable_models (line 62) | public function it_should_fire_job_with_resolvable_models()
FILE: tests/Iverberk/Larasearch/LarasearchServiceProviderTest.php
function base_path (line 7) | function base_path($path = null)
class LarasearchServiceProviderTest (line 15) | class LarasearchServiceProviderTest extends \PHPUnit_Framework_TestCase {
method setup (line 20) | protected function setup()
method tearDown (line 27) | protected function tearDown()
method it_should_boot (line 35) | public function it_should_boot()
method it_should_boot_container_bindings (line 64) | public function it_should_boot_container_bindings()
method it_should_bind_elasticsearch (line 92) | public function it_should_bind_elasticsearch()
method it_should_bind_logger (line 124) | public function it_should_bind_logger()
method it_should_bind_index (line 151) | public function it_should_bind_index()
method it_should_bind_query (line 205) | public function it_should_bind_query()
method it_should_bind_proxy (line 241) | public function it_should_bind_proxy()
method it_should_bind_result (line 277) | public function it_should_bind_result()
method it_should_register_commands (line 308) | public function it_should_register_commands()
method it_should_provide_services (line 360) | public function it_should_provide_services()
FILE: tests/Iverberk/Larasearch/ObserverTest.php
class ObserverTest (line 11) | class ObserverTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 13) | protected function tearDown()
method it_should_not_reindex_on_model_save (line 22) | public function it_should_not_reindex_on_model_save()
method it_should_reindex_on_model_save (line 48) | public function it_should_reindex_on_model_save()
method it_should_reindex_on_model_delete (line 132) | public function it_should_reindex_on_model_delete()
FILE: tests/Iverberk/Larasearch/ProxyTest.php
function date (line 8) | function date()
class ProxyTest (line 13) | class ProxyTest extends \PHPUnit_Framework_TestCase {
method setUp (line 40) | protected function setUp()
method tearDown (line 70) | protected function tearDown()
method it_can_get_config (line 79) | public function it_can_get_config()
method it_can_get_model (line 101) | public function it_can_get_model()
method it_can_get_index (line 109) | public function it_can_get_index()
method it_can_get_type (line 117) | public function it_can_get_type()
method it_can_get_client (line 125) | public function it_can_get_client()
method it_can_search (line 133) | public function it_can_search()
method it_can_search_with_a_query (line 167) | public function it_can_search_with_a_query()
method it_can_search_for_a_single_document (line 208) | public function it_can_search_for_a_single_document()
method it_can_reindex_when_alias_does_not_exist (line 245) | public function it_can_reindex_when_alias_does_not_exist()
method it_can_reindex_when_alias_exists (line 286) | public function it_can_reindex_when_alias_exists()
method it_should_index (line 348) | public function it_should_index()
method it_should_refresh_docs (line 356) | public function it_should_refresh_docs()
method it_should_delete_docs (line 393) | public function it_should_delete_docs()
method it_should_enable_indexing_globally (line 422) | public function it_should_enable_indexing_globally()
method it_should_disable_indexing_globally (line 435) | public function it_should_disable_indexing_globally()
FILE: tests/Iverberk/Larasearch/QueryTest.php
class QueryTest (line 6) | class QueryTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 8) | protected function tearDown()
method it_should_search_with_term (line 17) | public function it_should_search_with_term()
method it_should_search_on_term_with_exact_field (line 92) | public function it_should_search_on_term_with_exact_field()
method it_should_search_with_term_and_misspellings (line 163) | public function it_should_search_with_term_and_misspellings()
method it_should_search_on_fields_with_term (line 267) | public function it_should_search_on_fields_with_term()
method it_should_search_on_term_with_autocomplete (line 358) | public function it_should_search_on_term_with_autocomplete()
method it_should_search_on_fields_with_term_and_autocomplete (line 423) | public function it_should_search_on_fields_with_term_and_autocomplete()
method it_should_search_on_fields_with_term_and_select (line 488) | public function it_should_search_on_fields_with_term_and_select()
method it_should_search_on_fields_with_term_and_load (line 573) | public function it_should_search_on_fields_with_term_and_load()
method it_should_search_on_fields_and_highlight (line 658) | public function it_should_search_on_fields_and_highlight()
method it_should_search_on_fields_with_suggestions (line 757) | public function it_should_search_on_fields_with_suggestions()
method it_should_search_with_aggregations (line 846) | public function it_should_search_with_aggregations()
method it_should_search_with_sort (line 918) | public function it_should_search_with_sort()
method it_should_throw_an_exception_when_multiple_queries_are_provided (line 988) | public function it_should_throw_an_exception_when_multiple_queries_are...
method getMocks (line 1021) | private function getMocks()
FILE: tests/Iverberk/Larasearch/Response/RecordsTest.php
class RecordsTest (line 5) | class RecordsTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 7) | protected function tearDown()
method it_should_construct (line 15) | public function it_should_construct()
FILE: tests/Iverberk/Larasearch/Response/ResultTest.php
class ResultTest (line 5) | class ResultTest extends \PHPUnit_Framework_TestCase {
method setUp (line 16) | protected function setUp()
method tearDown (line 45) | protected function tearDown()
method it_should_get_id (line 53) | public function it_should_get_id()
method it_should_get_type (line 61) | public function it_should_get_type()
method it_should_get_index (line 69) | public function it_should_get_index()
method it_should_get_score (line 77) | public function it_should_get_score()
method it_should_get_source (line 85) | public function it_should_get_source()
method it_should_get_fields (line 93) | public function it_should_get_fields()
method it_should_get_hit (line 103) | public function it_should_get_hit()
method it_should_get_highlights (line 111) | public function it_should_get_highlights()
method it_should_get_attributes_from_hit (line 121) | public function it_should_get_attributes_from_hit()
method it_should_convert_to_array (line 132) | public function it_should_convert_to_array()
method it_should_cover_hundred_procent (line 150) | public function it_should_cover_hundred_procent()
FILE: tests/Iverberk/Larasearch/Response/ResultsTest.php
class ResultsTest (line 5) | class ResultsTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 7) | protected function tearDown()
method it_should_construct (line 15) | public function it_should_construct()
FILE: tests/Iverberk/Larasearch/ResponseTest.php
class ResponseTest (line 5) | class ResponseTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 27) | protected function tearDown()
method it_should_get_model (line 35) | public function it_should_get_model()
method it_should_get_response (line 55) | public function it_should_get_response()
method it_should_get_results (line 77) | public function it_should_get_results()
method it_should_get_records (line 100) | public function it_should_get_records()
method it_should_get_took (line 133) | public function it_should_get_took()
method it_should_get_hits (line 153) | public function it_should_get_hits()
method it_should_get_timed_out (line 173) | public function it_should_get_timed_out()
method it_should_get_shards (line 193) | public function it_should_get_shards()
method it_should_get_max_score (line 213) | public function it_should_get_max_score()
method it_should_get_total (line 233) | public function it_should_get_total()
method it_should_get_suggestions_with_fields (line 253) | public function it_should_get_suggestions_with_fields()
method it_should_get_suggestions_without_fields (line 275) | public function it_should_get_suggestions_without_fields()
method it_should_get_aggregations_with_name (line 297) | public function it_should_get_aggregations_with_name()
method it_should_get_aggregations_without_name (line 319) | public function it_should_get_aggregations_without_name()
method getMocks (line 344) | private function getMocks()
FILE: tests/Iverberk/Larasearch/Traits/CallableTraitTest.php
class CallableTraitTest (line 6) | class CallableTraitTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 8) | protected function tearDown()
method it_should_boot_callback_trait_and_register_observer (line 17) | public function it_should_boot_callback_trait_and_register_observer()
method it_should_boot_callback_trait_and_throw_exception (line 30) | public function it_should_boot_callback_trait_and_throw_exception()
FILE: tests/Iverberk/Larasearch/Traits/SearchableTraitTest.php
class SearchableTraitTest (line 10) | class SearchableTraitTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 12) | protected function tearDown()
method it_should_get_a_proxy (line 21) | public function it_should_get_a_proxy()
method it_should_throw_an_exception_if_included_in_a_non_eloquent_model (line 61) | public function it_should_throw_an_exception_if_included_in_a_non_eloq...
method it_should_call_methods_on_the_proxy (line 74) | public function it_should_call_methods_on_the_proxy()
method it_should_not_call_methods_on_the_proxy (line 119) | public function it_should_not_call_methods_on_the_proxy()
method it_should_get_elasticsearch_id (line 145) | public function it_should_get_elasticsearch_id()
FILE: tests/Iverberk/Larasearch/Traits/TransformableTraitTest.php
class TransformableTraitTest (line 7) | class TransformableTraitTest extends \PHPUnit_Framework_TestCase {
method tearDown (line 9) | protected function tearDown()
method it_should_transform (line 17) | public function it_should_transform()
FILE: tests/Iverberk/Larasearch/UtilsTest.php
class UtilsTest (line 4) | class UtilsTest extends \PHPUnit_Framework_TestCase {
method testThatKeysCanBeFoundInAnArray (line 6) | public function testThatKeysCanBeFoundInAnArray()
method testThatArraysAreMergedRecursivelyByOverwritingCommonKeys (line 22) | public function testThatArraysAreMergedRecursivelyByOverwritingCommonK...
method testThatSearchableModelsAreFoundInDirectories (line 58) | public function testThatSearchableModelsAreFoundInDirectories()
FILE: tests/Support/Dummy.php
class Dummy (line 5) | class Dummy {
FILE: tests/Support/Stubs/Child.php
class Child (line 5) | class Child extends Illuminate\Database\Eloquent\Model {
method mother (line 14) | public function mother()
method father (line 25) | public function father()
method toys (line 33) | public function toys()
FILE: tests/Support/Stubs/Foo/Bar.php
class Item (line 5) | class Item extends \Illuminate\Database\Eloquent\Model {
FILE: tests/Support/Stubs/Husband.php
class Husband (line 5) | class Husband extends Illuminate\Database\Eloquent\Model {
method wife (line 29) | public function wife()
method children (line 39) | public function children()
method getEsId (line 44) | public function getEsId()
FILE: tests/Support/Stubs/NamespaceDummy.php
class NamespaceDummy (line 3) | class NamespaceDummy {
FILE: tests/Support/Stubs/Toy.php
class Toy (line 5) | class Toy extends Illuminate\Database\Eloquent\Model {
method children (line 12) | public function children()
FILE: tests/Support/Stubs/Wife.php
class Wife (line 5) | class Wife extends Illuminate\Database\Eloquent\Model {
method husband (line 15) | public function husband()
method children (line 23) | public function children()
Condensed preview — 50 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (276K chars).
[
{
"path": ".gitignore",
"chars": 96,
"preview": "/vendor\ncomposer.phar\ncomposer.lock\n.DS_Store\n\ntests/coverage/*\n.idea/\natlassian-ide-plugin.xml\n"
},
{
"path": ".travis.yml",
"chars": 179,
"preview": "language: php\n\nphp:\n - 5.3\n - 5.4\n - 5.5\n - 5.6\n - hhvm\n\nbefore_script:\n - composer self-update\n - composer insta"
},
{
"path": "LICENSE",
"chars": 1078,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Ivo Verberk\n\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "README.md",
"chars": 1682,
"preview": "Introduction\n------------\n\nLarasearch is a Laravel package that aims to seamlessly integrate Elasticsearch functionality"
},
{
"path": "composer.json",
"chars": 895,
"preview": "{\n \"name\": \"iverberk/larasearch\",\n \"description\": \"Elasticsearch enabled Eloquent models\",\n \"keywords\": [\"searc"
},
{
"path": "phpunit.xml",
"chars": 753,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit backupGlobals=\"false\"\n backupStaticAttributes=\"false\"\n b"
},
{
"path": "src/Iverberk/Larasearch/Commands/PathsCommand.php",
"chars": 11079,
"preview": "<?php namespace Iverberk\\Larasearch\\Commands;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Database\\Eloquent\\Model;\nu"
},
{
"path": "src/Iverberk/Larasearch/Commands/ReindexCommand.php",
"chars": 3208,
"preview": "<?php namespace Iverberk\\Larasearch\\Commands;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Database\\Eloquent\\Model;\nu"
},
{
"path": "src/Iverberk/Larasearch/Exceptions/ImportException.php",
"chars": 349,
"preview": "<?php namespace Iverberk\\Larasearch\\Exceptions;\n\nuse Exception;\n\nclass ImportException extends Exception {\n\n // Redef"
},
{
"path": "src/Iverberk/Larasearch/Index.php",
"chars": 12767,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\App;\nuse Il"
},
{
"path": "src/Iverberk/Larasearch/Jobs/DeleteJob.php",
"chars": 1138,
"preview": "<?php namespace Iverberk\\Larasearch\\Jobs;\n\nuse Iverberk\\Larasearch\\Config;\nuse Illuminate\\Foundation\\Application;\nuse Il"
},
{
"path": "src/Iverberk/Larasearch/Jobs/ReindexJob.php",
"chars": 1324,
"preview": "<?php namespace Iverberk\\Larasearch\\Jobs;\n\nuse Illuminate\\Config\\Repository;\nuse Illuminate\\Foundation\\Application;\nuse "
},
{
"path": "src/Iverberk/Larasearch/LarasearchServiceProvider.php",
"chars": 3963,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Elasticsearch\\Client;\nuse Illuminate\\Support\\ServiceProvider;\nuse Iverberk\\Lar"
},
{
"path": "src/Iverberk/Larasearch/Observer.php",
"chars": 3705,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Collection;\nuse Ill"
},
{
"path": "src/Iverberk/Larasearch/Proxy.php",
"chars": 6041,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\App;\nuse Il"
},
{
"path": "src/Iverberk/Larasearch/Query.php",
"chars": 10104,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse stdClass;\n\nclass Query {\n\n /**\n * @var Proxy\n */\n private $proxy"
},
{
"path": "src/Iverberk/Larasearch/Response/Records.php",
"chars": 792,
"preview": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Illuminate\\Support\\Collection;\nuse Iverberk\\Larasearch\\Response;\n\ncla"
},
{
"path": "src/Iverberk/Larasearch/Response/Result.php",
"chars": 4563,
"preview": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Illuminate\\Contracts\\Support\\Arrayable;\n\nclass Result implements \\Arr"
},
{
"path": "src/Iverberk/Larasearch/Response/Results.php",
"chars": 790,
"preview": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Illuminate\\Support\\Collection;\nuse Iverberk\\Larasearch\\Response;\n\ncla"
},
{
"path": "src/Iverberk/Larasearch/Response.php",
"chars": 3041,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Iverberk\\Larasearch\\Response\\Results;\n"
},
{
"path": "src/Iverberk/Larasearch/Traits/CallableTrait.php",
"chars": 510,
"preview": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Iverberk\\Larasearch\\Observer;\n\n"
},
{
"path": "src/Iverberk/Larasearch/Traits/SearchableTrait.php",
"chars": 2571,
"preview": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\App;"
},
{
"path": "src/Iverberk/Larasearch/Traits/TransformableTrait.php",
"chars": 500,
"preview": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Illuminate\\Support\\Facades\\Config;\n\ntrait TransformableTrait {\n\n /**"
},
{
"path": "src/Iverberk/Larasearch/Utils.php",
"chars": 3266,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse PHPParser_Parser;\nuse PHPParser_Lexer;\nuse PHPParser_Node_Stmt_Namespace;\nUse "
},
{
"path": "src/config/larasearch.php",
"chars": 10189,
"preview": "<?php\n\nuse Psr\\Log\\LogLevel;\n\n$compiled = __DIR__ . '/paths.json';\n\n// Check for a json file that contains the compiled "
},
{
"path": "tests/Iverberk/Larasearch/Commands/PathsCommandTest.php",
"chars": 10164,
"preview": "<?php namespace Iverberk\\Larasearch\\Commands;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\File;\n"
},
{
"path": "tests/Iverberk/Larasearch/Commands/ReindexCommandTest.php",
"chars": 4617,
"preview": "<?php namespace Iverberk\\Larasearch\\Commands;\n\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Mockery as m;\n\nclass"
},
{
"path": "tests/Iverberk/Larasearch/IndexTest.php",
"chars": 77072,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Facade;\nuse Ill"
},
{
"path": "tests/Iverberk/Larasearch/Jobs/DeleteJobTest.php",
"chars": 1265,
"preview": "<?php namespace Iverberk\\Larasearch\\Jobs;\n\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nclass DeleteJobTest extends \\PH"
},
{
"path": "tests/Iverberk/Larasearch/Jobs/ReindexJobTest.php",
"chars": 2801,
"preview": "<?php namespace Iverberk\\Larasearch\\Jobs;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Mockery as m;\nuse AspectMock\\Test as "
},
{
"path": "tests/Iverberk/Larasearch/LarasearchServiceProviderTest.php",
"chars": 10044,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Config;\nuse Moc"
},
{
"path": "tests/Iverberk/Larasearch/ObserverTest.php",
"chars": 3846,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Husband;\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Co"
},
{
"path": "tests/Iverberk/Larasearch/ProxyTest.php",
"chars": 10301,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Facade;\nuse Moc"
},
{
"path": "tests/Iverberk/Larasearch/QueryTest.php",
"chars": 31173,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nclass QueryTest extends \\PHPUnit_Fra"
},
{
"path": "tests/Iverberk/Larasearch/Response/RecordsTest.php",
"chars": 1392,
"preview": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Mockery as m;\n\nclass RecordsTest extends \\PHPUnit_Framework_TestCase "
},
{
"path": "tests/Iverberk/Larasearch/Response/ResultTest.php",
"chars": 3657,
"preview": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Mockery as m;\n\nclass ResultTest extends \\PHPUnit_Framework_TestCase {"
},
{
"path": "tests/Iverberk/Larasearch/Response/ResultsTest.php",
"chars": 1385,
"preview": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Mockery as m;\n\nclass ResultsTest extends \\PHPUnit_Framework_TestCase "
},
{
"path": "tests/Iverberk/Larasearch/ResponseTest.php",
"chars": 6430,
"preview": "<?php namespace Iverberk\\Larasearch;\n\nuse Mockery as m;\n\nclass ResponseTest extends \\PHPUnit_Framework_TestCase {\n\n p"
},
{
"path": "tests/Iverberk/Larasearch/Traits/CallableTraitTest.php",
"chars": 699,
"preview": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nclass CallableTraitTest exten"
},
{
"path": "tests/Iverberk/Larasearch/Traits/SearchableTraitTest.php",
"chars": 3234,
"preview": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Husband;\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Fac"
},
{
"path": "tests/Iverberk/Larasearch/Traits/TransformableTraitTest.php",
"chars": 859,
"preview": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Config;\n"
},
{
"path": "tests/Iverberk/Larasearch/UtilsTest.php",
"chars": 2222,
"preview": "<?php namespace Iverberk\\Larasearch;\n\n\nclass UtilsTest extends \\PHPUnit_Framework_TestCase {\n\n public function testTh"
},
{
"path": "tests/Support/Dummy.php",
"chars": 98,
"preview": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Dummy {\n\n use SearchableTrait;\n\n}"
},
{
"path": "tests/Support/Stubs/Child.php",
"chars": 710,
"preview": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Child extends Illuminate\\Database\\Eloquent\\Model {\n\n us"
},
{
"path": "tests/Support/Stubs/Foo/Bar.php",
"chars": 158,
"preview": "<?php namespace House;\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Item extends \\Illuminate\\Database\\Eloquen"
},
{
"path": "tests/Support/Stubs/Husband.php",
"chars": 1063,
"preview": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Husband extends Illuminate\\Database\\Eloquent\\Model {\n\n "
},
{
"path": "tests/Support/Stubs/NamespaceDummy.php",
"chars": 54,
"preview": "<?php namespace DummyTest;\n\nclass NamespaceDummy {\n\n} "
},
{
"path": "tests/Support/Stubs/Toy.php",
"chars": 300,
"preview": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Toy extends Illuminate\\Database\\Eloquent\\Model {\n\n use "
},
{
"path": "tests/Support/Stubs/Wife.php",
"chars": 527,
"preview": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Wife extends Illuminate\\Database\\Eloquent\\Model {\n\n use"
},
{
"path": "tests/bootstrap.php",
"chars": 649,
"preview": "<?php\n\n// Composer autoloader\n\nrequire __DIR__ . '/../vendor/autoload.php';\n\n// Boot Aspect Mock\n\n$kernel = \\AspectMock\\"
}
]
About this extraction
This page contains the full source code of the iverberk/larasearch GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 50 files (253.2 KB), approximately 54.6k tokens, and a symbol index with 329 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.