[
  {
    "path": ".gitignore",
    "content": "/vendor\ncomposer.phar\ncomposer.lock\n.DS_Store\n\ntests/coverage/*\n.idea/\natlassian-ide-plugin.xml\n"
  },
  {
    "path": ".travis.yml",
    "content": "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 install --prefer-source --no-interaction --dev\n\nscript: phpunit\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Ivo Verberk\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "Introduction\n------------\n\nLarasearch is a Laravel package that aims to seamlessly integrate Elasticsearch functionality with the Eloquent ORM.\n\nFeatures\n--------\n\n  - Plug 'n Play searching functionality for Eloquent models\n  - Automatic creation/indexing based on Eloquent model properties and relations\n  - Aggregations, Suggestions, Autocomplete, Highlighting, etc. It's all there!\n  - Load Eloquent models based on Elasticsearch queries\n  - Automatic reindexing on updates of (related) Eloquent models\n\nInstallation\n------------\n\n*Laravel 5*\n\nNB: This is preliminary support. When L5 compatibility is stable I will tag it with a version.\n\nAdd Larasearch to your composer.json file:\n\n```\"iverberk/larasearch\": \"dev-L5\"```\n\nAdd the service provider to your Laravel application config:\n\n```PHP\n'Iverberk\\Larasearch\\LarasearchServiceProvider'\n```\n\n*Laravel 4*\n\nAdd Larasearch to your composer.json file:\n\n```\"iverberk/larasearch\": \"0.8.0\"```\n\nAdd the service provider to your Laravel application config:\n\n```PHP\n'Iverberk\\Larasearch\\LarasearchServiceProvider'\n```\n\n\n\nWiki\n----\nPlease see the Github [wiki](https://github.com/iverberk/larasearch/wiki/Introduction) for the most up-to-date documentation.\n\nChangelog\n---------\nAll releases are tracked and documented in the [changelog](https://github.com/iverberk/larasearch/wiki/Changelog).\n\nCredits\n-------\nThis package is very much inspired by these excellent packages that already exist for the Ruby/Rails ecosystem.\n\n* [Searchkick](https://github.com/ankane/searchkick)\n* [Elasticsearch Rails](https://github.com/elasticsearch/elasticsearch-rails)\n\nA lot of their ideas have been reused to work within a PHP/Laravel environment.\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"iverberk/larasearch\",\n    \"description\": \"Elasticsearch enabled Eloquent models\",\n    \"keywords\": [\"search\", \"elasticsearch\", \"eloquent\"],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Ivo Verberk\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.4.0\",\n        \"illuminate/support\": \"~5.0\",\n        \"illuminate/database\": \"~5.0\",\n        \"illuminate/console\": \"~5.0\",\n\t\t\"illuminate/config\": \"~5.0\",\n        \"doctrine/dbal\": \"2.5.1\",\n        \"elasticsearch/elasticsearch\": \"~1.0\",\n        \"nikic/php-parser\": \"*\"\n    },\n    \"autoload\": {\n        \"psr-0\": {\n            \"Iverberk\\\\Larasearch\": \"src/\"\n        },\n        \"classmap\": [\n            \"tests/Support/Stubs\",\n            \"tests/Support\"\n        ]\n    },\n    \"require-dev\": {\n        \"mockery/mockery\": \"dev-master\",\n\t\t\"phpunit/phpunit\": \"4.4.*\",\n        \"codeception/aspect-mock\": \"*\"\n    }\n}\n"
  },
  {
    "path": "phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit backupGlobals=\"false\"\n         backupStaticAttributes=\"false\"\n         bootstrap=\"tests/bootstrap.php\"\n         colors=\"true\"\n         convertErrorsToExceptions=\"true\"\n         convertNoticesToExceptions=\"true\"\n         convertWarningsToExceptions=\"true\"\n         processIsolation=\"false\"\n         stopOnFailure=\"false\"\n         syntaxCheck=\"false\"\n>\n    <testsuites>\n        <testsuite name=\"Package Test Suite\">\n            <directory suffix=\".php\">./tests/</directory>\n        </testsuite>\n    </testsuites>\n\n    <filter>\n        <whitelist addUncoveredFilesFromWhitelist=\"true\">\n            <directory suffix=\".php\">./src/Iverberk/Larasearch</directory>\n        </whitelist>\n    </filter>\n\n</phpunit>\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Commands/PathsCommand.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Commands;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Illuminate\\Support\\Facades\\File;\nuse Iverberk\\Larasearch\\Utils;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass PathsCommand extends Command {\n\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'larasearch:paths';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Generate paths from Eloquent models';\n\n    /**\n     * @var array\n     */\n    private $relationClassMethods = [];\n\n    /**\n     * @var array\n     */\n    private $relatedModels = [];\n\n    /**\n     * @var array\n     */\n    private $paths = [];\n\n    /**\n     * @var array\n     */\n    private $reversedPaths = [];\n\n    /**\n     * Scan directories for Eloquent models that use the SearchableTrait.\n     * Generate paths for all these models so that we can (re)index these\n     * models.\n     *\n     * @return void\n     */\n    public function fire()\n    {\n        $models = $this->argument('model');\n\n        foreach ($models as $model)\n        {\n            $this->compilePaths(new $model);\n        }\n\n        if ($directories = $this->option('dir'))\n        {\n            $directoryModels = array_diff(Utils::findSearchableModels($directories), $models);\n\n            foreach ($directoryModels as $model)\n            {\n                // Find paths for related models\n                $this->compilePaths(new $model);\n            }\n        }\n\n        if (!empty($models) || !empty($directoryModels))\n        {\n            $this->writeConfig();\n        } else\n        {\n            $this->info('No models found.');\n        }\n    }\n\n    /**\n     * @return array\n     */\n    public function getPaths()\n    {\n        return $this->paths;\n    }\n\n    /**\n     * @return array\n     */\n    public function getReversedPaths()\n    {\n        return $this->reversedPaths;\n    }\n\n    /**\n     * Get the console command arguments.\n     *\n     * @return array\n     */\n    protected function getArguments()\n    {\n        return array(\n            array('model', InputOption::VALUE_OPTIONAL, 'Eloquent model to find paths for', null)\n        );\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return array(\n            array('dir', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Directory to scan for searchable models', null, ''),\n            array('relations', null, InputOption::VALUE_NONE, 'Include related Eloquent models', null),\n            array('write-config', null, InputOption::VALUE_NONE, 'Include the compiled paths in the package configuration', null),\n        );\n    }\n\n    /**\n     * Inspect all relations and build a (reverse) path for every relation.\n     * This information is used to quickly determine which relations need to\n     * be eager loaded on a model when (re)indexing. It also defines the document\n     * structure for Elasticsearch.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Model\n     * @param string $ancestor\n     * @param array $path\n     * @param array $reversedPath\n     * @param null $start\n     */\n    protected function compilePaths(Model $model, $ancestor = null, $path = [], $reversedPath = [], $start = null)\n    {\n        // Initialize some variables if this is the first call\n        if ($ancestor == null) $ancestor = $model;\n        if ($start == null) $start = $model;\n\n        $modelClass = get_class($model);\n\n        // Initialize the found relations to an empty array\n        $relations = [];\n\n        if ($this->option('relations'))\n        {\n            // Find all related models\n            $relatedModels = $this->getRelatedModels($model);\n\n            foreach ($relatedModels as $related)\n            {\n                $newPath = $path;\n                $newPath[] = $related['method']->name;\n\n                // Check if we need to recurse for this related model\n                if (!$related['model'] instanceof $ancestor &&\n                    !$related['model'] instanceof $start &&\n                    $this->checkDocHints($related['method']->getDocComment(), $start)\n                )\n                {\n                    // Get the relations of the related model here, so\n                    // that we can build a reversed path for this relation\n                    $this->getRelatedModels($related['model']);\n\n                    $newReversedPath = $reversedPath;\n\n                    // Check if a reciprocal relation is found back to the original model\n                    if (!isset($this->relationClassMethods[get_class($related['model'])][$modelClass]))\n                    {\n                        // Check if we are possibly dealing with a polymorphic relation (reference to itself)\n                        if (array_key_exists(get_class($related['model']), $this->relationClassMethods[get_class($related['model'])]))\n                        {\n                            $model = get_class($related['model']);\n                            $newReversedPath[] = $this->relationClassMethods[$model][$model];\n                        } else\n                        {\n                            throw new \\RuntimeException(\"Reciprocal relation not found for model '\" . get_class($related['model']) . \"' from within '$modelClass' model\");\n                        }\n                    } else\n                    {\n                        $newReversedPath[] = $this->relationClassMethods[get_class($related['model'])][$modelClass];\n                    }\n\n                    // Add this relation\n                    $relations[] = $related;\n\n                    $this->reversedPaths[$modelClass][] = implode('.', array_reverse($reversedPath));\n                    $this->reversedPaths[$modelClass] = array_values(array_unique($this->reversedPaths[$modelClass]));\n\n                    $this->compilePaths($related['model'], $model, $newPath, $newReversedPath, $start);\n                }\n            }\n        }\n\n        // Found no more relations for this model so build the final path\n        // and add the last inverse path segment\n        if (empty($relations))\n        {\n\n            if (!empty($path))\n            {\n                $this->paths[get_class($start)][] = implode('.', $path);\n            } else\n            {\n                $this->paths[get_class($start)] = [];\n            }\n\n            $this->reversedPaths[$modelClass][] = implode('.', array_reverse($reversedPath));\n            $this->reversedPaths[$modelClass] = array_values(array_unique($this->reversedPaths[$modelClass]));\n        }\n    }\n\n    /**\n     * Inspect the relation method annotations to see if we need to follow the relation\n     *\n     * @param string $docComment\n     * @param        $model\n     * @return bool\n     */\n    protected function checkDocHints($docComment, $model)\n    {\n        // Check if we never follow this relation\n        if (preg_match('/@follow\\s+NEVER/', $docComment)) return false;\n\n        // Check if we follow the relation from the 'base' model\n        if (preg_match('/@follow\\s+UNLESS\\s+' . str_replace('\\\\', '\\\\\\\\', get_class($model)) . '\\b/', $docComment))\n        {\n            return false;\n        }\n\n        if (preg_match('/@follow\\s+FROM\\b/', $docComment) && !preg_match('/@follow\\s+FROM\\s+' . str_replace('\\\\', '\\\\\\\\', get_class($model)) . '\\b/', $docComment))\n        {\n            return false;\n        }\n\n        // We follow the relation\n        return true;\n    }\n\n    /**\n     * Find related models from a base model\n     *\n     * @param $model\n     * @return array\n     */\n    protected function getRelatedModels(Model $model)\n    {\n        // Store the class name\n        $modelClass = get_class($model);\n\n        // Check if we already know the related models for this model\n        if (!isset($this->relatedModels[$modelClass]))\n        {\n            $relatedModels = [];\n\n            $methods = with(new \\ReflectionClass($model))->getMethods();\n\n            // Iterate all class methods\n            foreach ($methods as $method)\n            {\n                // Check if this method returns an Eloquent relation\n                if ($method->class == $modelClass &&\n                    preg_match('/@return\\s+\\\\\\\\Illuminate\\\\\\\\Database\\\\\\\\Eloquent\\\\\\\\Relations/', $method->getDocComment())\n                )\n                {\n                    // Get the method name, so that we can call it on the model\n                    $relationMethod = $method->name;\n\n                    // Find the relation\n                    $relation = $model->$relationMethod();\n\n                    if ($relation instanceof Relation)\n                    {\n                        // Find the related model\n                        $related = $relation->getRelated();\n\n                        // Store the method to help build the inverse path\n                        $this->relationClassMethods[$modelClass][get_class($related)] = $relationMethod;\n\n                        $relatedModels[] = ['model' => $related, 'method' => $method];\n                    }\n                }\n            }\n\n            // Cache related models for this model\n            $this->relatedModels[$modelClass] = $relatedModels;\n\n            // Return the related models\n            return $relatedModels;\n        } else\n        {\n            // Return from cache\n            return $this->relatedModels[$modelClass];\n        }\n    }\n\n    /**\n     * Write the paths config to a file or to standard output\n     *\n     * @return void\n     */\n    private function writeConfig()\n    {\n        if ($this->option('write-config'))\n        {\n            $configFile = base_path() . '/config/larasearch.php';\n\n            if ($this->getLaravel())\n            {\n                if ( ! File::exists($configFile))\n                {\n                    if ($this->confirm('It appears that you have not yet published the larasearch config. Would you like to do this now?', false))\n                    {\n                        $this->call('vendor:publish', ['--provider' => 'Iverberk\\\\Larasearch\\LarasearchServiceProvider', '--tag' => 'config']);\n                    }\n                    else\n                    {\n                        return;\n                    }\n                }\n            }\n            else\n            {\n                if ( ! File::exists($configFile))\n                {\n                    $this->info('Lumen application detected. Please copy the config manually to config/larasearch.php.');\n                }\n            }\n\n            File::put(dirname($configFile) . \"/paths.json\", json_encode(['paths' => $this->paths, 'reversedPaths' => $this->reversedPaths], JSON_PRETTY_PRINT));\n\n            $this->info('Paths file written to local package configuration');\n        }\n        else\n        {\n            $this->info(json_encode(['paths' => $this->paths, 'reversedPaths' => $this->reversedPaths], JSON_PRETTY_PRINT));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Commands/ReindexCommand.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Commands;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\File;\nuse Iverberk\\Larasearch\\Utils;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass ReindexCommand extends Command {\n\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'larasearch:reindex';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Reindex Eloquent models to Elasticsearch.';\n\n    /**\n     * Execute the console command.\n     *\n     * @return mixed\n     */\n    public function fire()\n    {\n        $directoryModels = [];\n        $models = $this->argument('model');\n\n        foreach ($models as $model)\n        {\n            $instance = $this->getModelInstance($model);\n            $this->reindexModel($instance);\n        }\n\n        if ($directories = $this->option('dir'))\n        {\n            $directoryModels = array_diff(Utils::findSearchableModels($directories), $models);\n\n            foreach ($directoryModels as $model)\n            {\n                $instance = $this->getModelInstance($model);\n                $this->reindexModel($instance);\n            }\n        }\n\n        if (empty($models) && empty($directoryModels))\n        {\n            $this->info('No models found.');\n        }\n    }\n\n    /**\n     * Get the console command arguments.\n     *\n     * @return array\n     */\n    protected function getArguments()\n    {\n        return array(\n            array('model', InputOption::VALUE_OPTIONAL, 'Eloquent model to reindex', null)\n        );\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return array(\n            array('relations', null, InputOption::VALUE_NONE, 'Reindex related Eloquent models', null),\n            array('mapping', null, InputOption::VALUE_REQUIRED, 'A file containing custom mappings', null),\n            array('dir', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Directory to scan for searchable models', null),\n            array('batch', null, InputOption::VALUE_OPTIONAL, 'The number of records to index in a single batch', 750),\n            array('force', null, InputOption::VALUE_NONE, 'Overwrite existing indices and documents', null),\n        );\n    }\n\n    /**\n     * Reindex a model to Elasticsearch\n     *\n     * @param Model $model\n     */\n    protected function reindexModel(Model $model)\n    {\n        $mapping = $this->option('mapping') ? json_decode(File::get($this->option('mapping')), true) : null;\n\n        $this->info('---> Reindexing ' . get_class($model));\n\n        $model->reindex(\n            $this->option('relations'),\n            $this->option('batch'),\n            $mapping,\n            function ($batch)\n            {\n                $this->info(\"* Batch ${batch}\");\n            }\n        );\n    }\n\n    /**\n     * Simple method to create instances of classes on the fly\n     * It's primarily here to enable unit-testing\n     *\n     * @param string $model\n     */\n    protected function getModelInstance($model)\n    {\n        return new $model;\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Exceptions/ImportException.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Exceptions;\n\nuse Exception;\n\nclass ImportException extends Exception {\n\n    // Redefine the exception so message isn't optional\n    public function __construct($message, $code = 0, $errorItems = [])\n    {\n        // make sure everything is assigned properly\n        parent::__construct($message, $code);\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Index.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Str;\nuse Iverberk\\Larasearch\\Exceptions\\ImportException;\n\nclass Index {\n\n    /**\n     * Index name\n     *\n     * @var string\n     */\n    private $name;\n\n    /**\n     * Elasticsearch client\n     *\n     * @var \\Elasticsearch\\Client\n     */\n    private static $client;\n\n    /**\n     * Index parameters\n     *\n     * @var array\n     */\n    private $params;\n\n    /**\n     * Larasearch Eloquent proxy\n     *\n     * @var Proxy\n     */\n    private $proxy;\n\n    /**\n     * Retrieve the ElasticSearch Client\n     *\n     * @return \\Elasticsearch\\Client\n     */\n    private static function getClient()\n    {\n        return self::$client;\n    }\n\n\n    /**\n     * @param Proxy $proxy\n     * @param string $name\n     */\n    public function __construct(Proxy $proxy, $name = '')\n    {\n        self::$client = App::make('Elasticsearch');\n\n        $this->setProxy($proxy);\n        $this->setName($name ?: $proxy->getModel()->getTable());\n    }\n\n    /**\n     * Import an Eloquent\n     *\n     * @param Model $model\n     * @param array $relations\n     * @param int $batchSize\n     * @param callable $callback\n     * @internal param $type\n     */\n    public function import(Model $model, $relations = [], $batchSize = 750, Callable $callback = null)\n    {\n        $batch = 0;\n\n        while (true)\n        {\n            // Increase the batch number\n            $batch += 1;\n\n            // Load records from the database\n            $records = $model\n                ->with($relations)\n                ->skip($batchSize * ($batch - 1))\n                ->take($batchSize)\n                ->get();\n\n            // Break out of the loop if we are out of records\n            if (count($records) == 0) break;\n\n            // Call the callback function to provide feedback on the import process\n            if ($callback)\n            {\n                $callback($batch);\n            }\n\n            // Transform each record before sending it to Elasticsearch\n            $data = [];\n\n            foreach ($records as $record)\n            {\n                $data[] = [\n                    'index' => [\n                        '_id' => $record->getEsId()\n                    ]\n                ];\n\n                $data[] = $record->transform(!empty($relations));\n            }\n\n            // Bulk import the data to Elasticsearch\n            $this->bulk($data);\n        }\n    }\n\n    /**\n     * Set index name\n     *\n     * @param string\n     * @return Index\n     */\n    public function setName($name)\n    {\n        $index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');\n        if ($index_prefix && !Str::startsWith($name, $index_prefix)) $name = $index_prefix . $name;\n\n        $this->name = $name;\n\n        return $this;\n    }\n\n    /**\n     * Get index name\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return strtolower($this->name);\n    }\n\n    /**\n     * Set ElasticSearch Proxy for the index\n     *\n     * @param Proxy $proxy\n     * @return \\Iverberk\\Larasearch\\Proxy\n     * @author Chris Nagle\n     */\n    public function setProxy(Proxy $proxy)\n    {\n        $this->proxy = $proxy;\n\n        return $proxy;\n    }\n\n    /**\n     * Get ElasticSearch Proxy for the index\n     *\n     * @return \\Iverberk\\Larasearch\\Proxy\n     */\n    public function getProxy()\n    {\n        return $this->proxy;\n    }\n\n    /**\n     * Create a new index\n     *\n     * @param array $options\n     */\n    public function create($options = [])\n    {\n        $body = empty($options) ? $this->getDefaultIndexParams() : $options;\n\n        self::getClient()->indices()->create(['index' => $this->getName(), 'body' => $body]);\n    }\n\n    /**\n     * Delete an index\n     */\n    public function delete()\n    {\n        self::getClient()->indices()->delete(['index' => $this->getName()]);\n    }\n\n    /**\n     * Check if an index exists\n     *\n     * @return bool\n     */\n    public function exists()\n    {\n        return self::getClient()->indices()->exists(['index' => $this->getName()]);\n    }\n\n    /**\n     * Check if an alias exists\n     *\n     * @param $alias\n     * @return bool\n     */\n    public function aliasExists($alias)\n    {\n        $index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');\n        if ($index_prefix && !Str::startsWith($alias, $index_prefix)) $alias = $index_prefix . $alias;\n\n        return self::getClient()->indices()->existsAlias(['name' => $alias]);\n    }\n\n    /**\n     * Store a record in the index\n     *\n     * @param $record\n     */\n    public function store($record)\n    {\n        $params['index'] = $this->getName();\n        $params['type'] = $record['type'];\n        $params['id'] = $record['id'];\n        $params['body'] = $record['data'];\n\n        self::getClient()->index($params);\n    }\n\n    /**\n     * Retrieve a record from the index\n     *\n     * @param $record\n     */\n    public function retrieve($record)\n    {\n        $params['index'] = $this->getName();\n        $params['type'] = $record['type'];\n        $params['id'] = $record['id'];\n\n        self::getClient()->get($params);\n    }\n\n    /**\n     * Remove a record from the index\n     *\n     * @param $record\n     */\n    public function remove($record)\n    {\n        $params['index'] = $this->getName();\n        $params['type'] = $record['type'];\n        $params['id'] = $record['id'];\n\n        self::getClient()->delete($params);\n    }\n\n    /**\n     * Inspect tokens returned from the analyzer\n     *\n     * @param string $text\n     * @param array $options\n     */\n    public function tokens($text, $options = [])\n    {\n        self::getClient()->indices()->analyze(array_merge(['index' => $this->getName(), 'text' => $text], $options));\n    }\n\n    /**\n     * @return array\n     */\n    public function getParams()\n    {\n        return $this->params;\n    }\n\n    /**\n     * @param $params\n     */\n    public function setParams($params)\n    {\n        $this->params = $params;\n    }\n\n    /**\n     * @param $records\n     * @throws ImportException\n     */\n    public function bulk($records)\n    {\n        $params['index'] = $this->getName();\n        $params['type'] = $this->getProxy()->getType();\n        $params['body'] = $records;\n\n        $results = self::getClient()->bulk($params);\n\n        if ($results['errors'])\n        {\n            $errorItems = [];\n\n            foreach ($results['items'] as $item)\n            {\n                if (array_key_exists('error', $item['index']))\n                {\n                    $errorItems[] = $item;\n                }\n            }\n\n            throw new ImportException('Bulk import with errors', 1, $errorItems);\n        }\n    }\n\n    /**\n     * Clean old indices that start with $name\n     *\n     * @param $name\n     */\n    public static function clean($name)\n    {\n        $index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');\n        if ($index_prefix && !Str::startsWith($name, $index_prefix)) $name = $index_prefix . $name;\n\n        $indices = self::getClient()->indices()->getAliases();\n        foreach ($indices as $index => $value)\n        {\n            if (empty($value['aliases']) && preg_match(\"/^${name}_\\\\d{14,17}$/\", $index))\n            {\n                self::getClient()->indices()->delete(['index' => $index]);\n            }\n        }\n    }\n\n    /**\n     * Retrieve aliases\n     *\n     * @param $name\n     * @return array\n     */\n    public static function getAlias($name)\n    {\n        $index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');\n        if ($index_prefix && !Str::startsWith($name, $index_prefix)) $name = $index_prefix . $name;\n\n        return self::getClient()->indices()->getAlias(['name' => $name]);\n    }\n\n    /**\n     * @param array $actions\n     * @return array\n     */\n    public static function updateAliases(array $actions)\n    {\n        if (isset($actions['actions']) && ($index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '')))\n        {\n            foreach ($actions['actions'] as &$action)\n            {\n                list($verb, $data) = each($action);\n                if (!Str::startsWith($data['index'], $index_prefix)) $action[$verb]['index'] = $index_prefix . $data['index'];\n                if (!Str::startsWith($data['alias'], $index_prefix)) $action[$verb]['alias'] = $index_prefix . $data['alias'];\n            }\n        }\n\n        return self::getClient()->indices()->updateAliases(['body' => $actions]);\n    }\n\n    /**\n     * Refresh an index\n     *\n     * @param $index\n     * @return array\n     */\n    public static function refresh($index)\n    {\n        $index_prefix = Config::get('larasearch.elasticsearch.index_prefix', '');\n        if ($index_prefix && !Str::startsWith($index, $index_prefix)) $index = $index_prefix . $index;\n\n        return self::getClient()->indices()->refresh(['index' => $index]);\n    }\n\n    /**\n     * Initialize the default index settings and mappings\n     *\n     * @return array\n     */\n    private function getDefaultIndexParams()\n    {\n        $analyzers = Config::get('larasearch.elasticsearch.analyzers');\n        $params = Config::get('larasearch.elasticsearch.defaults.index');\n        $mapping = [];\n\n        $mapping_options = array_combine(\n            $analyzers,\n            array_map(function ($type)\n                {\n                    $config = $this->getProxy()->getConfig();\n\n                    // Maintain backwards compatibility by allowing a plain array of analyzer => fields\n                    $field_mappings = Utils::findKey($config, $type, false) ?: [];\n\n                    // Also read from a dedicated array key called 'analyzers'\n                    if (isset($config['analyzers']))\n                    {\n                        $field_mappings = array_merge($field_mappings, Utils::findKey($config['analyzers'], $type, false) ?: []);\n                    }\n\n                    return $field_mappings;\n                },\n                $analyzers\n            )\n        );\n\n        foreach (array_unique(array_flatten(array_values($mapping_options))) as $field)\n        {\n            // Extract path segments from dot separated field\n            $pathSegments = explode('.', $field);\n\n            // Last element is the field name\n            $fieldName = array_pop($pathSegments);\n\n            // Apply default field mapping\n            $fieldMapping = [\n                'type' => \"multi_field\",\n                'fields' => [\n                    $fieldName => [\n                        'type' => 'string',\n                        'index' => 'not_analyzed'\n                    ],\n                    'analyzed' => [\n                        'type' => 'string',\n                        'index' => 'analyzed'\n                    ]\n                ]\n            ];\n\n            // Check if we need to add additional mappings\n            foreach ($mapping_options as $type => $fields)\n            {\n                if (in_array($field, $fields))\n                {\n                    $fieldMapping['fields'][$type] = [\n                        'type' => 'string',\n                        'index' => 'analyzed',\n                        'analyzer' => \"larasearch_${type}_index\"\n                    ];\n                }\n            }\n\n            if (!empty($pathSegments))\n            {\n                $mapping = Utils::array_merge_recursive_distinct(\n                    $mapping,\n                    $this->getNestedFieldMapping($fieldName, $fieldMapping, $pathSegments)\n                );\n            } else\n            {\n                $mapping[$fieldName] = $fieldMapping;\n            }\n        }\n\n        if (!empty($mapping)) $params['mappings']['_default_']['properties'] = $mapping;\n\n        $params['index'] = $this->getName();\n        $params['type'] = $this->getProxy()->getType();\n\n        return $params;\n    }\n\n    /**\n     * @param $fieldName\n     * @param $fieldMapping\n     * @param $pathSegments\n     * @return array\n     */\n    private function getNestedFieldMapping($fieldName, $fieldMapping, $pathSegments)\n    {\n        $nested = [];\n        $current = array_pop($pathSegments);\n\n        // Create the first level\n        $nested[$current] = [\n            'type' => 'object',\n            'properties' => [\n                $fieldName => $fieldMapping\n            ]\n        ];\n\n        // Add any additional levels\n        foreach (array_reverse($pathSegments) as $pathSegment)\n        {\n            $nested[$pathSegment] = [\n                'type' => 'object',\n                'properties' => $nested\n            ];\n\n            unset($nested[$current]);\n            $current = $pathSegment;\n        }\n\n        return $nested;\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Jobs/DeleteJob.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Jobs;\n\nuse Iverberk\\Larasearch\\Config;\nuse Illuminate\\Foundation\\Application;\nuse Illuminate\\Queue\\Jobs\\Job;\n\n/**\n * Class DeleteJob\n *\n * @package Iverberk\\Larasearch\\Jobs\n */\nclass DeleteJob {\n\n    /**\n     * @var Application\n     */\n    private $app;\n\n    /**\n     * @var Config\n     */\n    private $config;\n\n    /**\n     * @param Application $app\n     * @param Config\n     */\n    public function __construct(Application $app, Config $config)\n    {\n        $this->app = $app;\n        $this->config = $config;\n    }\n\n    /**\n     * @param Job $job\n     * @param mixed $models\n     */\n    public function fire(Job $job, $models)\n    {\n        $loggerContainerBinding = $this->config->get('logger', 'iverberk.larasearch.logger');\n        $logger = $this->app->make($loggerContainerBinding);\n\n        foreach ($models as $model)\n        {\n            list($class, $id) = explode(':', $model);\n\n            $logger->info('Deleting ' . $class . ' with ID: ' . $id . ' from Elasticsearch');\n\n            $model = new $class;\n\n            $model->deleteDoc($id);\n        }\n\n        $job->delete();\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Jobs/ReindexJob.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Jobs;\n\nuse Illuminate\\Config\\Repository;\nuse Illuminate\\Foundation\\Application;\nuse Illuminate\\Queue\\Jobs\\Job;\nuse Exception;\n\n/**\n * Class ReindexJob\n *\n * @package Iverberk\\Larasearch\\Jobs\n */\nclass ReindexJob {\n\n    /**\n     * @var Application\n     */\n    private $app;\n\n    /**\n     * @var Config\n     */\n    private $config;\n\n    /**\n     * @param Application $app\n     * @param Repository $config\n     */\n    public function __construct(Application $app, Repository $config)\n    {\n        $this->app = $app;\n        $this->config = $config;\n    }\n\n    public function fire(Job $job, $models)\n    {\n        $loggerContainerBinding = $this->config->get('larasearch.logger');\n        $logger = $this->app->make($loggerContainerBinding);\n\n        foreach ($models as $model)\n        {\n            list($class, $id) = explode(':', $model);\n\n            $logger->info('Indexing ' . $class . ' with ID: ' . $id);\n\n            try\n            {\n                $model = $class::findOrFail($id);\n                $model->refreshDoc($model);\n            } catch (Exception $e)\n            {\n                $logger->error('Indexing ' . $class . ' with ID: ' . $id . ' failed: ' . $e->getMessage());\n\n                $job->release(60);\n            }\n        }\n\n        $job->delete();\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/LarasearchServiceProvider.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Elasticsearch\\Client;\nuse Illuminate\\Support\\ServiceProvider;\nuse Iverberk\\Larasearch\\Commands\\PathsCommand;\nuse Iverberk\\Larasearch\\Commands\\ReindexCommand;\nuse Iverberk\\Larasearch\\Response\\Result;\nuse Monolog\\Handler\\NullHandler;\nuse Monolog\\Logger;\n\nclass LarasearchServiceProvider extends ServiceProvider\n{\n\n    /**\n     * Indicates if loading of the provider is deferred.\n     *\n     * @var bool\n     */\n    protected $defer = false;\n\n    public function boot()\n    {\n        $this->bootContainerBindings();\n\n        $this->publishes([\n            __DIR__ . '/../../config/larasearch.php' => base_path('config/larasearch.php'),\n        ], 'config');\n    }\n\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->registerCommands();\n\n        if (file_exists(base_path('config/larasearch.php')))\n        {\n            $this->mergeConfigFrom(base_path('config/larasearch.php'), 'larasearch');\n        }\n        else\n        {\n            $this->mergeConfigFrom(__DIR__ . '/../../config/larasearch.php', 'larasearch');\n        }\n    }\n\n    /**\n     * Boot the container bindings.\n     *\n     * @return void\n     */\n    public function bootContainerBindings()\n    {\n        $this->bindElasticsearch();\n        $this->bindLogger();\n        $this->bindIndex();\n        $this->bindQuery();\n        $this->bindProxy();\n        $this->bindResult();\n    }\n\n    /**\n     * Bind a Larasearch log handler to the container\n     */\n    protected function bindLogger()\n    {\n        $this->app->singleton('iverberk.larasearch.logger', function ($app)\n        {\n            return new Logger('larasearch', [new NullHandler()]);\n        });\n    }\n\n    /**\n     * Bind the Elasticsearch client to the container\n     */\n    protected function bindElasticsearch()\n    {\n        $this->app->singleton('Elasticsearch', function ($app)\n        {\n            return new Client(\\Illuminate\\Support\\Facades\\Config::get('larasearch.elasticsearch.params'));\n        });\n    }\n\n    /**\n     * Bind the Larasearch index to the container\n     */\n    protected function bindIndex()\n    {\n        $this->app->bind('iverberk.larasearch.index', function ($app, $params)\n        {\n            $name = isset($params['name']) ? $params['name'] : '';\n\n            return new Index($params['proxy'], $name);\n        });\n    }\n\n    /**\n     * Bind the Larasearch Query to the container\n     */\n    protected function bindQuery()\n    {\n        $this->app->bind('iverberk.larasearch.query', function ($app, $params)\n        {\n            return new Query($params['proxy'], $params['term'], $params['options']);\n        });\n    }\n\n    /**\n     * Bind the Larasearch proxy to the container\n     */\n    protected function bindProxy()\n    {\n        $this->app->bind('iverberk.larasearch.proxy', function ($app, $model)\n        {\n            return new Proxy($model);\n        });\n    }\n\n    /**\n     * Bind the Larasearch result to the container\n     */\n    protected function bindResult()\n    {\n        $this->app->bind('iverberk.larasearch.response.result', function ($app, array $hit)\n        {\n            return new Result($hit);\n        });\n    }\n\n    /**\n     * Register the commands.\n     *\n     * @return void\n     */\n    protected function registerCommands()\n    {\n        $this->app['iverberk.larasearch.commands.reindex'] = $this->app->share(function ($app)\n        {\n            return new ReindexCommand();\n        });\n\n        $this->app['iverberk.larasearch.commands.paths'] = $this->app->share(function ($app)\n        {\n            return new PathsCommand();\n        });\n\n        $this->commands('iverberk.larasearch.commands.reindex');\n        $this->commands('iverberk.larasearch.commands.paths');\n    }\n\n    /**\n     * Get the services provided by the provider.\n     *\n     * @return array\n     */\n    public function provides()\n    {\n        return array();\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Observer.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Queue;\n\nclass Observer {\n\n    /**\n     * Model delete event handler\n     *\n     * @param Model $model\n     */\n    public function deleted(Model $model)\n    {\n        // Delete corresponding $model document from Elasticsearch\n        Queue::push('Iverberk\\Larasearch\\Jobs\\DeleteJob', [get_class($model) . ':' . $model->getKey()]);\n\n        // Update all related model documents to reflect that $model has been removed\n        Queue::push('Iverberk\\Larasearch\\Jobs\\ReindexJob', $this->findAffectedModels($model, true));\n    }\n\n    /**\n     * Model save event handler\n     *\n     * @param Model $model\n     */\n    public function saved(Model $model)\n    {\n        if ($model::$__es_enable && $model->shouldIndex())\n        {\n            Queue::push('Iverberk\\Larasearch\\Jobs\\ReindexJob', $this->findAffectedModels($model));\n        }\n    }\n\n    /**\n     * Find all searchable models that are affected by the model change\n     *\n     * @param Model $model\n     * @return array\n     */\n    private function findAffectedModels(Model $model, $excludeCurrent = false)\n    {\n        // Temporary array to store affected models\n        $affectedModels = [];\n\n        $paths = Config::get('larasearch.reversedPaths.' . get_class($model), []);\n\n        foreach ((array)$paths as $path)\n        {\n            if (!empty($path))\n            {\n                $model = $model->load($path);\n\n                // Explode the path into an array\n                $path = explode('.', $path);\n\n                // Define a little recursive function to walk the relations of the model based on the path\n                // Eventually it will queue all affected searchable models for reindexing\n                $walk = function ($relation, array $path) use (&$walk, &$affectedModels)\n                {\n                    $segment = array_shift($path);\n\n                    $relation = $relation instanceof Collection ? $relation : new Collection([$relation]);\n\n                    foreach ($relation as $record)\n                    {\n                        if ($record instanceof Model)\n                        {\n                            if (!empty($segment))\n                            {\n                                if (array_key_exists($segment, $record->getRelations()))\n                                {\n                                    $walk($record->getRelation($segment), $path);\n                                } else\n                                {\n                                    // Apparently the relation doesn't exist on this model, so skip the rest of the path as well\n                                    return;\n                                }\n                            } else\n                            {\n                                if (in_array('Iverberk\\Larasearch\\Traits\\SearchableTrait', class_uses($record)))\n                                {\n                                    $affectedModels[] = get_class($record) . ':' . $record->getKey();\n                                }\n                            }\n                        }\n                    }\n                };\n\n                $walk($model->getRelation(array_shift($path)), $path);\n            } else if (!$excludeCurrent)\n            {\n                if (in_array('Iverberk\\Larasearch\\Traits\\SearchableTrait', class_uses($model)))\n                {\n                    $affectedModels[] = get_class($model) . ':' . $model->getKey();\n                }\n            }\n        }\n\n        return array_unique($affectedModels);\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Proxy.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Config;\n\nclass Proxy {\n\n    /**\n     * @var array\n     */\n    private $config;\n\n    /**\n     * Construct the Elasticsearch proxy based on an Eloquent model\n     *\n     * @param Model $model\n     */\n    public function __construct(Model $model)\n    {\n        $class = get_class($model);\n\n        $this->config = property_exists($class, '__es_config') ? $class::$__es_config : [];\n\n        $this->config['model'] = $model;\n        $this->config['type'] = str_singular($model->getTable());\n\n        $this->config['client'] = App::make('Elasticsearch');\n        $this->config['index'] = App::make('iverberk.larasearch.index', array('proxy' => $this));\n    }\n\n    /**\n     * @return array\n     */\n    public function getConfig()\n    {\n        return $this->config;\n    }\n\n    /**\n     * @return Model\n     */\n    public function getModel()\n    {\n        return $this->config['model'];\n    }\n\n    /**\n     * @return Index\n     */\n    public function getIndex()\n    {\n        return $this->config['index'];\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getType()\n    {\n        return $this->config['type'];\n    }\n\n    /**\n     * @return \\Elasticsearch\\Client\n     */\n    public function getClient()\n    {\n        return $this->config['client'];\n    }\n\n    /**\n     * @param       $term\n     * @param array $options\n     * @return \\Iverberk\\Larasearch\\Response\n     */\n    public function search($term, $options = [])\n    {\n        return App::make('iverberk.larasearch.query', ['proxy' => $this, 'term' => $term, 'options' => $options])->execute();\n    }\n\n    /**\n     * Performs a search based on a custom Elasticsearch query\n     *\n     * @param array $query\n     * @param array $options\n     * @return \\Iverberk\\Larasearch\\Response\n     */\n    public function searchByQuery($query, $options = [])\n    {\n        $options = array_merge(['query' => $query], $options);\n\n        return App::make('iverberk.larasearch.query', ['proxy' => $this, 'term' => null, 'options' => $options])->execute();\n    }\n\n    /**\n     * Retrieves a single document by identifier\n     *\n     * @param $id\n     * @return Result\n     */\n    public function searchById($id)\n    {\n        return App::make('iverberk.larasearch.response.result', $this->config['client']->get(\n                [\n                    'index' => $this->getIndex()->getName(),\n                    'type' => $this->getType(),\n                    'id' => $id\n                ]\n            )\n        );\n    }\n\n    /**\n     * @param bool $relations\n     * @param int $batchSize\n     * @param array $mapping\n     * @param callable $callback\n     * @internal param bool $force\n     * @internal param array $params\n     */\n    public function reindex($relations = false, $batchSize = 750, $mapping = [], Callable $callback = null)\n    {\n        $model = $this->config['model'];\n        $name = $this->config['index']->getName();\n\n        $newName = $name . '_' . date(\"YmdHis\");\n        $relations = $relations ? Config::get('larasearch.paths.' . get_class($model)) : [];\n\n        Index::clean($name);\n\n        $index = App::make('iverberk.larasearch.index', array('name' => $newName, 'proxy' => $this));\n        $index->create($mapping);\n\n        if ($index->aliasExists($name))\n        {\n            $index->import($model, $relations, $batchSize, $callback);\n            $remove = [];\n\n            foreach (Index::getAlias($name) as $index => $aliases)\n            {\n                $remove = [\n                    'remove' => [\n                        'index' => $index,\n                        'alias' => $name\n                    ]\n                ];\n            }\n\n            $add = [\n                'add' => [\n                    'index' => $newName,\n                    'alias' => $name\n                ]\n            ];\n\n            $actions[] = array_merge($remove, $add);\n\n            Index::updateAliases(['actions' => $actions]);\n            Index::clean($name);\n        } else\n        {\n            if ($this->config['index']->exists()) $this->config['index']->delete();\n\n            $actions[] =\n                [\n                    'add' => [\n                        'index' => $newName,\n                        'alias' => $name\n                    ]\n                ];\n\n            Index::updateAliases([\n                'actions' => $actions\n            ]);\n\n            $index->import($model, $relations, $batchSize, $callback);\n        }\n\n        Index::refresh($name);\n    }\n\n    /**\n     * Determine if the model requires a (re)index. Defaults to 'true' but can\n     * be overridden by user-defined logic.\n     *\n     * @return bool\n     */\n    public function shouldIndex()\n    {\n        return true;\n    }\n\n    /**\n     * Reindex a specific database record to Elasticsearch\n     */\n    public function refreshDoc($model)\n    {\n        $this->config['client']->index(\n            [\n                'id' => $model->getEsId(),\n                'index' => $this->getIndex()->getName(),\n                'type' => $this->getType(),\n                'body' => $model->transform(true)\n            ]\n        );\n    }\n\n    /**\n     * Delete a specific database record within Elasticsearch\n     *\n     * @param $id Eloquent id of model object\n     */\n    public function deleteDoc($id)\n    {\n        $this->config['client']->delete(\n            [\n                'id' => $id,\n                'index' => $this->getIndex()->getName(),\n                'type' => $this->getType()\n            ]\n        );\n    }\n\n    /**\n     * Globally enable (re)indexing for this model\n     */\n    public function enableIndexing()\n    {\n        $class = get_class($this->config['model']);\n\n        $class::$__es_enable = true;\n    }\n\n    /**\n     * Globally disable (re)indexing for this model\n     */\n    public function disableIndexing()\n    {\n        $class = get_class($this->config['model']);\n\n        $class::$__es_enable = false;\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Query.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse stdClass;\n\nclass Query {\n\n    /**\n     * @var Proxy\n     */\n    private $proxy;\n\n    /**\n     * @var string\n     */\n    private $term;\n\n    /**\n     * @var array\n     */\n    private $options;\n\n    /**\n     * @var array\n     */\n    private $fields;\n\n    /**\n     * @var array\n     */\n    private $payload;\n\n    /**\n     * @var array\n     */\n    private $pagination;\n\n    /**\n     * @param Proxy $proxy\n     * @param       $term\n     * @param array $options\n     */\n    public function __construct(Proxy $proxy, $term, $options = [])\n    {\n        $this->proxy = $proxy;\n        $this->term = $term;\n        $this->options = $options;\n    }\n\n    /**\n     *\n     */\n    private function getAggregations()\n    {\n        if ($aggregations = Utils::findKey($this->options, 'aggs', false))\n        {\n            foreach ($aggregations as $name => $aggregation)\n            {\n                switch ($aggregation['type'])\n                {\n                    case 'terms':\n                        $this->payload['aggs'][$name]['terms'] = ['field' => $aggregation['field'], 'size' => 0];\n                        break;\n                }\n            }\n        }\n    }\n\n    /**\n     *\n     */\n    private function getFields()\n    {\n        if (array_key_exists('fields', $this->options))\n        {\n            if (array_key_exists('autocomplete', $this->options))\n            {\n                $this->fields = array_map(function ($field)\n                    {\n                        return \"${field}.autocomplete\";\n                    },\n                    $this->options['fields']\n                );\n            } else\n            {\n                foreach ($this->options['fields'] as $key => $value)\n                {\n                    if (is_string($key))\n                    {\n                        $k = $key;\n                        $v = $value;\n                    } else\n                    {\n                        // $key is the numerical index, so use $value as key\n                        $k = $value;\n                        $v = 'word';\n                    }\n                    $this->fields[] = \"$k.\" . (($v == 'word') ? 'analyzed' : $v);\n                }\n\n            }\n        } else\n        {\n            if (array_key_exists('autocomplete', $this->options))\n            {\n                $this->fields = array_map(function ($field)\n                    {\n                        return \"${field}.autocomplete\";\n                    },\n                    Utils::findKey($this->proxy->getConfig(), 'autocomplete', []));\n            } else\n            {\n                $this->fields = ['_all'];\n            }\n        }\n    }\n\n    /**\n     * Add requested pagination parameters to the payload\n     */\n    private function getPagination()\n    {\n        # pagination\n        $this->pagination['page'] = 1;\n        $this->pagination['per_page'] = Utils::findKey($this->options, 'limit', 50);\n        $this->pagination['padding'] = Utils::findKey($this->options, 'padding', 0);\n        $this->pagination['offset'] = Utils::findKey($this->options, 'offset', 0);\n\n        $this->payload['size'] = $this->pagination['per_page'];\n        $this->payload['from'] = $this->pagination['offset'];\n    }\n\n    /**\n     * Add requested highlights to the payload\n     */\n    private function getHighlight()\n    {\n        if (Utils::findKey($this->options, 'highlight', false))\n        {\n            foreach ($this->fields as $field)\n            {\n                $this->payload['highlight']['fields'][$field] = new StdClass();\n            }\n\n            if ($tag = Utils::findKey($this->options['highlight'], 'tag', false))\n            {\n                $this->payload['highlight']['pre_tags'] = [$tag];\n                $this->payload['highlight']['post_tags'] = [preg_replace('/\\A</', '</', $tag)];\n            }\n        }\n    }\n\n    /**\n     * Add requested suggestions to the payload\n     */\n    private function getSuggest()\n    {\n        if ($suggestions = Utils::findKey($this->options, 'suggest', false))\n        {\n            $suggest_fields = Utils::findKey($this->proxy->getConfig(), 'suggest', []);\n\n            if ($fields = Utils::findKey($this->options, 'fields', false))\n            {\n                $suggest_fields = array_intersect($suggest_fields, $fields);\n            }\n\n            if (!empty($suggest_fields))\n            {\n                $this->payload['suggest'] = ['text' => $this->term];\n                foreach ($suggest_fields as $field)\n                {\n                    $this->payload['suggest'][$field] = ['phrase' => ['field' => \"${field}.suggest\"]];\n                }\n            }\n        }\n    }\n\n\n    /**\n     * Allow sorting of results\n     */\n    private function getSort()\n    {\n        if ($sort = Utils::findKey($this->options, 'sort', false))\n        {\n            $this->payload['sort'] = $sort;\n        }\n    }\n\n    /**\n     * Construct the payload from the options\n     */\n    private function getPayload()\n    {\n        $payloads = [\n            'json' => Utils::findKey($this->options, 'json', false),\n            'query' => Utils::findKey($this->options, 'query', false),\n            'similar' => [\n                'query' => [\n                    'more_like_this' => [\n                        'fields' => $this->fields,\n                        'like_text' => $this->term,\n                        'min_doc_freq' => 1,\n                        'min_term_freq' => 1,\n                        'analyzer' => \"larasearch_search2\"\n                    ]\n                ]\n            ],\n            'autocomplete' => [\n                'query' => [\n                    'multi_match' => [\n                        'fields' => $this->fields,\n                        'query' => $this->term,\n                        'analyzer' => \"larasearch_autocomplete_search\"\n                    ]\n                ]\n            ]\n        ];\n\n        // Find the correct payload based on the options\n        $payload_key = array_intersect_key($this->options, $payloads);\n\n        $operator = Utils::findKey($this->options, 'operator', 'and');\n\n        if (count($payload_key) == 1)\n        {\n            $this->payload = array_merge($this->payload, $payloads[key($payload_key)]);\n        } elseif (count($payload_key) == 0)\n        {\n            if ($this->term == '*')\n            {\n                $payload = ['match_all' => []];\n            } else\n            {\n                $queries = [];\n\n                foreach ($this->fields as $field)\n                {\n                    $qs = [];\n\n                    $shared_options = [\n                        'query' => $this->term,\n                        'operator' => $operator,\n                        'boost' => 1\n                    ];\n\n                    if ($field == '_all' || substr_compare($field, '.analyzed', -9, 9) === 0)\n                    {\n                        $qs = array_merge($qs, [\n                                array_merge($shared_options, ['boost' => 10, 'analyzer' => \"larasearch_search\"]),\n                                array_merge($shared_options, ['boost' => 10, 'analyzer' => \"larasearch_search2\"])\n                            ]\n                        );\n                        if ($misspellings = Utils::findKey($this->options, 'misspellings', false))\n                        {\n                            $distance = 1;\n                            $qs = array_merge($qs, [\n                                    array_merge($shared_options, ['fuzziness' => $distance, 'max_expansions' => 3, 'analyzer' => \"larasearch_search\"]),\n                                    array_merge($shared_options, ['fuzziness' => $distance, 'max_expansions' => 3, 'analyzer' => \"larasearch_search2\"])\n                                ]\n                            );\n\n                        }\n                    } elseif (substr_compare($field, '.exact', -6, 6) === 0)\n                    {\n                        $f = substr($field, 0, -6);\n                        $queries[] = [\n                            'match' => [\n                                $f => array_merge($shared_options, ['analyzer' => 'keyword'])\n                            ]\n                        ];\n                    } else\n                    {\n                        $analyzer = preg_match('/\\.word_(start|middle|end)\\z/', $field) ? \"larasearch_word_search\" : \"larasearch_autocomplete_search\";\n                        $qs[] = array_merge($shared_options, ['analyzer' => $analyzer]);\n                    }\n\n                    $queries = array_merge($queries, array_map(function ($q) use ($field)\n                    {\n                        return ['match' => [$field => $q]];\n                    }, $qs));\n                }\n\n                $payload = ['dis_max' => ['queries' => $queries]];\n            }\n\n            $this->payload['query'] = $payload;\n        } else\n        {\n            // We have multiple query definitions, so abort\n            throw new \\InvalidArgumentException('Cannot use multiple query definitions.');\n        }\n\n        if ($load = Utils::findKey($this->options, 'load', false))\n        {\n            $this->payload['fields'] = is_array($load) ? $load : [];\n        } elseif ($select = Utils::findKey($this->options, 'select', false))\n        {\n            $this->payload['fields'] = $select;\n        }\n    }\n\n    /**\n     * Execute the query and return the response in a rich wrapper class\n     *\n     * @return Response\n     */\n    public function execute()\n    {\n        $this->getFields();\n        $this->getPagination();\n        $this->getHighlight();\n        $this->getSuggest();\n        $this->getAggregations();\n        $this->getSort();\n        $this->getPayload();\n\n        $params = [\n            'index' => Utils::findKey($this->options, 'index', false) ?: $this->proxy->getIndex()->getName(),\n            'type' => Utils::findKey($this->options, 'type', false) ?: $this->proxy->getType(),\n            'body' => $this->payload\n        ];\n\n        return new Response($this->proxy->getModel(), $this->proxy->getClient()->search($params));\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Response/Records.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Illuminate\\Support\\Collection;\nuse Iverberk\\Larasearch\\Response;\n\nclass Records extends Collection {\n\n    /**\n     * Contains an Elasticsearch response wrapper\n     *\n     * @var \\Iverberk\\Larasearch\\Response\n     */\n    private $response;\n\n    /**\n     * Construct a collection of Eloquent models based on the search result\n     *\n     * @access public\n     * @param Response $response\n     */\n    public function __construct(Response $response)\n    {\n        $this->response = $response;\n\n        $ids = array_map(function ($hit)\n        {\n            return $hit['_id'];\n        }, $this->response->getHits());\n\n        $model = $response->getModel();\n\n        parent::__construct($model::whereIn('id', $ids)->get()->toArray());\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Response/Result.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Illuminate\\Contracts\\Support\\Arrayable;\n\nclass Result implements \\ArrayAccess, Arrayable {\n\n    /**\n     * Contains an Elasticsearch hit response\n     *\n     * @access private\n     * @var array\n     */\n    private $hit;\n\n    /**\n     * Construct the result with the an Elasticsearch hit array\n     *\n     * @access public\n     * @param array $hit\n     */\n    public function __construct(array $hit)\n    {\n        $this->hit = $hit;\n    }\n\n    /**\n     * Return the hit id\n     *\n     * @acccess public\n     * @return integer\n     */\n    public function getId()\n    {\n        return (int)$this->hit['_id'];\n    }\n\n    /**\n     * Return the hit document type\n     *\n     * @access public\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->hit['_type'];\n    }\n\n    /**\n     * Return the hit index\n     *\n     * @access public\n     * @return string\n     */\n    public function getIndex()\n    {\n        return $this->hit['_index'];\n    }\n\n    /**\n     * Return the hit score\n     *\n     * @access public\n     * @return float\n     */\n    public function getScore()\n    {\n        return (float)$this->hit['_score'];\n    }\n\n    /**\n     * Return the _source object\n     *\n     * @access public\n     * @return array\n     */\n    public function getSource()\n    {\n        return $this->hit['_source'];\n    }\n\n    /**\n     * @param array $fields\n     * @return array\n     */\n    public function getFields($fields = [])\n    {\n        $results = [];\n        foreach ($fields as $field)\n        {\n            $results[$field] = $this->hit['fields'][$field];\n        }\n\n        return empty($fields) ? $this->hit['fields'] : $results;\n    }\n\n    /**\n     * Return the hit object\n     *\n     * @access public\n     * @return array\n     */\n    public function getHit()\n    {\n        return $this->hit;\n    }\n\n    /**\n     * @param array $fields\n     * @return array\n     */\n    public function getHighlights($fields = [])\n    {\n        if (!empty($fields))\n        {\n            $results = [];\n            foreach ($fields as $field)\n            {\n                foreach ($this->hit['highlight'] as $key => $value)\n                {\n                    if (preg_match(\"/^${field}.*/\", $key) === 1)\n                    {\n                        $results[$field] = $value;\n                    }\n                }\n            }\n\n            return $results;\n        } else\n        {\n            return $this->hit['highlight'];\n        }\n    }\n\n    /**\n     * Get data by key\n     *\n     * @param string The key data to retrieve\n     * @return mixed\n     * @access public\n     */\n    public function __get($key)\n    {\n        $item = array_get($this->hit, $this->getPath($key));\n\n        return $item;\n    }\n\n    /**\n     * Whether or not an offset exists\n     *\n     * @param mixed $offset\n     * @access      public\n     * @return boolean\n     * @abstracting ArrayAccess\n     */\n    public function offsetExists($offset)\n    {\n        return (array_get($this->hit, $this->getPath($offset)) !== null);\n    }\n\n    /**\n     * Returns the value at specified offset\n     *\n     * @param mixed $offset\n     * @access      public\n     * @return mixed\n     * @abstracting ArrayAccess\n     */\n    public function offsetGet($offset)\n    {\n        return $this->offsetExists($offset) ? array_get($this->hit, $this->getPath($offset)) : null;\n    }\n\n    /**\n     * Assigns a value to the specified offset\n     *\n     * @param mixed $offset\n     * @param mixed $value\n     * @access      public\n     * @abstracting ArrayAccess\n     */\n    public function offsetSet($offset, $value)\n    {\n        // Not allowed for Elasticsearch responses, update the Eloquent model instead.\n    }\n\n    /**\n     * Unsets an offset\n     *\n     * @param mixed $offset\n     * @access      public\n     * @abstracting ArrayAccess\n     */\n    public function offsetUnset($offset)\n    {\n        // Not allowed for Elasticsearch responses, update the Eloquent model instead.\n    }\n\n    /**\n     * Check if the $offset parameter contains a dot and return the appropriate path\n     * in the array\n     *\n     * @access private\n     * @param $offset\n     * @return string\n     */\n    private function getPath($offset)\n    {\n        return (strpos($offset, '.') !== false) ? $path = $offset : \"_source.${offset}\";\n    }\n\n    /**\n     * Get the instance as an array.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return isset($this->hit['fields']) ? $this->hit['fields'] : $this->hit['_source'];\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Response/Results.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Illuminate\\Support\\Collection;\nuse Iverberk\\Larasearch\\Response;\n\nclass Results extends Collection {\n\n    /**\n     * Contains an Elasticsearch response wrapper\n     *\n     * @var \\Iverberk\\Larasearch\\Response\n     */\n    private $response;\n\n    /**\n     * Construct a collection of Result objects based on the hits\n     * in the Elasticsearch response\n     *\n     * @param Response $response\n     */\n    public function __construct(Response $response)\n    {\n        $this->response = $response;\n\n        parent::__construct(\n            array_map(\n                function ($hit)\n                {\n                    return new Result($hit);\n                },\n                $this->response->getHits()\n            )\n        );\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Response.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Iverberk\\Larasearch\\Response\\Results;\n\nclass Response {\n\n    /**\n     * @var \\Illuminate\\Database\\Eloquent\\Model\n     */\n    private $model;\n\n    /**\n     * Elasticsearch response\n     *\n     * @var array\n     */\n    private $response;\n\n    /**\n     * @param Model $model\n     * @param array $response\n     */\n    public function __construct(Model $model, Array $response)\n    {\n        $this->model = $model;\n        $this->response = $response;\n    }\n\n    /**\n     * @return Model\n     */\n    public function getModel()\n    {\n        return $this->model;\n    }\n\n    /**\n     * @return array\n     */\n    public function getResponse()\n    {\n        return $this->response;\n    }\n\n    /**\n     * @return Results\n     */\n    public function getResults()\n    {\n        return new Results($this);\n    }\n\n    /**\n     * @return \\Illuminate\\Database\\Eloquent\\Collection|static[]\n     */\n    public function getRecords()\n    {\n        if (count($this->getHits()) > 0)\n        {\n            $ids = array_map(function ($hit)\n            {\n                return $hit['_id'];\n            }, $this->getHits());\n\n            return call_user_func_array(array($this->model, 'whereIn'), array('id', $ids))->get();\n        } else\n        {\n            return call_user_func(array($this->model, 'newCollection'));\n        }\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getTook()\n    {\n        return $this->response['took'];\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getHits()\n    {\n        return $this->response['hits']['hits'];\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getTimedOut()\n    {\n        return $this->response['timed_out'];\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getShards()\n    {\n        return $this->response['_shards'];\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getMaxScore()\n    {\n        return $this->response['hits']['max_score'];\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getTotal()\n    {\n        return $this->response['hits']['total'];\n    }\n\n    /**\n     * @param array $fields\n     * @return mixed\n     */\n    public function getSuggestions($fields = [])\n    {\n        if (!empty($fields))\n        {\n            $results = [];\n            foreach ($fields as $field)\n            {\n                foreach ($this->response['suggest'] as $key => $value)\n                {\n                    if (preg_match(\"/^${field}.*/\", $key) !== false)\n                    {\n                        $results[$field] = $value;\n                    }\n                }\n            }\n\n            return $results;\n        } else\n        {\n            return $this->response['suggest'];\n        }\n    }\n\n    /**\n     * @param string $name\n     * @return array\n     */\n    public function getAggregations($name = '')\n    {\n        return empty($name) ? $this->response['aggregations'] : $this->response['aggregations'][$name];\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Traits/CallableTrait.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Iverberk\\Larasearch\\Observer;\n\ntrait CallableTrait {\n\n    /**\n     * Boot the trait by registering the Larasearch observer with the model\n     */\n    public static function bootCallableTrait()\n    {\n        if (new static instanceof Model)\n        {\n            static::observe(new Observer);\n        } else\n        {\n            throw new \\Exception(\"This trait can ony be used in Eloquent models.\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Traits/SearchableTrait.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\App;\n\ntrait SearchableTrait {\n\n    use TransformableTrait;\n    use CallableTrait;\n\n    /**\n     * The Elasticsearch proxy class\n     *\n     * @var \\Iverberk\\Larasearch\\Proxy\n     */\n    protected static $__es_proxy = null;\n\n    /**\n     * Related Eloquent models as dot separated paths\n     *\n     * @var array\n     */\n    private static $__es_paths = [];\n\n    /**\n     * Boolean variable to globally enable/disable (re)indexing\n     *\n     * @var bool\n     */\n    public static $__es_enable = true;\n\n    /**\n     * Return an instance of the Elasticsearch proxy\n     *\n     * @throws \\Exception\n     * @return \\Iverberk\\Larasearch\\Proxy | bool\n     */\n    public static function getProxy()\n    {\n        if (!static::$__es_proxy)\n        {\n            $instance = new static;\n\n            if ($instance instanceof Model)\n            {\n                static::$__es_proxy = App::make('iverberk.larasearch.proxy', $instance);\n\n                return static::$__es_proxy;\n            } else\n            {\n                throw new \\Exception(\"This trait can ony be used in Eloquent models.\");\n            }\n        }\n\n        return static::$__es_proxy;\n    }\n\n    /**\n     * Clear the Elasticsearch proxy\n     */\n    public static function clearProxy()\n    {\n        static::$__es_proxy = null;\n    }\n\n    /**\n     * Catch dynamic method calls intended for the Elasticsearch proxy\n     *\n     * @param  string $method\n     * @param  array $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        $proxy = static::getProxy();\n\n        if (is_callable([$proxy, $method]))\n        {\n            return call_user_func_array(array($proxy, $method), $parameters);\n        }\n\n        return parent::__call($method, $parameters);\n    }\n\n    /**\n     * Catch dynamic static method calls intended for the Elasticsearch proxy\n     *\n     * @param  string $method\n     * @param  array $parameters\n     * @return mixed\n     */\n    public static function __callStatic($method, $parameters)\n    {\n        $proxy = static::getProxy();\n\n        if (is_callable([$proxy, $method]))\n        {\n            return call_user_func_array(array($proxy, $method), $parameters);\n        }\n\n        return parent::__callStatic($method, $parameters);\n    }\n\n    /**\n     * Allow custom generation of Elasticsearch document id\n     *\n     * @return mixed\n     */\n    public function getEsId()\n    {\n        return $this->getKey();\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Traits/TransformableTrait.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Illuminate\\Support\\Facades\\Config;\n\ntrait TransformableTrait {\n\n    /**\n     * Transform the Person model and its relations to an Elasticsearch document.\n     *\n     * @param bool $relations\n     * @return array\n     */\n    public function transform($relations = false)\n    {\n        $relations = $relations ? Config::get('larasearch.paths.' . get_class($this)) : [];\n\n        $doc = $this->load($relations)->toArray();\n\n        return $doc;\n    }\n\n}\n"
  },
  {
    "path": "src/Iverberk/Larasearch/Utils.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse PHPParser_Parser;\nuse PHPParser_Lexer;\nuse PHPParser_Node_Stmt_Namespace;\nUse PHPParser_Node_Stmt_Class;\nuse RecursiveDirectoryIterator;\nuse RecursiveIteratorIterator;\nuse RegexIterator;\n\nclass Utils {\n\n    /**\n     * Read and return parameters from an array.\n     *\n     * @param array $params\n     * @param string $arg\n     *\n     * @param null $default\n     * @return null|mixed\n     */\n    public static function findKey($params, $arg, $default = null)\n    {\n        if (is_object($params) === true)\n        {\n            $params = (array)$params;\n        }\n\n        if (isset($params[$arg]) === true)\n        {\n            $val = $params[$arg];\n            unset($params[$arg]);\n\n            return $val;\n        } else\n        {\n            return $default;\n        }\n    }\n\n    /**\n     * Taken from http://php.net/manual/en/function.array-merge-recursive.php#92195\n     * Removed the pass-by-reference to accomdate unit-testing\n     *\n     * @param array $array1\n     * @param array $array2\n     * @return array\n     */\n    public static function array_merge_recursive_distinct(array $array1, array $array2)\n    {\n        $merged = $array1;\n\n        foreach ($array2 as $key => &$value)\n        {\n            if (is_array($value) && isset ($merged[$key]) && is_array($merged[$key]))\n            {\n                $merged[$key] = self::array_merge_recursive_distinct($merged[$key], $value);\n            } else\n            {\n                $merged[$key] = $value;\n            }\n        }\n\n        return $merged;\n    }\n\n    public static function findSearchableModels($directories)\n    {\n        $models = [];\n        $parser = new PHPParser_Parser(new PHPParser_Lexer);\n\n        // Iterate over each directory and inspect files for models\n        foreach ($directories as $directory)\n        {\n            // iterate over all .php files in the directory\n            $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));\n            $files = new RegexIterator($files, '/\\.php$/');\n\n            foreach ($files as $file)\n            {\n                // read the file that should be converted\n                $code = file_get_contents($file);\n\n                // parse\n                $stmts = $parser->parse($code);\n\n                $walk = function ($stmt, $key, $ns) use (&$models, &$walk)\n                {\n                    if ($stmt instanceof PHPParser_Node_Stmt_Namespace)\n                    {\n                        $new_ns = implode('\\\\', $stmt->name->parts);\n                        if ($ns && strpos($new_ns, $ns) !== 0) $new_ns = $ns . $new_ns;\n                        array_walk($stmt->stmts, $walk, $new_ns);\n                    } else if ($stmt instanceof PHPParser_Node_Stmt_Class)\n                    {\n                        $class = $stmt->name;\n                        if ($ns) $class = $ns . '\\\\' . $class;\n                        if (in_array('Iverberk\\\\Larasearch\\\\Traits\\\\SearchableTrait', class_uses($class)))\n                        {\n                            $models[] = $class;\n                        }\n                    }\n                };\n\n                array_walk($stmts, $walk, '');\n            }\n        }\n\n        return $models;\n    }\n\n}\n"
  },
  {
    "path": "src/config/larasearch.php",
    "content": "<?php\n\nuse Psr\\Log\\LogLevel;\n\n$compiled = __DIR__ . '/paths.json';\n\n// Check for a json file that contains the compiled paths for model relations\n$pathConfig = file_exists($compiled) ? json_decode(file_get_contents($compiled), true) : [];\n\nreturn array_merge($pathConfig, array(\n\n    'elasticsearch' => [\n\n        /**\n         * Configuration array for the low-level Elasticsearch client. See\n         * http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/_configuration.html\n         * for additional options.\n         */\n\n        'params' => [\n            'hosts'                 => [ 'localhost:9200' ],\n            'connectionClass'       => '\\Elasticsearch\\Connections\\GuzzleConnection',\n            'connectionFactoryClass'=> '\\Elasticsearch\\Connections\\ConnectionFactory',\n            'connectionPoolClass'   => '\\Elasticsearch\\ConnectionPool\\StaticNoPingConnectionPool',\n            'selectorClass'         => '\\Elasticsearch\\ConnectionPool\\Selectors\\RoundRobinSelector',\n            'serializerClass'       => '\\Elasticsearch\\Serializers\\SmartSerializer',\n            'sniffOnStart'          => false,\n            'connectionParams'      => [],\n            'logging'               => false,\n            'logObject'             => null,\n            'logPath'               => 'elasticsearch.log',\n            'logLevel'              => LogLevel::WARNING,\n            'traceObject'           => null,\n            'tracePath'             => 'elasticsearch.log',\n            'traceLevel'            => LogLevel::WARNING,\n            'guzzleOptions'         => [],\n            'connectionPoolParams'  => ['randomizeHosts' => true],\n            'retries'               => null,\n        ],\n\n        'analyzers' => [\n            'autocomplete',\n            'suggest',\n            'text_start',\n            'text_middle',\n            'text_end',\n            'word_start',\n            'word_middle',\n            'word_end'\n        ],\n\n        /**\n         * Default configuration array for Elasticsearch indices based on Eloquent models\n         * CREDIT: Analyzers, Tokenizers and Filters are copied and renamed from the Searchkick\n         * project to get started quickly.\n         */\n\n        'defaults' => [\n            'index' => [\n                'settings' => [\n                    'number_of_shards' => 1,\n                    'number_of_replicas' => 0,\n                    'analysis' => [\n                        'analyzer' => [\n                            'larasearch_keyword' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"larasearch_stemmer\"]\n                            ],\n                            'default_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"standard\", \"lowercase\", \"asciifolding\", \"larasearch_index_shingle\", \"larasearch_stemmer\"]\n                            ],\n                            'larasearch_search' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"standard\", \"lowercase\", \"asciifolding\", \"larasearch_search_shingle\", \"larasearch_stemmer\"]\n                            ],\n                            'larasearch_search2' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"standard\", \"lowercase\", \"asciifolding\", \"larasearch_stemmer\"]\n                            ],\n                            'larasearch_autocomplete_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"larasearch_autocomplete_ngram\",\n                                'filter' => [\"lowercase\", \"asciifolding\"]\n                            ],\n                            'larasearch_autocomplete_search' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\"]\n                            ],\n                            'larasearch_word_search' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\"]\n                            ],\n                            'larasearch_suggest_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_suggest_shingle\"]\n                            ],\n                            'larasearch_text_start_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_edge_ngram\"]\n                            ],\n                            'larasearch_text_middle_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_ngram\"]\n                            ],\n                            'larasearch_text_end_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"reverse\", \"larasearch_edge_ngram\", \"reverse\"]\n                            ],\n                            'larasearch_word_start_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_edge_ngram\"]\n                            ],\n                            'larasearch_word_middle_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_ngram\"]\n                            ],\n                            'larasearch_word_end_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"reverse\", \"larasearch_edge_ngram\", \"reverse\"]\n                            ]\n                        ],\n                        'filter' => [\n                            'larasearch_index_shingle' => [\n                                'type' => \"shingle\",\n                                'token_separator' => \"\"\n                            ],\n                            'larasearch_search_shingle' => [\n                                'type' => \"shingle\",\n                                'token_separator' => \"\",\n                                'output_unigrams' => false,\n                                'output_unigrams_if_no_shingles' => true\n                            ],\n                            'larasearch_suggest_shingle' => [\n                                'type' => \"shingle\",\n                                'max_shingle_size' => 5\n                            ],\n                            'larasearch_edge_ngram' => [\n                                'type' => \"edgeNGram\",\n                                'min_gram' => 1,\n                                'max_gram' => 50\n                            ],\n                            'larasearch_ngram' => [\n                                'type' => \"nGram\",\n                                'min_gram' => 1,\n                                'max_gram' => 50\n                            ],\n                            'larasearch_stemmer' => [\n                                'type' => \"snowball\",\n                                'language' => \"English\"\n                            ]\n                        ],\n                        'tokenizer' => [\n                            'larasearch_autocomplete_ngram' => [\n                                'type' => \"edgeNGram\",\n                                'min_gram' => 1,\n                                'max_gram' => 50\n                            ]\n                        ]\n                    ]\n                ],\n                'mappings' => [\n                    '_default_' => [\n                        # https://gist.github.com/kimchy/2898285\n                        'dynamic_templates' => [\n                            [\n                                'string_template' => [\n                                    'match' => '*',\n                                    'match_mapping_type' => 'string',\n                                    'mapping' => [\n                                        # http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/\n                                        'type' => 'multi_field',\n                                        'fields' => [\n                                            # analyzed field must be the default field for include_in_all\n                                            # http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/\n                                            # however, we can include the not_analyzed field in _all\n                                            # and the _all index analyzer will take care of it\n                                            '{name}' => ['type' => 'string', 'index' => 'not_analyzed'],\n                                            'analyzed' => ['type' => 'string', 'index' => 'analyzed']\n                                        ]\n                                    ]\n                                ]\n                            ]\n                        ]\n                    ]\n                ]\n            ]\n        ],\n\t    \n        'index_prefix' => ''\n    ],\n\n\t'logger' => 'iverberk.larasearch.logger'\n\n));\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Commands/PathsCommandTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Commands;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\File;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Mockery as m;\n\n/**\n * Global function mocks\n */\nfunction app_path()\n{\n    return PathsCommandTest::$functions->app_path();\n}\n\nfunction constant($const)\n{\n    return PathsCommandTest::$functions->constant($const);\n}\n\nfunction base_path()\n{\n    return PathsCommandTest::$functions->base_path();\n}\n\n/**\n * Class PathsCommandTest\n * @package Iverberk\\Larasearch\\Commands\n * @preserveGlobalState disabled\n */\nclass PathsCommandTest extends \\PHPUnit_Framework_TestCase {\n\n    /**\n     * @var \\Mockery\\Mock $functions\n     */\n    public static $functions;\n\n    /**\n     *\n     */\n    public function setUp()\n    {\n        parent::setUp();\n\n        self::$functions = m::mock();\n    }\n\n    /**\n     *\n     */\n    protected function tearDown()\n    {\n        m::close();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_options()\n    {\n        /**\n         *\n         * Set\n         *\n         **/\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\PathsCommand');\n        $options = array(\n            array('dir', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Directory to scan for searchable models', null, ''),\n            array('relations', null, InputOption::VALUE_NONE, 'Include related Eloquent models', null),\n            array('write-config', null, InputOption::VALUE_NONE, 'Include the compiled paths in the package configuration', null),\n        );\n\n        /**\n         *\n         * Assertion\n         *\n         **/\n        $this->assertEquals($options, $command->getOptions());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_arguments()\n    {\n        /**\n         *\n         * Set\n         *\n         **/\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\PathsCommand');\n        $arguments = array(\n            array('model', InputOption::VALUE_OPTIONAL, 'Eloquent model to find paths for', null)\n        );\n\n        /**\n         *\n         * Assertion\n         *\n         **/\n        $this->assertEquals($arguments, $command->getArguments());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_with_models_and_config()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $command\n         */\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\PathsCommand')->makePartial();\n        $command->shouldAllowMockingProtectedMethods();\n\n        File::clearResolvedInstance('files');\n        File::shouldReceive('put')->once()->andReturn(true);\n        File::shouldReceive('exists')->once()->andReturn(true);\n\n        App::shouldReceive('make')->andReturn(true);\n\n        self::$functions->shouldReceive('base_path')->once()->andReturn('');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $command->shouldReceive('argument')\n            ->with('model')\n            ->once()\n            ->andReturn(['Husband']);\n\n        $command->shouldReceive('option')\n            ->with('dir')\n            ->once()\n            ->andReturn([__DIR__ . '/../../../Support/Stubs']);\n\n        $command->shouldReceive('option')\n            ->with('write-config')\n            ->once()\n            ->andReturn(true);\n\n        $command->shouldReceive('option')\n            ->with('relations')\n            ->times(17)\n            ->andReturn(true);\n\n        $command->shouldReceive('error', 'confirm', 'call', 'info')\n            ->andReturn(true);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $command->fire();\n\n\n        $expected = [\n            'Husband' => ['wife.children.toys'],\n            'Child' => ['mother', 'father', 'toys'],\n            'Toy' => ['children.mother', 'children.father'],\n            'Wife' => ['husband', 'children.toys'],\n            'House\\\\Item' => []\n        ];\n        $actual = $command->getPaths();\n\n        foreach ($expected as $model => $paths)\n        {\n            $this->assertArrayHasKey($model, $actual);\n\n            foreach ($paths as $path)\n            {\n                $this->assertContains($path, $actual[$model]);\n            }\n        }\n\n        $expected = [\n            'Husband' => ['', 'wife', 'children', 'children.toys'],\n            'Child' => ['mother.husband', 'mother', '', 'toys'],\n            'Toy' => ['children.mother.husband', 'children.mother', 'children', ''],\n            'Wife' => ['husband', '', 'children', 'children.toys'],\n            'House\\\\Item' => ['']\n        ];\n        $actual = $command->getReversedPaths();\n\n        foreach ($expected as $model => $paths)\n        {\n            $this->assertArrayHasKey($model, $actual);\n\n            foreach ($paths as $path)\n            {\n                $this->assertContains($path, $actual[$model]);\n            }\n        }\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_without_models()\n    {\n        /**\n         * Set\n         *\n         * @var \\Mockery\\Mock $command\n         */\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\PathsCommand')->makePartial();\n        $command->shouldAllowMockingProtectedMethods();\n\n        App::shouldReceive('make')->andReturn(true);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $command->shouldReceive('argument')\n            ->with('model')\n            ->once()\n            ->andReturn([]);\n\n\n        $command->shouldReceive('option')\n            ->with('dir')\n            ->once()\n            ->andReturn([]);\n\n\n        $command->shouldReceive('compilePaths', 'error', 'confirm', 'call', 'info')\n            ->andReturn(true);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $command->fire();\n\n        $this->assertEquals(\n            [],\n            $command->getPaths()\n        );\n\n        $this->assertEquals(\n            [],\n            $command->getReversedPaths()\n        );\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_without_config()\n    {\n        /**\n         * Set\n         *\n         * @var \\Mockery\\Mock $command\n         */\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\PathsCommand')->makePartial();\n        $command->shouldAllowMockingProtectedMethods();\n\n        App::shouldReceive('make')->andReturn(true);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $command->shouldReceive('argument')\n            ->with('model')\n            ->once()\n            ->andReturn(['Husband']);\n\n        $command->shouldReceive('option')\n            ->with('dir')\n            ->once()\n            ->andReturn([__DIR__ . '/../../../Support/Stubs']);\n\n        $command->shouldReceive('option')\n            ->with('write-config')\n            ->once()\n            ->andReturn(false);\n\n        $command->shouldReceive('compilePaths', 'error', 'confirm', 'call', 'info')\n            ->andReturn(true);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $command->fire();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_with_laravel_and_config_confirmed()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $command\n         */\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\PathsCommand')->makePartial();\n        $command->shouldAllowMockingProtectedMethods();\n\n        File::clearResolvedInstance('files');\n        File::shouldReceive('put')->once()->andReturn(true);\n        File::shouldReceive('exists')->once()->andReturn(false);\n\n        App::shouldReceive('make')->andReturn(true);\n\n        self::$functions->shouldReceive('base_path')->once()->andReturn('');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $command->shouldReceive('getLaravel')\n            ->once()\n            ->andReturn(true);\n\n        $command->shouldReceive('argument')\n            ->with('model')\n            ->once()\n            ->andReturn(['Husband']);\n\n        $command->shouldReceive('option')\n            ->with('dir')\n            ->once()\n            ->andReturn([__DIR__ . '/../../../Support/Stubs']);\n\n        $command->shouldReceive('option')\n            ->with('write-config')\n            ->once()\n            ->andReturn(true);\n\n        $command->shouldReceive('confirm')\n            ->once()\n            ->andReturn(true);\n\n        $command->shouldReceive('compilePaths', 'error', 'call', 'info')\n            ->andReturn(true);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $command->fire();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_with_config_not_confirmed()\n    {\n        /**\n         * Set\n         *\n         * @var \\Mockery\\Mock $command\n         */\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\PathsCommand')->makePartial();\n        $command->shouldAllowMockingProtectedMethods();\n\n        File::clearResolvedInstance('files');\n        File::shouldReceive('exists')->once()->andReturn(false);\n\n        App::shouldReceive('make')->andReturn(true);\n\n        self::$functions->shouldReceive('base_path')->once()->andReturn('');\n\n        /**\n         * Expectation\n         */\n        $command->shouldReceive('getLaravel')\n            ->once()\n            ->andReturn(true);\n\n        $command->shouldReceive('argument')\n            ->with('model')\n            ->once()\n            ->andReturn(['Husband']);\n\n        $command->shouldReceive('option')\n            ->with('dir')\n            ->once()\n            ->andReturn([__DIR__ . '/../../../Support/Stubs']);\n\n        $command->shouldReceive('option')\n            ->with('write-config')\n            ->once()\n            ->andReturn(true);\n\n        $command->shouldReceive('confirm')\n            ->once()\n            ->andReturn(false);\n\n        $command->shouldReceive('compilePaths', 'error', 'call', 'info')\n            ->andReturn(true);\n\n        /*\n        |------------------------------------------------------------\n        | Assertion\n        |------------------------------------------------------------\n        */\n        $command->fire();\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Commands/ReindexCommandTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Commands;\n\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Mockery as m;\n\nclass ReindexCommandTest extends \\PHPUnit_Framework_TestCase {\n\n    /**\n     *\n     */\n    protected function tearDown()\n    {\n        m::close();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_options()\n    {\n        /**\n         *\n         * Set\n         *\n         **/\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\ReindexCommand');\n        $options = array(\n            array('relations', null, InputOption::VALUE_NONE, 'Reindex related Eloquent models', null),\n            array('mapping', null, InputOption::VALUE_REQUIRED, 'A file containing custom mappings', null),\n            array('dir', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Directory to scan for searchable models', null),\n            array('batch', null, InputOption::VALUE_OPTIONAL, 'The number of records to index in a single batch', 750),\n            array('force', null, InputOption::VALUE_NONE, 'Overwrite existing indices and documents', null)\n        );\n\n        /**\n         *\n         * Assertion\n         *\n         **/\n        $this->assertEquals($options, $command->getOptions());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_arguments()\n    {\n        /**\n         *\n         * Set\n         *\n         **/\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\ReindexCommand');\n        $arguments = array(\n            array('model', InputOption::VALUE_OPTIONAL, 'Eloquent model to reindex', null)\n        );\n\n        /**\n         *\n         * Assertion\n         *\n         **/\n        $this->assertEquals($arguments, $command->getArguments());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_without_models()\n    {\n        /**\n         *\n         * Set\n         *\n         **/\n        /* @var \\Mockery\\Mock $command */\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\ReindexCommand')->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $command->shouldReceive('argument')\n            ->with('model')\n            ->once()\n            ->andReturn([]);\n\n        $command->shouldReceive('option')\n            ->with('dir')\n            ->once()\n            ->andReturn([]);\n\n        $command->shouldReceive('info')\n            ->once()\n            ->andReturn(true);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $command->fire();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_with_models()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        /* @var \\Mockery\\Mock $command */\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\ReindexCommand')->makePartial();\n        $command->shouldAllowMockingProtectedMethods();\n\n        $model = m::mock('Husband');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $model->shouldReceive('reindex')\n            ->with(true, 750, null, \\Mockery::type('closure'))\n            ->times(5)\n            ->andReturnUsing(function ($relations, $batch, $mapping, $callback)\n            {\n                $callback(1);\n            });\n\n        $command->shouldReceive('argument')\n            ->with('model')\n            ->once()\n            ->andReturn(['Husband']);\n\n        $command->shouldReceive('option')\n            ->with('dir')\n            ->once()\n            ->andReturn([__DIR__ . '/../../../Support/Stubs']);\n\n        $command->shouldReceive('option')\n            ->with('mapping')\n            ->times(5)\n            ->andReturn(false);\n\n        $command->shouldReceive('option')\n            ->with('relations')\n            ->times(5)\n            ->andReturn(true);\n\n        $command->shouldReceive('option')\n            ->with('batch')\n            ->times(5)\n            ->andReturn(750);\n\n        $command->shouldReceive('info')->andReturn(true);\n\n        $command->shouldReceive('getModelInstance')->times(5)->andReturn($model);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $command->fire();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_a_model_instance()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $command = m::mock('Iverberk\\Larasearch\\Commands\\ReindexCommand')->makePartial();\n        $command->shouldAllowMockingProtectedMethods();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $model = $command->getModelInstance('Husband');\n\n        $this->assertInstanceOf('Husband', $model);\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/IndexTest.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Facade;\nuse Illuminate\\Support\\Facades\\Config;\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nclass IndexTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n        am::clean();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_import()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         */\n        list($index) = $this->getMocks();\n        $test = $this;\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        /* @var \\Mockery\\Mock $model */\n        $model = m::mock('Illuminate\\Database\\Eloquent\\Model')->makePartial();\n\n        $model->shouldReceive('with->skip->take->get')\n            ->twice()\n            ->andReturn([\n                $model, $model, $model\n            ], []);\n\n        $model->shouldReceive('getEsId')\n            ->times(3)\n            ->andReturn(1);\n\n        $model->shouldReceive('transform')\n            ->times(3)\n            ->andReturn(['mock', 'data']);\n\n        $index->shouldReceive('bulk')\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->import($model, [], 750, function ($batch) use ($test)\n        {\n            $test->assertEquals(1, $batch);\n        });\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_set_name()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         */\n        list($index) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals($index, $index->setName('Mock'));\n        $this->assertEquals('bar_mock', $index->getName());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_only_prepend_prefix_once()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         */\n        list($index) = $this->getMocks('baz_');\n\n        /**\n         * Assertions\n         */\n        $this->assertEquals($index, $index->setName('baz_MockMe'));\n        $this->assertEquals('baz_mockme', $index->getName());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_name()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         */\n        list($index) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals('husband', $index->getName());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_create_an_index()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n        $test = $this;\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        Config::shouldReceive('get')\n            ->with('larasearch.elasticsearch.analyzers')\n            ->andReturn([\n                'autocomplete',\n                'suggest',\n                'text_start',\n                'text_middle',\n                'text_end',\n                'word_start',\n                'word_middle',\n                'word_end'\n            ]);\n\n        Config::shouldReceive('get')\n            ->with('larasearch.elasticsearch.defaults.index')\n            ->andReturn([\n                'settings' => [\n                    'number_of_shards' => 1,\n                    'number_of_replicas' => 0,\n                    'analysis' => [\n                        'analyzer' => [\n                            'larasearch_keyword' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"larasearch_stemmer\"]\n                            ],\n                            'default_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"standard\", \"lowercase\", \"asciifolding\", \"larasearch_index_shingle\", \"larasearch_stemmer\"]\n                            ],\n                            'larasearch_search' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"standard\", \"lowercase\", \"asciifolding\", \"larasearch_search_shingle\", \"larasearch_stemmer\"]\n                            ],\n                            'larasearch_search2' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"standard\", \"lowercase\", \"asciifolding\", \"larasearch_stemmer\"]\n                            ],\n                            'larasearch_autocomplete_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"larasearch_autocomplete_ngram\",\n                                'filter' => [\"lowercase\", \"asciifolding\"]\n                            ],\n                            'larasearch_autocomplete_search' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\"]\n                            ],\n                            'larasearch_word_search' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\"]\n                            ],\n                            'larasearch_suggest_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_suggest_shingle\"]\n                            ],\n                            'larasearch_text_start_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_edge_ngram\"]\n                            ],\n                            'larasearch_text_middle_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_ngram\"]\n                            ],\n                            'larasearch_text_end_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"reverse\", \"larasearch_edge_ngram\", \"reverse\"]\n                            ],\n                            'larasearch_word_start_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_edge_ngram\"]\n                            ],\n                            'larasearch_word_middle_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_ngram\"]\n                            ],\n                            'larasearch_word_end_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"reverse\", \"larasearch_edge_ngram\", \"reverse\"]\n                            ]\n                        ],\n                        'filter' => [\n                            'larasearch_index_shingle' => [\n                                'type' => \"shingle\",\n                                'token_separator' => \"\"\n                            ],\n                            'larasearch_search_shingle' => [\n                                'type' => \"shingle\",\n                                'token_separator' => \"\",\n                                'output_unigrams' => false,\n                                'output_unigrams_if_no_shingles' => true\n                            ],\n                            'larasearch_suggest_shingle' => [\n                                'type' => \"shingle\",\n                                'max_shingle_size' => 5\n                            ],\n                            'larasearch_edge_ngram' => [\n                                'type' => \"edgeNGram\",\n                                'min_gram' => 1,\n                                'max_gram' => 50\n                            ],\n                            'larasearch_ngram' => [\n                                'type' => \"nGram\",\n                                'min_gram' => 1,\n                                'max_gram' => 50\n                            ],\n                            'larasearch_stemmer' => [\n                                'type' => \"snowball\",\n                                'language' => \"English\"\n                            ]\n                        ],\n                        'tokenizer' => [\n                            'larasearch_autocomplete_ngram' => [\n                                'type' => \"edgeNGram\",\n                                'min_gram' => 1,\n                                'max_gram' => 50\n                            ]\n                        ]\n                    ]\n                ]]);\n\n        $client->shouldReceive('indices->create')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                          \"index\": \"husband\",\n                          \"body\": {\n                            \"settings\": {\n                              \"number_of_shards\": 1,\n                              \"number_of_replicas\": 0,\n                              \"analysis\": {\n                                \"analyzer\": {\n                                  \"larasearch_keyword\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"larasearch_stemmer\"\n                                    ]\n                                  },\n                                  \"default_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"standard\",\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_index_shingle\",\n                                      \"larasearch_stemmer\"\n                                    ]\n                                  },\n                                  \"larasearch_search\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"standard\",\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_search_shingle\",\n                                      \"larasearch_stemmer\"\n                                    ]\n                                  },\n                                  \"larasearch_search2\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"standard\",\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_stemmer\"\n                                    ]\n                                  },\n                                  \"larasearch_autocomplete_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"larasearch_autocomplete_ngram\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\"\n                                    ]\n                                  },\n                                  \"larasearch_autocomplete_search\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\"\n                                    ]\n                                  },\n                                  \"larasearch_word_search\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\"\n                                    ]\n                                  },\n                                  \"larasearch_suggest_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_suggest_shingle\"\n                                    ]\n                                  },\n                                  \"larasearch_text_start_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_edge_ngram\"\n                                    ]\n                                  },\n                                  \"larasearch_text_middle_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_ngram\"\n                                    ]\n                                  },\n                                  \"larasearch_text_end_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"reverse\",\n                                      \"larasearch_edge_ngram\",\n                                      \"reverse\"\n                                    ]\n                                  },\n                                  \"larasearch_word_start_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_edge_ngram\"\n                                    ]\n                                  },\n                                  \"larasearch_word_middle_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_ngram\"\n                                    ]\n                                  },\n                                  \"larasearch_word_end_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"reverse\",\n                                      \"larasearch_edge_ngram\",\n                                      \"reverse\"\n                                    ]\n                                  }\n                                },\n                                \"filter\": {\n                                  \"larasearch_index_shingle\": {\n                                    \"type\": \"shingle\",\n                                    \"token_separator\": \"\"\n                                  },\n                                  \"larasearch_search_shingle\": {\n                                    \"type\": \"shingle\",\n                                    \"token_separator\": \"\",\n                                    \"output_unigrams\": false,\n                                    \"output_unigrams_if_no_shingles\": true\n                                  },\n                                  \"larasearch_suggest_shingle\": {\n                                    \"type\": \"shingle\",\n                                    \"max_shingle_size\": 5\n                                  },\n                                  \"larasearch_edge_ngram\": {\n                                    \"type\": \"edgeNGram\",\n                                    \"min_gram\": 1,\n                                    \"max_gram\": 50\n                                  },\n                                  \"larasearch_ngram\": {\n                                    \"type\": \"nGram\",\n                                    \"min_gram\": 1,\n                                    \"max_gram\": 50\n                                  },\n                                  \"larasearch_stemmer\": {\n                                    \"type\": \"snowball\",\n                                    \"language\": \"English\"\n                                  }\n                                },\n                                \"tokenizer\": {\n                                  \"larasearch_autocomplete_ngram\": {\n                                    \"type\": \"edgeNGram\",\n                                    \"min_gram\": 1,\n                                    \"max_gram\": 50\n                                  }\n                                }\n                              }\n                            },\n                            \"mappings\": {\n                              \"_default_\": {\n                                \"properties\": {\n                                  \"name\": {\n                                    \"type\": \"multi_field\",\n                                    \"fields\": {\n                                      \"name\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"not_analyzed\"\n                                      },\n                                      \"analyzed\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\"\n                                      },\n                                      \"autocomplete\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_autocomplete_index\"\n                                      },\n                                      \"suggest\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_suggest_index\"\n                                      },\n                                      \"text_start\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_text_start_index\"\n                                      },\n                                      \"text_middle\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_text_middle_index\"\n                                      },\n                                      \"text_end\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_text_end_index\"\n                                      },\n                                      \"word_start\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_word_start_index\"\n                                      },\n                                      \"word_middle\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_word_middle_index\"\n                                      },\n                                      \"word_end\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_word_end_index\"\n                                      }\n                                    }\n                                  },\n                                  \"wife\": {\n                                    \"type\": \"object\",\n                                    \"properties\": {\n                                      \"name\": {\n                                        \"type\": \"multi_field\",\n                                        \"fields\": {\n                                          \"name\": {\n                                            \"type\": \"string\",\n                                            \"index\": \"not_analyzed\"\n                                          },\n                                          \"analyzed\": {\n                                            \"type\": \"string\",\n                                            \"index\": \"analyzed\"\n                                          },\n                                          \"autocomplete\": {\n                                            \"type\": \"string\",\n                                            \"index\": \"analyzed\",\n                                            \"analyzer\": \"larasearch_autocomplete_index\"\n                                          }\n                                        }\n                                      },\n                                      \"children\": {\n                                        \"type\": \"object\",\n                                        \"properties\": {\n                                          \"name\": {\n                                            \"type\": \"multi_field\",\n                                            \"fields\": {\n                                              \"name\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"not_analyzed\"\n                                              },\n                                              \"analyzed\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\"\n                                              },\n                                              \"text_start\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_text_start_index\"\n                                              },\n                                              \"text_middle\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_text_middle_index\"\n                                              },\n                                              \"text_end\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_text_end_index\"\n                                              },\n                                              \"word_start\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_word_start_index\"\n                                              },\n                                              \"word_middle\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_word_middle_index\"\n                                              },\n                                              \"word_end\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_word_end_index\"\n                                              }\n                                            }\n                                          }\n                                        }\n                                      }\n                                    }\n                                  }\n                                }\n                              }\n                            },\n                            \"index\": \"husband\",\n                            \"type\": \"Husband\"\n                          }\n                        }', true)\n                    ,\n                    $params);\n            });\n\n        $proxy->shouldReceive('getType')->andReturn('Husband');\n        $proxy->shouldReceive('getConfig')->andReturn([\n            'autocomplete' => ['name', 'wife.name'],\n            'suggest' => ['name'],\n            'text_start' => ['name', 'wife.children.name'],\n            'text_middle' => ['name', 'wife.children.name'],\n            'text_end' => ['name', 'wife.children.name'],\n            'word_start' => ['name', 'wife.children.name'],\n            'word_middle' => ['name', 'wife.children.name'],\n            'word_end' => ['name', 'wife.children.name']\n        ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->create();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_create_an_index_with_a_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n        $test = $this;\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        Config::shouldReceive('get')\n            ->with('larasearch.elasticsearch.analyzers')\n            ->andReturn([\n                'autocomplete',\n                'suggest',\n                'text_start',\n                'text_middle',\n                'text_end',\n                'word_start',\n                'word_middle',\n                'word_end'\n            ]);\n\n        Config::shouldReceive('get')\n            ->with('larasearch.elasticsearch.defaults.index')\n            ->andReturn([\n                'settings' => [\n                    'number_of_shards' => 1,\n                    'number_of_replicas' => 0,\n                    'analysis' => [\n                        'analyzer' => [\n                            'larasearch_keyword' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"larasearch_stemmer\"]\n                            ],\n                            'default_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"standard\", \"lowercase\", \"asciifolding\", \"larasearch_index_shingle\", \"larasearch_stemmer\"]\n                            ],\n                            'larasearch_search' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"standard\", \"lowercase\", \"asciifolding\", \"larasearch_search_shingle\", \"larasearch_stemmer\"]\n                            ],\n                            'larasearch_search2' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"standard\", \"lowercase\", \"asciifolding\", \"larasearch_stemmer\"]\n                            ],\n                            'larasearch_autocomplete_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"larasearch_autocomplete_ngram\",\n                                'filter' => [\"lowercase\", \"asciifolding\"]\n                            ],\n                            'larasearch_autocomplete_search' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\"]\n                            ],\n                            'larasearch_word_search' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\"]\n                            ],\n                            'larasearch_suggest_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_suggest_shingle\"]\n                            ],\n                            'larasearch_text_start_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_edge_ngram\"]\n                            ],\n                            'larasearch_text_middle_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_ngram\"]\n                            ],\n                            'larasearch_text_end_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"keyword\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"reverse\", \"larasearch_edge_ngram\", \"reverse\"]\n                            ],\n                            'larasearch_word_start_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_edge_ngram\"]\n                            ],\n                            'larasearch_word_middle_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"larasearch_ngram\"]\n                            ],\n                            'larasearch_word_end_index' => [\n                                'type' => \"custom\",\n                                'tokenizer' => \"standard\",\n                                'filter' => [\"lowercase\", \"asciifolding\", \"reverse\", \"larasearch_edge_ngram\", \"reverse\"]\n                            ]\n                        ],\n                        'filter' => [\n                            'larasearch_index_shingle' => [\n                                'type' => \"shingle\",\n                                'token_separator' => \"\"\n                            ],\n                            'larasearch_search_shingle' => [\n                                'type' => \"shingle\",\n                                'token_separator' => \"\",\n                                'output_unigrams' => false,\n                                'output_unigrams_if_no_shingles' => true\n                            ],\n                            'larasearch_suggest_shingle' => [\n                                'type' => \"shingle\",\n                                'max_shingle_size' => 5\n                            ],\n                            'larasearch_edge_ngram' => [\n                                'type' => \"edgeNGram\",\n                                'min_gram' => 1,\n                                'max_gram' => 50\n                            ],\n                            'larasearch_ngram' => [\n                                'type' => \"nGram\",\n                                'min_gram' => 1,\n                                'max_gram' => 50\n                            ],\n                            'larasearch_stemmer' => [\n                                'type' => \"snowball\",\n                                'language' => \"English\"\n                            ]\n                        ],\n                        'tokenizer' => [\n                            'larasearch_autocomplete_ngram' => [\n                                'type' => \"edgeNGram\",\n                                'min_gram' => 1,\n                                'max_gram' => 50\n                            ]\n                        ]\n                    ]\n                ]]);\n\n\n        $client->shouldReceive('indices->create')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                          \"index\": \"bar_husband\",\n                          \"body\": {\n                            \"settings\": {\n                              \"number_of_shards\": 1,\n                              \"number_of_replicas\": 0,\n                              \"analysis\": {\n                                \"analyzer\": {\n                                  \"larasearch_keyword\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"larasearch_stemmer\"\n                                    ]\n                                  },\n                                  \"default_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"standard\",\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_index_shingle\",\n                                      \"larasearch_stemmer\"\n                                    ]\n                                  },\n                                  \"larasearch_search\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"standard\",\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_search_shingle\",\n                                      \"larasearch_stemmer\"\n                                    ]\n                                  },\n                                  \"larasearch_search2\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"standard\",\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_stemmer\"\n                                    ]\n                                  },\n                                  \"larasearch_autocomplete_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"larasearch_autocomplete_ngram\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\"\n                                    ]\n                                  },\n                                  \"larasearch_autocomplete_search\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\"\n                                    ]\n                                  },\n                                  \"larasearch_word_search\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\"\n                                    ]\n                                  },\n                                  \"larasearch_suggest_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_suggest_shingle\"\n                                    ]\n                                  },\n                                  \"larasearch_text_start_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_edge_ngram\"\n                                    ]\n                                  },\n                                  \"larasearch_text_middle_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_ngram\"\n                                    ]\n                                  },\n                                  \"larasearch_text_end_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"keyword\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"reverse\",\n                                      \"larasearch_edge_ngram\",\n                                      \"reverse\"\n                                    ]\n                                  },\n                                  \"larasearch_word_start_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_edge_ngram\"\n                                    ]\n                                  },\n                                  \"larasearch_word_middle_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"larasearch_ngram\"\n                                    ]\n                                  },\n                                  \"larasearch_word_end_index\": {\n                                    \"type\": \"custom\",\n                                    \"tokenizer\": \"standard\",\n                                    \"filter\": [\n                                      \"lowercase\",\n                                      \"asciifolding\",\n                                      \"reverse\",\n                                      \"larasearch_edge_ngram\",\n                                      \"reverse\"\n                                    ]\n                                  }\n                                },\n                                \"filter\": {\n                                  \"larasearch_index_shingle\": {\n                                    \"type\": \"shingle\",\n                                    \"token_separator\": \"\"\n                                  },\n                                  \"larasearch_search_shingle\": {\n                                    \"type\": \"shingle\",\n                                    \"token_separator\": \"\",\n                                    \"output_unigrams\": false,\n                                    \"output_unigrams_if_no_shingles\": true\n                                  },\n                                  \"larasearch_suggest_shingle\": {\n                                    \"type\": \"shingle\",\n                                    \"max_shingle_size\": 5\n                                  },\n                                  \"larasearch_edge_ngram\": {\n                                    \"type\": \"edgeNGram\",\n                                    \"min_gram\": 1,\n                                    \"max_gram\": 50\n                                  },\n                                  \"larasearch_ngram\": {\n                                    \"type\": \"nGram\",\n                                    \"min_gram\": 1,\n                                    \"max_gram\": 50\n                                  },\n                                  \"larasearch_stemmer\": {\n                                    \"type\": \"snowball\",\n                                    \"language\": \"English\"\n                                  }\n                                },\n                                \"tokenizer\": {\n                                  \"larasearch_autocomplete_ngram\": {\n                                    \"type\": \"edgeNGram\",\n                                    \"min_gram\": 1,\n                                    \"max_gram\": 50\n                                  }\n                                }\n                              }\n                            },\n                            \"mappings\": {\n                              \"_default_\": {\n                                \"properties\": {\n                                  \"name\": {\n                                    \"type\": \"multi_field\",\n                                    \"fields\": {\n                                      \"name\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"not_analyzed\"\n                                      },\n                                      \"analyzed\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\"\n                                      },\n                                      \"autocomplete\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_autocomplete_index\"\n                                      },\n                                      \"suggest\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_suggest_index\"\n                                      },\n                                      \"text_start\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_text_start_index\"\n                                      },\n                                      \"text_middle\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_text_middle_index\"\n                                      },\n                                      \"text_end\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_text_end_index\"\n                                      },\n                                      \"word_start\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_word_start_index\"\n                                      },\n                                      \"word_middle\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_word_middle_index\"\n                                      },\n                                      \"word_end\": {\n                                        \"type\": \"string\",\n                                        \"index\": \"analyzed\",\n                                        \"analyzer\": \"larasearch_word_end_index\"\n                                      }\n                                    }\n                                  },\n                                  \"wife\": {\n                                    \"type\": \"object\",\n                                    \"properties\": {\n                                      \"name\": {\n                                        \"type\": \"multi_field\",\n                                        \"fields\": {\n                                          \"name\": {\n                                            \"type\": \"string\",\n                                            \"index\": \"not_analyzed\"\n                                          },\n                                          \"analyzed\": {\n                                            \"type\": \"string\",\n                                            \"index\": \"analyzed\"\n                                          },\n                                          \"autocomplete\": {\n                                            \"type\": \"string\",\n                                            \"index\": \"analyzed\",\n                                            \"analyzer\": \"larasearch_autocomplete_index\"\n                                          }\n                                        }\n                                      },\n                                      \"children\": {\n                                        \"type\": \"object\",\n                                        \"properties\": {\n                                          \"name\": {\n                                            \"type\": \"multi_field\",\n                                            \"fields\": {\n                                              \"name\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"not_analyzed\"\n                                              },\n                                              \"analyzed\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\"\n                                              },\n                                              \"text_start\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_text_start_index\"\n                                              },\n                                              \"text_middle\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_text_middle_index\"\n                                              },\n                                              \"text_end\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_text_end_index\"\n                                              },\n                                              \"word_start\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_word_start_index\"\n                                              },\n                                              \"word_middle\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_word_middle_index\"\n                                              },\n                                              \"word_end\": {\n                                                \"type\": \"string\",\n                                                \"index\": \"analyzed\",\n                                                \"analyzer\": \"larasearch_word_end_index\"\n                                              }\n                                            }\n                                          }\n                                        }\n                                      }\n                                    }\n                                  }\n                                }\n                              }\n                            },\n                            \"index\": \"bar_husband\",\n                            \"type\": \"Husband\"\n                          }\n                        }', true)\n                    ,\n                    $params);\n            });\n\n        $proxy->shouldReceive('getType')->andReturn('Husband');\n        $proxy->shouldReceive('getConfig')->andReturn([\n            'autocomplete' => ['name', 'wife.name'],\n            'suggest' => ['name'],\n            'text_start' => ['name', 'wife.children.name'],\n            'text_middle' => ['name', 'wife.children.name'],\n            'text_end' => ['name', 'wife.children.name'],\n            'word_start' => ['name', 'wife.children.name'],\n            'word_middle' => ['name', 'wife.children.name'],\n            'word_end' => ['name', 'wife.children.name']\n        ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->create();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_delete_an_index()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->delete')\n            ->with(['index' => 'husband'])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->delete();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_delete_an_index_with_a_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->delete')\n            ->with(['index' => 'bar_husband'])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->delete();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_check_that_an_index_exists()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->exists')\n            ->with(['index' => 'husband'])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->exists();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_check_that_an_index_exists_with_a_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->exists')\n            ->with(['index' => 'bar_husband'])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->exists();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_check_that_an_alias_exists()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->existsAlias')\n            ->with(['name' => 'Alias'])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->aliasExists('Alias');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_check_that_an_alias_exists_with_a_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->existsAlias')\n            ->twice()\n            ->with(['name' => 'bar_alias'])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->aliasExists('alias');\n        $index->aliasExists('bar_alias');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_store_a_record()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('index')\n            ->with([\n                'index' => 'husband',\n                'type' => 'Husband',\n                'id' => 1,\n                'body' => 'data'\n            ])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->store([\n            'type' => 'Husband',\n            'id' => 1,\n            'data' => 'data'\n        ]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_store_a_record_with_an_index_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('index')\n            ->twice()\n            ->with([\n                'index' => 'bar_husband',\n                'type' => 'Husband',\n                'id' => 1,\n                'body' => 'data'\n            ])\n            ->andReturn();\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->store([\n            'type' => 'Husband',\n            'id' => 1,\n            'data' => 'data'\n        ]);\n        $index->setName('bar_Husband');\n        $index->store([\n            'type' => 'Husband',\n            'id' => 1,\n            'data' => 'data'\n        ]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_retrieve_a_record()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('get')\n            ->with([\n                'index' => 'husband',\n                'type' => 'Husband',\n                'id' => 1,\n            ])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->retrieve([\n            'type' => 'Husband',\n            'id' => 1,\n            'data' => 'data'\n        ]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_retrieve_a_record_iwth_an_index_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('get')\n            ->twice()\n            ->with([\n                'index' => 'bar_husband',\n                'type' => 'Husband',\n                'id' => 1,\n            ])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->retrieve([\n            'type' => 'Husband',\n            'id' => 1,\n            'data' => 'data'\n        ]);\n        $index->setName('bar_Husband');\n        $index->retrieve([\n            'type' => 'Husband',\n            'id' => 1,\n            'data' => 'data'\n        ]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_remove_a_record()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('delete')\n            ->with([\n                'index' => 'husband',\n                'type' => 'Husband',\n                'id' => 1\n            ])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->remove([\n            'type' => 'Husband',\n            'id' => 1\n        ]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_remove_a_record_with_an_index_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('delete')\n            ->twice()\n            ->with([\n                'index' => 'bar_husband',\n                'type' => 'Husband',\n                'id' => 1\n            ])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->remove([\n            'type' => 'Husband',\n            'id' => 1\n        ]);\n        $index->setName('bar_Husband');\n        $index->remove([\n            'type' => 'Husband',\n            'id' => 1\n        ]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_inspect_tokens()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->analyze')\n            ->with([\n                'index' => 'husband',\n                'text' => 'text',\n                'option1' => 1,\n                'option2' => 2\n            ])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->tokens('text', [\n            'option1' => 1,\n            'option2' => 2\n        ]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_inspect_tokens_with_an_index_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->analyze')\n            ->twice()\n            ->with([\n                'index' => 'bar_husband',\n                'text' => 'text',\n                'option1' => 1,\n                'option2' => 2\n            ])\n            ->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->tokens('text', [\n            'option1' => 1,\n            'option2' => 2\n        ]);\n        $index->setName('bar_Husband');\n        $index->tokens('text', [\n            'option1' => 1,\n            'option2' => 2\n        ]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_and_set_params()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        $index->setParams(['mock' => 'data']);\n        $this->assertEquals(['mock' => 'data'], $index->getParams());\n    }\n\n    /**\n     * @test\n     * @expectedException \\Iverberk\\Larasearch\\Exceptions\\ImportException\n     */\n    public function it_should_store_a_records_in_bulk_with_errors()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $proxy->shouldReceive('getType')->andReturn('Husband');\n\n        $client->shouldReceive('bulk')\n            ->with([\n                'index' => 'bar_husband',\n                'type' => 'Husband',\n                'body' => 'records'\n            ])\n            ->andReturn([\n                'errors' => true,\n                'items' => [\n                    [\n                        'index' => [\n                            'error' => true\n                        ]\n                    ]\n                ]\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->bulk('records');\n    }\n\n    /**\n     * @test\n     * @expectedException \\Iverberk\\Larasearch\\Exceptions\\ImportException\n     */\n    public function it_should_store_records_having_prefix_in_bulk_with_errors()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $proxy->shouldReceive('getType')->andReturn('Husband');\n\n        $client->shouldReceive('bulk')\n            ->with([\n                'index' => 'bar_husband',\n                'type' => 'Husband',\n                'body' => 'records'\n            ])\n            ->andReturn([\n                'errors' => true,\n                'items' => [\n                    [\n                        'index' => [\n                            'error' => true\n                        ]\n                    ]\n                ]\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->bulk('records');\n        $index->setName('bar_Husband');\n        $index->bulk('records');;\n    }\n\n    /**\n     * @test\n     * @expectedException \\Iverberk\\Larasearch\\Exceptions\\ImportException\n     */\n    public function it_should_store_records_having_explicit_prefix_in_bulk_with_errors()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $proxy->shouldReceive('getType')->andReturn('Husband');\n\n        $client->shouldReceive('bulk')\n            ->with([\n                'index' => 'bar_husband',\n                'type' => 'Husband',\n                'body' => 'records'\n            ])\n            ->andReturn([\n                'errors' => true,\n                'items' => [\n                    [\n                        'index' => [\n                            'error' => true\n                        ]\n                    ]\n                ]\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->setName('bar_Husband');\n        $index->bulk('records');;\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_store_a_records_in_bulk_without_errors()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $proxy->shouldReceive('getType')->andReturn('Husband');\n\n        $client->shouldReceive('bulk')\n            ->with([\n                'index' => 'husband',\n                'type' => 'Husband',\n                'body' => 'records'\n            ])\n            ->andReturn([\n                'errors' => false\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->bulk('records');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_store_a_records_having_index_prefix_in_bulk_without_errors()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $proxy->shouldReceive('getType')->andReturn('Husband');\n\n        $client->shouldReceive('bulk')\n            ->twice()\n            ->with([\n                'index' => 'bar_husband',\n                'type' => 'Husband',\n                'body' => 'records'\n            ])\n            ->andReturn([\n                'errors' => false\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $index->bulk('records');\n        $index->setName('bar_Husband');\n        $index->bulk('records');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_clean_old_indices()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        // Mock the self::$client variable\n        am::double('Iverberk\\Larasearch\\Index', ['self::$client' => $client]);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->getAliases')\n            ->andReturn([\n                'index_123456789101112' => [\n                    'aliases' => []\n                ]\n            ]);\n\n        $client->shouldReceive('indices->delete')\n            ->with([\n                'index' => 'index_123456789101112'\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        Index::clean('index');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_clean_old_indices_with_index_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        // Mock the self::$client variable\n        am::double('Iverberk\\Larasearch\\Index', ['self::$client' => $client]);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->getAliases')\n            ->twice()\n            ->andReturn([\n                'bar_index_123456789101112' => [\n                    'aliases' => []\n                ]\n            ]);\n\n        $client->shouldReceive('indices->delete')\n            ->twice()\n            ->with([\n                'index' => 'bar_index_123456789101112'\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        Index::clean('index');\n        Index::clean('bar_index');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_update_aliases()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        // Mock the self::$client variable\n        am::double('Iverberk\\Larasearch\\Index', ['self::$client' => $client]);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->updateAliases')\n            ->with([\n                'body' => ['actions' => []]\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        Index::updateAliases(['actions' => []]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_update_aliases_with_index_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        // Mock the self::$client variable\n        am::double('Iverberk\\Larasearch\\Index', ['self::$client' => $client]);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->updateAliases')\n            ->twice()\n            ->with([\n                'body' => ['actions' => [['add' => ['index' => 'bar_Husband', 'alias' => 'bar_Father']]]]\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        Index::updateAliases(['actions' => [['add' => ['index' => 'Husband', 'alias' => 'Father']]]]);\n        Index::updateAliases(['actions' => [['add' => ['index' => 'bar_Husband', 'alias' => 'bar_Father']]]]);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_aliases()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        // Mock the self::$client variable\n        am::double('Iverberk\\Larasearch\\Index', ['self::$client' => $client]);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->getAlias')\n            ->with([\n                'name' => 'mock'\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        Index::getAlias('mock');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_aliases_with_an_index_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        // Mock the self::$client variable\n        am::double('Iverberk\\Larasearch\\Index', ['self::$client' => $client]);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->getAlias')\n            ->twice()\n            ->with([\n                'name' => 'bar_mock'\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        Index::getAlias('mock');\n        Index::getAlias('bar_mock');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_refresh()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks();\n\n        // Mock the self::$client variable\n        am::double('Iverberk\\Larasearch\\Index', ['self::$client' => $client]);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->refresh')\n            ->with([\n                'index' => 'mock'\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        Index::refresh('mock');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_refresh_with_an_index_prefix()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $index\n         * @var \\Mockery\\Mock $proxy\n         * @var \\Mockery\\Mock $client\n         */\n        list($index, $proxy, $client) = $this->getMocks('bar_');\n\n        // Mock the self::$client variable\n        am::double('Iverberk\\Larasearch\\Index', ['self::$client' => $client]);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('indices->refresh')\n            ->twice()\n            ->with([\n                'index' => 'bar_mock'\n            ]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        Index::refresh('mock');\n        Index::refresh('bar_mock');\n    }\n\n    /**\n     * Construct an Index mock\n     *\n     * @return array\n     */\n    private function getMocks($index_prefix = '')\n    {\n        /**\n         *\n         * Expectation\n         *\n         */\n        Facade::clearResolvedInstances();\n\n        $client = m::mock('Elasticsearch\\Client');\n\n        App::shouldReceive('make')\n            ->with('Elasticsearch')\n            ->andReturn($client);\n\n        Config::shouldReceive('get')\n            ->with('larasearch.elasticsearch.index_prefix', '')\n            ->andReturn($index_prefix);\n\n        $proxy = m::mock('Iverberk\\Larasearch\\Proxy');\n        $proxy->shouldReceive('getModel->getTable')\n            ->andReturn('Husband');\n\n        $index = m::mock('Iverberk\\Larasearch\\Index', [$proxy], [m::BLOCKS => ['setName', 'setProxy']])->makePartial();\n\n        return [$index, $proxy, $client];\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Jobs/DeleteJobTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Jobs;\n\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nclass DeleteJobTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n        am::clean();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_job()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n\t    $app = m::mock('Illuminate\\Foundation\\Application');\n\t    $config = m::mock('Iverberk\\Larasearch\\Config');\n\t    $logger = m::mock('Monolog\\Logger');\n\t    am::double('Husband', ['deleteDoc' => true]);\n\n        $job = m::mock('Illuminate\\Queue\\Jobs\\Job');\n        $models = [\n            'Husband:999'\n        ];\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $logger->shouldReceive('info')->with('Deleting Husband with ID: 999 from Elasticsearch');\n        $config->shouldReceive('get')->with('logger', 'iverberk.larasearch.logger')->andReturn('iverberk.larasearch.logger');\n        $app->shouldReceive('make')->with('iverberk.larasearch.logger')->andReturn($logger);\n        $job->shouldReceive('delete')->once();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        with(new DeleteJob($app, $config))->fire($job, $models);\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Jobs/ReindexJobTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Jobs;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Mockery as m;\nuse AspectMock\\Test as am;\nuse Mockery;\n\nclass ReindexJobTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n        am::clean();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_job_with_unresolvable_models()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.proxy', Mockery::any())\n            ->once()\n            ->andReturn('mock');\n\n        $app = m::mock('Illuminate\\Foundation\\Application');\n        $config = m::mock('Illuminate\\Config\\Repository');\n        $logger = m::mock('Monolog\\Logger');\n        $job = m::mock('Illuminate\\Queue\\Jobs\\Job');\n        $models = [\n            'Husband:99999'\n        ];\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $logger->shouldReceive('info')->with('Indexing Husband with ID: 99999');\n        $logger->shouldReceive('error')->with('Indexing Husband with ID: 99999 failed: No query results for model [Husband].');\n        $config->shouldReceive('get')->with('larasearch.logger')->andReturn('iverberk.larasearch.logger');\n        $app->shouldReceive('make')->with('iverberk.larasearch.logger')->andReturn($logger);\n        $job->shouldReceive('delete')->once();\n        $job->shouldReceive('release')->with(60)->once();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        with(new ReindexJob($app, $config))->fire($job, $models);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_fire_job_with_resolvable_models()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $app = m::mock('Illuminate\\Foundation\\Application');\n        $config = m::mock('Illuminate\\Config\\Repository');\n        $logger = m::mock('Monolog\\Logger');\n        $model = m::mock('Husband');\n        $model->shouldReceive('refreshDoc')->with($model)->once();\n        $husband = am::double('Husband', ['findOrFail' => $model]);\n        $models = [\n            'Husband:999'\n        ];\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $logger->shouldReceive('info')->with('Indexing Husband with ID: 999');\n        $config->shouldReceive('get')->with('larasearch.logger')->andReturn('iverberk.larasearch.logger');\n        $app->shouldReceive('make')->with('iverberk.larasearch.logger')->andReturn($logger);\n        $job = m::mock('Illuminate\\Queue\\Jobs\\Job');\n        $job->shouldReceive('delete')->once();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        with(new ReindexJob($app, $config))->fire($job, $models);\n\n        // $husband->verifyInvoked('findOrFail');\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/LarasearchServiceProviderTest.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Config;\nuse Mockery as m;\n\nfunction base_path($path = null)\n{\n    return LarasearchServiceProviderTest::$functions->base_path($path);\n}\n\n/**\n * Class LarasearchServiceProviderTest\n */\nclass LarasearchServiceProviderTest extends \\PHPUnit_Framework_TestCase {\n\n    public static $functions;\n    protected static $providers_real_path;\n\n    protected function setup()\n    {\n        self::$functions = m::mock();\n        self::$functions->shouldReceive('base_path')->andReturn('');\n        self::$providers_real_path = realpath(__DIR__ . '/../../../src/Iverberk/Larasearch');\n    }\n\n    protected function tearDown()\n    {\n        m::close();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_boot()\n    {\n        /**\n         * Set\n         */\n        $sp = m::mock('Iverberk\\Larasearch\\LarasearchServiceProvider[bootContainerBindings, publishes]', ['something']);\n        $sp->shouldAllowMockingProtectedMethods();\n\n        /**\n         * Expectation\n         */\n        $sp->shouldReceive('publishes')\n            ->with([\n                self::$providers_real_path . '/../../config/larasearch.php' => base_path('config/larasearch.php'),\n            ], 'config')\n            ->once();\n\n        $sp->shouldReceive('bootContainerBindings')\n            ->once();\n\n        /**\n         * Assertion\n         */\n        $sp->boot();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_boot_container_bindings()\n    {\n        /**\n         * Set\n         */\n        $sp = m::mock('Iverberk\\Larasearch\\LarasearchServiceProvider[' .\n            'bindProxy, bindIndex, bindLogger, bindElasticsearch, bindQuery, bindResult]', ['something']);\n        $sp->shouldAllowMockingProtectedMethods();\n\n        /**\n         * Expectation\n         */\n        $sp->shouldReceive('bindElasticsearch')->once()->andReturn(true);\n        $sp->shouldReceive('bindLogger')->once()->andReturn(true);\n        $sp->shouldReceive('bindProxy')->once()->andReturn(true);\n        $sp->shouldReceive('bindIndex')->once()->andReturn(true);\n        $sp->shouldReceive('bindQuery')->once()->andReturn(true);\n        $sp->shouldReceive('bindResult')->once()->andReturn(true);\n\n        /**\n         * Assertions\n         */\n        $sp->bootContainerBindings();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_bind_elasticsearch()\n    {\n        /**\n         * Set\n         */\n        $app = m::mock('LaravelApp');\n        $sp = m::mock('Iverberk\\Larasearch\\LarasearchServiceProvider[bindElasticsearch]', [$app]);\n\n        /**\n         * Expectation\n         */\n        Config::shouldReceive('get')\n            ->with('larasearch.elasticsearch.params')\n            ->once()\n            ->andReturn([]);\n\n        $app->shouldReceive('singleton')\n            ->once()\n            ->andReturnUsing(\n                function ($name, $closure) use ($app)\n                {\n                    $this->assertEquals('Elasticsearch', $name);\n                    $this->assertInstanceOf('Elasticsearch\\Client', $closure($app));\n                }\n            );\n\n        $sp->bindElasticsearch();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_bind_logger()\n    {\n        /**\n         * Set\n         */\n        $app = m::mock('LaravelApp');\n        $sp = m::mock('Iverberk\\Larasearch\\LarasearchServiceProvider[bindLogger]', [$app]);\n\n        /**\n         * Expectation\n         */\n        $app->shouldReceive('singleton')\n            ->once()\n            ->andReturnUsing(\n                function ($name, $closure) use ($app)\n                {\n                    $this->assertEquals('iverberk.larasearch.logger', $name);\n                    $this->assertInstanceOf('Monolog\\Logger', $closure($app));\n                }\n            );\n\n        $sp->bindLogger();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_bind_index()\n    {\n        /**\n         * Set\n         */\n        App::clearResolvedInstances();\n        Config::clearResolvedInstances();\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.index', m::any())\n            ->once()\n            ->andReturn('mock');\n\n        App::shouldReceive('make')\n            ->with('Elasticsearch')\n            ->twice()\n            ->andReturn('mock');\n\n        Config::shouldReceive('get')\n            ->with('larasearch.elasticsearch.index_prefix', '')\n            ->andReturn('');\n\n        $model = m::mock('Illuminate\\Database\\Eloquent\\Model');\n        $model->shouldReceive('getTable')\n            ->once()\n            ->andReturn('mockType');\n        $app = m::mock('LaravelApp');\n        $proxy = m::mock('Iverberk\\Larasearch\\Proxy', [$model]);\n        $sp = m::mock('Iverberk\\Larasearch\\LarasearchServiceProvider[bindIndex]', [$app]);\n\n        /**\n         * Expectation\n         */\n        $app->shouldReceive('bind')\n            ->once()\n            ->andReturnUsing(\n                function ($name, $closure) use ($app, $proxy)\n                {\n                    $this->assertEquals('iverberk.larasearch.index', $name);\n                    $this->assertInstanceOf('Iverberk\\Larasearch\\Index',\n                        $closure($app, ['proxy' => $proxy, 'name' => 'name']));\n                }\n            );\n\n\n        /**\n         * Assertion\n         */\n        $sp->bindIndex();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_bind_query()\n    {\n        /**\n         * Set\n         */\n        $model = m::mock('Illuminate\\Database\\Eloquent\\Model');\n        $model->shouldReceive('getTable')\n            ->once()\n            ->andReturn('mockType');\n        $app = m::mock('LaravelApp');\n        $proxy = m::mock('Iverberk\\Larasearch\\Proxy', [$model]);\n        $sp = m::mock('Iverberk\\Larasearch\\LarasearchServiceProvider[bindQuery]', [$app]);\n\n        /**\n         * Expectation\n         */\n        $app->shouldReceive('bind')\n            ->once()\n            ->andReturnUsing(\n                function ($name, $closure) use ($app, $proxy)\n                {\n                    $this->assertEquals('iverberk.larasearch.query', $name);\n                    $this->assertInstanceOf('Iverberk\\Larasearch\\Query',\n                        $closure($app, ['proxy' => $proxy, 'term' => 'term', 'options' => []]));\n                }\n            );\n\n        /**\n         * Assertion\n         */\n        $sp->bindQuery();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_bind_proxy()\n    {\n        /**\n         * Set\n         */\n        $model = m::mock('Illuminate\\Database\\Eloquent\\Model');\n        $model->shouldReceive('getTable')\n            ->once()\n            ->andReturn('mockType');\n        $app = m::mock('LaravelApp');\n        $sp = m::mock('Iverberk\\Larasearch\\LarasearchServiceProvider[bindProxy]', [$app]);\n\n        /**\n         * Expectation\n         */\n        $app->shouldReceive('bind')\n            ->once()\n            ->andReturnUsing(\n                function ($name, $closure) use ($app, $model)\n                {\n                    $this->assertEquals('iverberk.larasearch.proxy', $name);\n                    $this->assertInstanceOf('Iverberk\\Larasearch\\Proxy',\n                        $closure($app, $model));\n                }\n            );\n\n\n        /**\n         * Assertion\n         */\n        $sp->bindProxy();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_bind_result()\n    {\n        /**\n         * Set\n         */\n        $app = m::mock('LaravelApp');\n        $sp = m::mock('Iverberk\\Larasearch\\LarasearchServiceProvider[bindResult]', [$app]);\n\n        /**\n         * Expectation\n         */\n        $app->shouldReceive('bind')\n            ->once()\n            ->andReturnUsing(\n                function ($name, $closure) use ($app)\n                {\n                    $this->assertEquals('iverberk.larasearch.response.result', $name);\n                    $this->assertInstanceOf('Iverberk\\Larasearch\\Response\\Result',\n                        $closure($app, []));\n                }\n            );\n\n        /**\n         * Assertion\n         */\n        $sp->bindResult();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_register_commands()\n    {\n        /**\n         * Set\n         */\n        $app = m::mock('Illuminate\\Container\\Container');\n        $sp = m::mock('Iverberk\\Larasearch\\LarasearchServiceProvider[commands, mergeConfigFrom]', [$app]);\n        $sp->shouldAllowMockingProtectedMethods();\n\n        /**\n         * Expectation\n         */\n        $app->shouldReceive('offsetSet')->andReturn(true);\n        $app->shouldReceive('offsetGet')->andReturn(true);\n\n        $app->shouldReceive('share')\n            ->once()\n            ->andReturnUsing(function ($closure) use ($app)\n            {\n                $this->assertInstanceOf('Iverberk\\Larasearch\\Commands\\ReindexCommand', $closure($app));\n            });\n\n        $app->shouldReceive('share')\n            ->once()\n            ->andReturnUsing(function ($closure) use ($app)\n            {\n                $this->assertInstanceOf('Iverberk\\Larasearch\\Commands\\PathsCommand', $closure($app));\n            });\n\n        $sp->shouldReceive('commands')\n            ->with('iverberk.larasearch.commands.reindex')\n            ->once()\n            ->andReturn(true);\n\n        $sp->shouldReceive('commands')\n            ->with('iverberk.larasearch.commands.paths')\n            ->once()\n            ->andReturn(true);\n\n        $sp->shouldReceive('mergeConfigFrom')\n            ->with(self::$providers_real_path . '/../../config/larasearch.php', 'larasearch')\n            ->once();\n\n        /**\n         * Assertion\n         */\n        $sp->register();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_provide_services()\n    {\n        /**\n         * Set\n         */\n        $app = m::mock('LaravelApp');\n\n        /**\n         * Assertion\n         */\n        $sp = new LarasearchServiceProvider($app);\n        $this->assertEquals([], $sp->provides());\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/ObserverTest.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Husband;\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Facade;\nuse Illuminate\\Support\\Facades\\Queue;\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nclass ObserverTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n        am::clean();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_not_reindex_on_model_save()\n    {\n        /**\n         *\n         * Expectation\n         *\n         */\n        $queue = am::double('Illuminate\\Support\\Facades\\Queue', ['push' => null]);\n\n        $husband = m::mock('Husband');\n        $husband->shouldReceive('shouldIndex')->andReturn(false);\n\n        /**\n         *\n         *\n         * Assertion\n         *\n         */\n        with(new Observer)->saved($husband);\n\n        $queue->verifyNeverInvoked('push');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_reindex_on_model_save()\n    {\n        /**\n         *\n         * Expectation\n         *\n         */\n        Facade::clearResolvedInstances();\n\n        $proxy = m::mock('Iverberk\\Larasearch\\Proxy');\n        $proxy->shouldReceive('shouldIndex')->andReturn(true);\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.proxy', m::type('Illuminate\\Database\\Eloquent\\Model'))\n            ->andReturn($proxy);\n\n        Config::shouldReceive('get')\n            ->with('larasearch.reversedPaths.Husband', [])\n            ->once()\n            ->andReturn(['', 'wife', 'children', 'children.toys']);\n\n        Queue::shouldReceive('push')\n            ->with('Iverberk\\Larasearch\\Jobs\\ReindexJob', [\n                'Husband:2',\n                'Wife:2',\n                'Child:2',\n                'Toy:2'\n            ])->once();\n\n        /**\n         *\n         *\n         * Assertion\n         *\n         */\n        $husband = \\Husband::find(2);\n        $husband->clearProxy();\n\n        with(new Observer)->saved($husband);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        Facade::clearResolvedInstances();\n\n        $proxy = m::mock('Iverberk\\Larasearch\\Proxy');\n        $proxy->shouldReceive('shouldIndex')->andReturn(true);\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.proxy', m::type('Illuminate\\Database\\Eloquent\\Model'))\n            ->andReturn($proxy);\n\n        Config::shouldReceive('get')\n            ->with('larasearch.reversedPaths.Toy', [])\n            ->once()\n            ->andReturn(['', 'children', 'children.mother.husband', 'children.mother']);\n\n        Queue::shouldReceive('push')\n            ->with('Iverberk\\Larasearch\\Jobs\\ReindexJob', [\n                'Toy:2',\n                'Child:8',\n                'Child:2',\n                'Husband:8',\n                'Husband:2',\n                'Wife:8',\n                'Wife:2'\n            ])->once();\n\n        /**\n         *\n         *\n         * Assertion\n         *\n         */\n        $toy = \\Toy::find(2);\n\n        with(new Observer)->saved($toy);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_reindex_on_model_delete()\n    {\n        /**\n         *\n         * Expectation\n         *\n         */\n        Facade::clearResolvedInstances();\n\n        Queue::shouldReceive('push')\n            ->with('Iverberk\\Larasearch\\Jobs\\DeleteJob', ['Husband:2'])\n            ->once();\n\n        Queue::shouldReceive('push')\n            ->with('Iverberk\\Larasearch\\Jobs\\ReindexJob', ['Wife:2', 'Child:2', 'Toy:2'])\n            ->once();\n\n        Config::shouldReceive('get')\n            ->with('/^larasearch.reversedPaths\\..*$/', [])\n            ->once()\n            ->andReturn(['', 'wife', 'children', 'children.toys']);\n\n        $husband = \\Husband::find(2);\n\n        with(new Observer)->deleted($husband);\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/ProxyTest.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Facade;\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nfunction date()\n{\n    return ProxyTest::$functions->date();\n}\n\nclass ProxyTest extends \\PHPUnit_Framework_TestCase {\n\n    /**\n     * @var \\Mockery\\Mock\n     */\n    private $proxy;\n\n    /**\n     * @var \\Mockery\\Mock\n     */\n    private $model;\n\n    /**\n     * @var \\Mockery\\Mock\n     */\n    private $index;\n\n    /**\n     * @var \\Mockery\\Mock\n     */\n    private $client;\n\n    /**\n     * @var \\Mockery\\Mock\n     */\n    public static $functions;\n\n    protected function setUp()\n    {\n        parent::setUp();\n\n        self::$functions = m::mock();\n\n        $this->index = m::mock('Iverberk\\Larasearch\\Index');\n        $this->model = m::mock('Husband')->makePartial();\n        $this->client = m::mock('Elasticsearch\\Client');\n\n        $this->model->shouldReceive('getTable')\n            ->once()\n            ->andReturn('Husbands');\n\n        Facade::clearResolvedInstances();\n        App::shouldReceive('make')\n            ->with('Elasticsearch')\n            ->once()\n            ->andReturn($this->client);\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.index', m::type('array'))\n            ->once()\n            ->andReturn($this->index);\n\n        $this->proxy = new Proxy($this->model);\n\n        self::$functions->shouldReceive('date')->andReturn('9999');\n    }\n\n    protected function tearDown()\n    {\n        m::close();\n        am::clean();\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_get_config()\n    {\n        $this->assertEquals([\n                'model' => $this->model,\n                'type' => 'Husband',\n                'client' => $this->client,\n                'index' => $this->index,\n                'autocomplete' => ['name', 'wife.name'],\n                'suggest' => ['name'],\n                'text_start' => ['name', 'wife.children.name'],\n                'text_middle' => ['name', 'wife.children.name'],\n                'text_end' => ['name', 'wife.children.name'],\n                'word_start' => ['name', 'wife.children.name'],\n                'word_middle' => ['name', 'wife.children.name'],\n                'word_end' => ['name', 'wife.children.name']\n            ],\n            $this->proxy->getConfig());\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_get_model()\n    {\n        $this->assertEquals($this->model, $this->proxy->getModel());\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_get_index()\n    {\n        $this->assertEquals($this->index, $this->proxy->getIndex());\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_get_type()\n    {\n        $this->assertEquals('Husband', $this->proxy->getType());\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_get_client()\n    {\n        $this->assertEquals($this->client, $this->proxy->getClient());\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_search()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $query = m::mock('Iverberk\\Larasearch\\Query');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $query->shouldReceive('execute')->andReturn('result');\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.query', ['proxy' => $this->proxy, 'term' => '*', 'options' => ['option']])\n            ->once()\n            ->andReturn($query);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $result = $this->proxy->search('*', ['option']);\n\n        $this->assertEquals('result', $result);\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_search_with_a_query()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $queryMock = m::mock('Iverberk\\Larasearch\\Query');\n\n        $query['index'] = 'my_index';\n        $query['type'] = 'my_type';\n        $query['body']['query']['match']['testField'] = 'abc';\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $queryMock->shouldReceive('execute')->andReturn('result');\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.query', [\n                'proxy' => $this->proxy,\n                'term' => null,\n                'options' => array_merge(['query' => $query], ['option'])])\n            ->once()\n            ->andReturn($queryMock);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $result = $this->proxy->searchByQuery($query, ['option']);\n\n        $this->assertEquals('result', $result);\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_search_for_a_single_document()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $query['index'] = 'my_index';\n        $query['type'] = 'my_type';\n        $query['id'] = 'abc';\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $this->index->shouldReceive('getName')->andReturn('index');\n        $this->client->shouldReceive('get')->andReturn(['hit']);\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.response.result', ['hit'])\n            ->once()\n            ->andReturn('result');\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $result = $this->proxy->searchById('abc');\n\n        $this->assertEquals('result', $result);\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_reindex_when_alias_does_not_exist()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $indexDouble = am::double('Iverberk\\Larasearch\\Index', ['refresh' => null, 'clean' => null, 'updateAliases' => null]);\n        $indexMock = m::mock('Iverberk\\Larasearch\\Index');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $this->index->shouldReceive('getName')->andReturn('Husband');\n        $this->index->shouldReceive('exists')->once()->andReturn(true);\n        $this->index->shouldReceive('delete')->once()->andReturn();\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.index', ['name' => 'Husband_9999', 'proxy' => $this->proxy])\n            ->andReturn($indexMock);\n\n        $indexMock->shouldReceive('create')->once()->andReturn();\n        $indexMock->shouldReceive('aliasExists')->once()->andReturn(false);\n        $indexMock->shouldReceive('import')->andReturn();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->proxy->reindex();\n\n        $indexDouble->verifyInvoked('refresh', 'Husband');\n        $indexDouble->verifyInvoked('clean', 'Husband');\n    }\n\n    /**\n     * @test\n     */\n    public function it_can_reindex_when_alias_exists()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $indexDouble = am::double('Iverberk\\Larasearch\\Index', [\n            'refresh' => null,\n            'clean' => null,\n            'updateAliases' => null,\n            'getAlias' => ['mockIndex' => 'aliases']\n        ]);\n        $indexMock = m::mock('Iverberk\\Larasearch\\Index');\n\n        $operations[] = [\n            'add' => [\n                'alias' => 'Husband',\n                'index' => 'Husband_9999'\n            ],\n            'remove' => [\n                'alias' => 'Husband',\n                'index' => 'mockIndex'\n            ]\n        ];\n\n        $actions[] = ['actions' => $operations];\n        $test = $this;\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $this->index->shouldReceive('getName')->andReturn('Husband');\n\n        $indexMock->shouldReceive('create')->once()->andReturn();\n        $indexMock->shouldReceive('aliasExists')->once()->andReturn(true);\n        $indexMock->shouldReceive('import')->andReturn();\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.index', ['name' => 'Husband_9999', 'proxy' => $this->proxy])\n            ->andReturn($indexMock);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->proxy->reindex();\n\n        $indexDouble->verifyInvoked('refresh', 'Husband');\n        $indexDouble->verifyInvoked('clean', 'Husband');\n        $indexDouble->verifyInvoked('updateAliases', function ($calls) use ($test, $actions)\n        {\n            $test->assertEquals($actions, $calls[0]);\n        });\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_index()\n    {\n        $this->assertEquals(true, $this->proxy->shouldIndex());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_refresh_docs()\n    {\n        /**\n         *\n         * Expectation\n         *\n         */\n        $this->model->shouldReceive('transform')\n            ->with(true)\n            ->andReturn('body');\n\n        $this->model->shouldReceive('getEsId')\n            ->andReturn(1);\n\n        $this->client->shouldReceive('index')\n            ->with([\n                'id' => '1',\n                'index' => 'Husband',\n                'type' => 'Husband',\n                'body' => 'body'\n            ])\n            ->andReturn();\n\n        $this->index->shouldReceive('getName')\n            ->andReturn('Husband');\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->proxy->refreshDoc($this->model);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_delete_docs()\n    {\n        /**\n         *\n         * Expectation\n         *\n         */\n        $this->client->shouldReceive('delete')\n            ->with([\n                'id' => 1,\n                'index' => 'Husband',\n                'type' => 'Husband'\n            ])\n            ->andReturn();\n\n        $this->index->shouldReceive('getName')\n            ->andReturn('Husband');\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->proxy->deleteDoc(1);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_enable_indexing_globally()\n    {\n        /**\n         * Assertions\n         */\n        $this->proxy->enableIndexing();\n\n        $this->assertEquals(\\Husband::$__es_enable, true);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_disable_indexing_globally()\n    {\n        /**\n         * Assertions\n         */\n        $this->proxy->disableIndexing();\n\n        $this->assertEquals(\\Husband::$__es_enable, false);\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/QueryTest.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nclass QueryTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n        am::clean();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_with_term()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [$proxy, 'term'])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                      \"index\": \"Husband\",\n                      \"type\": \"Husband\",\n                      \"body\": {\n                        \"size\": 50,\n                        \"from\": 0,\n                        \"query\": {\n                          \"dis_max\": {\n                            \"queries\": [\n                              {\n                                \"match\": {\n                                  \"_all\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search\"\n                                  }\n                                }\n                              },\n                              {\n                                \"match\": {\n                                  \"_all\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search2\"\n                                  }\n                                }\n                              }\n                            ]\n                          }\n                        }\n                      }\n                    }', true)\n                    ,\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_on_term_with_exact_field()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            'term',\n            [\n                'fields' => ['name' => 'exact']\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                      \"index\": \"Husband\",\n                      \"type\": \"Husband\",\n                      \"body\": {\n                        \"size\": 50,\n                        \"from\": 0,\n                        \"query\": {\n                          \"dis_max\": {\n                            \"queries\": [\n                              {\n                                \"match\": {\n                                  \"name\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 1,\n                                    \"analyzer\": \"keyword\"\n                                  }\n                                }\n                              }\n                            ]\n                          }\n                        }\n                      }\n                    }', true)\n                    ,\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_with_term_and_misspellings()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            'term',\n            [\n                'misspellings' => true\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                      \"index\": \"Husband\",\n                      \"type\": \"Husband\",\n                      \"body\": {\n                        \"size\": 50,\n                        \"from\": 0,\n                        \"query\": {\n                          \"dis_max\": {\n                            \"queries\": [\n                              {\n                                \"match\": {\n                                  \"_all\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search\"\n                                  }\n                                }\n                              },\n                              {\n                                \"match\": {\n                                  \"_all\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search2\"\n                                  }\n                                }\n                              },\n                              {\n                                \"match\": {\n                                  \"_all\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 1,\n                                    \"fuzziness\": 1,\n                                    \"max_expansions\": 3,\n                                    \"analyzer\": \"larasearch_search\"\n                                  }\n                                }\n                              },\n                              {\n                                \"match\": {\n                                  \"_all\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 1,\n                                    \"fuzziness\": 1,\n                                    \"max_expansions\": 3,\n                                    \"analyzer\": \"larasearch_search2\"\n                                  }\n                                }\n                              }\n                            ]\n                          }\n                        }\n                      }\n                    }', true),\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_on_fields_with_term()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            'term',\n            [\n                'fields' => ['name' => 'word_start', 'wife.name']\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                      \"index\": \"Husband\",\n                      \"type\": \"Husband\",\n                      \"body\": {\n                        \"size\": 50,\n                        \"from\": 0,\n                        \"query\": {\n                          \"dis_max\": {\n                            \"queries\": [\n                              {\n                                \"match\": {\n                                  \"name.word_start\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 1,\n                                    \"analyzer\": \"larasearch_word_search\"\n                                  }\n                                }\n                              },\n                              {\n                                \"match\": {\n                                  \"wife.name.analyzed\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search\"\n                                  }\n                                }\n                              },\n                              {\n                                \"match\": {\n                                  \"wife.name.analyzed\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search2\"\n                                  }\n                                }\n                              }\n                            ]\n                          }\n                        }\n                      }\n                    }', true)\n                    ,\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_on_term_with_autocomplete()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            'term',\n            [\n                'autocomplete' => true\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                      \"index\": \"Husband\",\n                      \"type\": \"Husband\",\n                      \"body\": {\n                        \"size\": 50,\n                        \"from\": 0,\n                        \"query\": {\n                          \"multi_match\": {\n                            \"fields\": [\n                              \"name.autocomplete\",\n                              \"wife.name.autocomplete\"\n                            ],\n                            \"query\": \"term\",\n                            \"analyzer\": \"larasearch_autocomplete_search\"\n                          }\n                        }\n                      }\n                    }', true)\n                    ,\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_on_fields_with_term_and_autocomplete()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            'term',\n            [\n                'fields' => ['wife.name'],\n                'autocomplete' => true\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                          \"index\": \"Husband\",\n                          \"type\": \"Husband\",\n                          \"body\": {\n                            \"size\": 50,\n                            \"from\": 0,\n                            \"query\": {\n                              \"multi_match\": {\n                                \"fields\": [\n                                  \"wife.name.autocomplete\"\n                                ],\n                                \"query\": \"term\",\n                                \"analyzer\": \"larasearch_autocomplete_search\"\n                              }\n                            }\n                          }\n                        }', true)\n                    ,\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_on_fields_with_term_and_select()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            'term',\n            [\n                'fields' => ['wife.name'],\n                'select' => ['name']\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                      \"index\": \"Husband\",\n                      \"type\": \"Husband\",\n                      \"body\": {\n                        \"size\": 50,\n                        \"from\": 0,\n                        \"query\": {\n                          \"dis_max\": {\n                            \"queries\": [\n                              {\n                                \"match\": {\n                                  \"wife.name.analyzed\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search\"\n                                  }\n                                }\n                              },\n                              {\n                                \"match\": {\n                                  \"wife.name.analyzed\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search2\"\n                                  }\n                                }\n                              }\n                            ]\n                          }\n                        },\n                        \"fields\": [\n                          \"name\"\n                        ]\n                      }\n                    }', true)\n                    ,\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_on_fields_with_term_and_load()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            'term',\n            [\n                'fields' => ['wife.name'],\n                'load' => ['name']\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                          \"index\": \"Husband\",\n                          \"type\": \"Husband\",\n                          \"body\": {\n                            \"size\": 50,\n                            \"from\": 0,\n                            \"query\": {\n                              \"dis_max\": {\n                                \"queries\": [\n                                  {\n                                    \"match\": {\n                                      \"wife.name.analyzed\": {\n                                        \"query\": \"term\",\n                                        \"operator\": \"and\",\n                                        \"boost\": 10,\n                                        \"analyzer\": \"larasearch_search\"\n                                      }\n                                    }\n                                  },\n                                  {\n                                    \"match\": {\n                                      \"wife.name.analyzed\": {\n                                        \"query\": \"term\",\n                                        \"operator\": \"and\",\n                                        \"boost\": 10,\n                                        \"analyzer\": \"larasearch_search2\"\n                                      }\n                                    }\n                                  }\n                                ]\n                              }\n                            },\n                            \"fields\": [\n                              \"name\"\n                            ]\n                          }\n                        }', true)\n                    ,\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_on_fields_and_highlight()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            'term',\n            [\n                'fields' => ['name'],\n                'highlight' => [\n                    'tag' => '<b>'\n                ]\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $query = json_decode(\n                    '{\n                      \"index\": \"Husband\",\n                      \"type\": \"Husband\",\n                      \"body\": {\n                        \"size\": 50,\n                        \"from\": 0,\n                        \"highlight\": {\n                          \"fields\": {\n                            \"name.analyzed\": {}\n                          },\n                          \"pre_tags\": [\n                            \"<b>\"\n                          ],\n                          \"post_tags\": [\n                            \"<\\/b>\"\n                          ]\n                        },\n                        \"query\": {\n                          \"dis_max\": {\n                            \"queries\": [\n                              {\n                                \"match\": {\n                                  \"name.analyzed\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search\"\n                                  }\n                                }\n                              },\n                              {\n                                \"match\": {\n                                  \"name.analyzed\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search2\"\n                                  }\n                                }\n                              }\n                            ]\n                          }\n                        }\n                      }\n                    }', true);\n\n                // Mark explicit stdclass\n                $query['body']['highlight']['fields']['name.analyzed'] = new \\StdClass;\n                $test->assertEquals(\n                    $query,\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_on_fields_with_suggestions()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            'term',\n            [\n                'fields' => ['name'],\n                'suggest' => true\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                      \"index\": \"Husband\",\n                      \"type\": \"Husband\",\n                      \"body\": {\n                        \"size\": 50,\n                        \"from\": 0,\n                        \"suggest\": {\n                          \"text\": \"term\",\n                          \"name\": {\n                            \"phrase\": {\n                              \"field\": \"name.suggest\"\n                            }\n                          }\n                        },\n                        \"query\": {\n                          \"dis_max\": {\n                            \"queries\": [\n                              {\n                                \"match\": {\n                                  \"name.analyzed\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search\"\n                                  }\n                                }\n                              },\n                              {\n                                \"match\": {\n                                  \"name.analyzed\": {\n                                    \"query\": \"term\",\n                                    \"operator\": \"and\",\n                                    \"boost\": 10,\n                                    \"analyzer\": \"larasearch_search2\"\n                                  }\n                                }\n                              }\n                            ]\n                          }\n                        }\n                      }\n                    }', true),\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_with_aggregations()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            '*',\n            [\n                'aggs' => [\n                    'agg_name' => [\n                        'type' => 'terms',\n                        'field' => 'name'\n                    ]\n                ]\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                        '{\n                      \"index\": \"Husband\",\n                      \"type\": \"Husband\",\n                      \"body\": {\n                        \"size\": 50,\n                        \"from\": 0,\n                        \"aggs\": {\n                          \"agg_name\": {\n                            \"terms\": {\n                              \"field\": \"name\",\n                              \"size\": 0\n                            }\n                          }\n                        },\n                        \"query\": {\n                          \"match_all\": [\n\n                          ]\n                        }\n                      }\n                    }', true),\n                    $params);\n\n                return [];\n            });\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_search_with_sort()\n    {\n        /**\n         * Set\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [$proxy, 'term', ['sort' => 'name']])->makePartial();\n\n        /**\n         * Expectation\n         */\n\n        $client->shouldReceive('search')\n            ->andReturnUsing(function ($params) use ($test)\n            {\n                $test->assertEquals(json_decode(\n                    '{\n                        \"index\": \"Husband\",\n                        \"type\": \"Husband\",\n                        \"body\": {\n                            \"size\": 50,\n                            \"from\": 0,\n                            \"sort\": \"name\",\n                            \"query\": {\n                                \"dis_max\": {\n                                    \"queries\": [\n                                        {\n                                            \"match\": {\n                                                \"_all\": {\n                                                    \"query\": \"term\",\n                                                    \"operator\": \"and\",\n                                                    \"boost\": 10,\n                                                    \"analyzer\": \"larasearch_search\"\n                                                }\n                                            }\n                                        },\n                                        {\n                                            \"match\": {\n                                                \"_all\": {\n                                                    \"query\": \"term\",\n                                                    \"operator\": \"and\",\n                                                    \"boost\": 10,\n                                                    \"analyzer\": \"larasearch_search2\"\n                                                }\n                                            }\n                                        }\n                                    ]\n                                }\n                            }\n                        }\n                    }', true), $params);\n                return [];\n            });\n\n        /**\n         * Assertion\n         */\n        $response = $query->execute();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response', $response);\n    }\n\n\n    /**\n     * @test\n     * @expectedException \\InvalidArgumentException\n     */\n    public function it_should_throw_an_exception_when_multiple_queries_are_provided()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $client\n         */\n        list($proxy, $client, $model) = $this->getMocks();\n        $test = $this;\n\n        $query = m::mock('Iverberk\\Larasearch\\Query', [\n            $proxy,\n            '*',\n            [\n                'json' => '{}',\n                'query' => []\n            ]\n        ])->makePartial();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $query->execute();\n    }\n\n    /**\n     * Construct an helper mocks\n     *\n     * @return array\n     */\n    private function getMocks()\n    {\n        $client = m::mock('Elasticsearch\\Client');\n        $model = m::mock('Illuminate\\Database\\Eloquent\\Model');\n\n        $proxy = m::mock('Iverberk\\Larasearch\\Proxy');\n        $proxy->shouldReceive('getClient')\n            ->andReturn($client);\n        $proxy->shouldReceive('getModel')\n            ->andReturn($model);\n        $proxy->shouldReceive('getIndex->getName')\n            ->andReturn('Husband');\n        $proxy->shouldReceive('getType')\n            ->andReturn('Husband');\n        $proxy->shouldReceive('getConfig')\n            ->andReturn([\n                'autocomplete' => ['name', 'wife.name'],\n\n                'suggest' => ['name'],\n\n                'text_start' => ['name', 'wife.children.name'],\n                'text_middle' => ['name', 'wife.children.name'],\n                'text_end' => ['name', 'wife.children.name'],\n\n                'word_start' => ['name', 'wife.children.name'],\n                'word_middle' => ['name', 'wife.children.name'],\n                'word_end' => ['name', 'wife.children.name']\n            ]);\n\n        return [$proxy, $client, $model];\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Response/RecordsTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Mockery as m;\n\nclass RecordsTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_construct()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $husbandMock = m::mock('Husband');\n        $response = m::mock('Iverberk\\Larasearch\\Response');\n        $test = $this;\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $husbandMock->shouldReceive('whereIn')\n            ->andReturnUsing(function ($attribute, $items) use ($test, $husbandMock)\n            {\n                $test->assertEquals('id', $attribute);\n                $test->assertEquals([1, 2], $items);\n                return $husbandMock;\n            });\n        $husbandMock->shouldReceive('get->toArray')\n            ->andReturn(['item1', 'item2']);\n\n        $response->shouldReceive('getHits')->andReturn([['_id' => 1], ['_id' => 2]]);\n        $response->shouldReceive('getModel')->andReturn($husbandMock);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $records = new Records($response);\n\n        $this->assertInstanceOf('Illuminate\\Support\\Collection', $records);\n        $this->assertEquals('item1', $records->first());\n        $this->assertEquals('item2', $records[1]);\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Response/ResultTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Mockery as m;\n\nclass ResultTest extends \\PHPUnit_Framework_TestCase {\n    /**\n     * @var \\Mockery\\Mock\n     */\n    private $result;\n\n    /**\n     * @var array\n     */\n    private $hit;\n\n    protected function setUp()\n    {\n        $this->hit = [\n            '_id' => 1,\n            '_type' => 2,\n            '_index' => 3,\n            '_score' => 4,\n            '_source' => [\n                'id' => 5,\n                'foo' => 'bar'\n            ],\n            'fields' => [\n                'field1' => 'value1',\n                'field2' => 'value2',\n                'nested' => [\n                    'nested_field' => 'nested_value'\n                ]\n            ],\n            'highlight' => [\n                'field3' => 'value3',\n                'field4' => 'value4'\n            ]\n        ];\n\n        $result = new Result($this->hit);\n\n        $this->result = m::mock($result);\n    }\n\n    protected function tearDown()\n    {\n        m::close();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_id()\n    {\n        $this->assertEquals(1, $this->result->getId());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_type()\n    {\n        $this->assertEquals(2, $this->result->getType());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_index()\n    {\n        $this->assertEquals(3, $this->result->getIndex());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_score()\n    {\n        $this->assertEquals(4, $this->result->getScore());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_source()\n    {\n        $this->assertEquals(['id' => 5, 'foo' => 'bar'], $this->result->getSource());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_fields()\n    {\n        $this->assertEquals(['field1' => 'value1', 'field2' => 'value2', 'nested' => ['nested_field' => 'nested_value']], $this->result->getFields());\n        $this->assertEquals(['field1' => 'value1'], $this->result->getFields(['field1']));\n        $this->assertEquals(['field1' => 'value1', 'field2' => 'value2'], $this->result->getFields(['field1', 'field2']));\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_hit()\n    {\n        $this->assertEquals($this->hit, $this->result->getHit());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_highlights()\n    {\n        $this->assertEquals($this->hit['highlight'], $this->result->getHighLights());\n        $this->assertEquals(['field3' => 'value3'], $this->result->getHighLights(['field3']));\n        $this->assertEquals(['field3' => 'value3', 'field4' => 'value4'], $this->result->getHighLights(['field3', 'field4']));\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_attributes_from_hit()\n    {\n        $result = new Result($this->hit);\n\n        $this->assertEquals('bar', $result->foo);\n        $this->assertEquals('nested_value', $result['fields.nested.nested_field']);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_convert_to_array()\n    {\n        $this->assertEquals([\n                'field1' => 'value1',\n                'field2' => 'value2',\n                'nested' => [\n                    'nested_field' => 'nested_value'\n                ]\n            ],\n            $this->result->toArray());\n    }\n\n    /**\n     * The set and unset function will never be implemented\n     * but who doesn't like 100% test coverage ;-)\n     *\n     * @test\n     */\n    public function it_should_cover_hundred_procent()\n    {\n        $this->result['foo'] = 'bar';\n        unset($this->result['foo']);\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Response/ResultsTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Response;\n\nuse Mockery as m;\n\nclass ResultsTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_construct()\n    {\n        $hit = [\n            '_id' => 1,\n            '_type' => 2,\n            '_index' => 3,\n            '_score' => 4,\n            '_source' => [\n                'id' => 5,\n                'foo' => 'bar'\n            ],\n            'fields' => [\n                'field1' => 'value1',\n                'field2' => 'value2',\n                'nested' => [\n                    'nested_field' => 'nested_value'\n                ]\n            ],\n            'highlight' => [\n                'field3' => 'value3',\n                'field4' => 'value4'\n            ]\n        ];\n\n        /**\n         *\n         * Set\n         *\n         */\n        $response = m::mock('Iverberk\\Larasearch\\Response');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $response->shouldReceive('getHits')->andReturn([$hit, $hit]);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $results = new Results($response);\n\n        $this->assertInstanceOf('Illuminate\\Support\\Collection', $results);\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response\\Result', $results->first());\n    }\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/ResponseTest.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\nuse Mockery as m;\n\nclass ResponseTest extends \\PHPUnit_Framework_TestCase {\n\n    private $responseFixture = [\n        'took' => 'took',\n        'timed_out' => 'timed_out',\n        '_shards' => 'shards',\n        'suggest' => [\n            'key_dummy' => 'value_dummy'\n        ],\n        'aggregations' => [\n            'named_aggregation' => 'named_aggregation'\n        ],\n        'hits' => [\n            'total' => 'total',\n            'max_score' => 'max_score',\n            'hits' => [\n                ['_id' => '1']\n            ]\n        ]\n\n    ];\n\n    protected function tearDown()\n    {\n        m::close();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_model()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals($model, $response->getModel());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_response()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals(\n            $this->responseFixture,\n            $response->getResponse());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_results()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $results = $response->getResults();\n\n        $this->assertInstanceOf('Iverberk\\Larasearch\\Response\\Results', $results);\n        $this->assertEquals(1, $results->first()->getId());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_records()\n    {\n        /**\n         *\n         * Set\n         *\n         * @var \\Mockery\\Mock $model\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $model->shouldReceive('get')->andReturn('succes');\n        $model->shouldReceive('whereIn')\n            ->with('id', [1])\n            ->andReturn($model);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $records = $response->getRecords();\n\n        $this->assertEquals('succes', $records);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_took()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals('took', $response->getTook());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_hits()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals([['_id' => 1]], $response->getHits());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_timed_out()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals('timed_out', $response->getTimedOut());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_shards()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals('shards', $response->getShards());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_max_score()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals('max_score', $response->getMaxScore());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_total()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $this->assertEquals('total', $response->getTotal());\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_suggestions_with_fields()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $suggestions = $response->getSuggestions(['key']);\n\n        $this->assertEquals(['key' => 'value_dummy'], $suggestions);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_suggestions_without_fields()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $suggestions = $response->getSuggestions();\n\n        $this->assertEquals(['key_dummy' => 'value_dummy'], $suggestions);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_aggregations_with_name()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $aggregations = $response->getAggregations('named_aggregation');\n\n        $this->assertEquals('named_aggregation', $aggregations);\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_aggregations_without_name()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        list($response, $model) = $this->getMocks();\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $aggregations = $response->getAggregations();\n\n        $this->assertEquals(['named_aggregation' => 'named_aggregation'], $aggregations);\n    }\n\n\n    /**\n     * Construct a Response mock\n     *\n     * @return array\n     */\n    private function getMocks()\n    {\n        $model = m::mock('Husband');\n\n        $response = m::mock('Iverberk\\Larasearch\\Response', array($model, $this->responseFixture))->makePartial();\n\n        return [$response, $model];\n    }\n\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Traits/CallableTraitTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nclass CallableTraitTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n        am::clean();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_boot_callback_trait_and_register_observer()\n    {\n        $husband = am::double('Husband', ['observe' => null]);\n\n        \\Husband::bootCallableTrait();\n\n        // $husband->verifyInvoked('observe');\n    }\n\n    /**\n     * @test\n     * @expectedException \\Exception\n     */\n    public function it_should_boot_callback_trait_and_throw_exception()\n    {\n        \\Dummy::bootCallableTrait();\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Traits/SearchableTraitTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Husband;\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Facade;\nuse Iverberk\\Larasearch\\Proxy;\nuse Mockery as m;\nuse AspectMock\\Test as am;\n\nclass SearchableTraitTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n        am::clean();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_a_proxy()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $proxy = m::mock('Iverberk\\Larasearch\\proxy');\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        Facade::clearResolvedInstances();\n        \\Husband::clearProxy();\n\n        App::shouldReceive('make')\n            ->with('iverberk.larasearch.proxy', m::type('Illuminate\\Database\\Eloquent\\Model'))\n            ->andReturn($proxy);\n\n        /**\n         *\n         *\n         * Assertion\n         *\n         */\n        $proxy1 = \\Husband::getProxy();\n\n        $this->assertSame($proxy, $proxy1);\n\n        $proxy2 = \\Husband::getProxy();\n\n        $this->assertSame($proxy, $proxy2);\n    }\n\n    /**\n     * @test\n     * @expectedException \\Exception\n     */\n    public function it_should_throw_an_exception_if_included_in_a_non_eloquent_model()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        \\Dummy::getProxy();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_call_methods_on_the_proxy()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $proxy = m::mock('Iverberk\\Larasearch\\proxy');\n        $husband = am::double('Husband', ['getProxy' => $proxy]);\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $proxy->shouldReceive('search')\n            ->with('*')\n            ->once()\n            ->andReturn('result_static');\n\n        $proxy->shouldReceive('search')\n            ->with('**')\n            ->once()\n            ->andReturn('result');\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        $result = \\Husband::search('*');\n\n        $this->assertEquals('result_static', $result);\n\n        $result = \\Husband::search('**');\n\n        $this->assertEquals('result', $result);\n\n        $husband->verifyInvoked('getProxy');\n    }\n\n    /**\n     * @test\n     * @expectedException \\BadMethodCallException\n     */\n    public function it_should_not_call_methods_on_the_proxy()\n    {\n        /**\n         *\n         * Expectation\n         *\n         */\n        App::clearResolvedInstance('app');\n        App::shouldReceive('make')->with('Elasticsearch')->andReturn(true);\n        App::shouldReceive('make')->with('iverberk.larasearch.index', m::type('array'))->andReturn(true);\n\n        /**\n         *\n         * Assertion\n         *\n         */\n        // Overrule the proxy defined in previous tests\n        am::double('Husband', ['getProxy' => new Proxy(new Husband)]);\n\n        // Call a non existing method\n        \\Husband::bogus('*');\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_get_elasticsearch_id()\n    {\n        /**\n         * Assertions\n         */\n        $husband = new Husband();\n\n        $this->assertEquals('dummy_id', $husband->getEsId());\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/Traits/TransformableTraitTest.php",
    "content": "<?php namespace Iverberk\\Larasearch\\Traits;\n\nuse Illuminate\\Support\\Facades\\App;\nuse Illuminate\\Support\\Facades\\Config;\nuse Mockery as m;\n\nclass TransformableTraitTest extends \\PHPUnit_Framework_TestCase {\n\n    protected function tearDown()\n    {\n        m::close();\n    }\n\n    /**\n     * @test\n     */\n    public function it_should_transform()\n    {\n        /**\n         *\n         * Set\n         *\n         */\n        $husband = m::mock('Husband')->makePartial();\n\n        /**\n         *\n         * Expectation\n         *\n         */\n        $husband->shouldReceive('load->toArray')->once()->andReturn('mock');\n\n        Config::shouldReceive('get')->with('/paths\\..*/')->once();\n        /**\n         *\n         * Assertion\n         *\n         */\n        $transformed = $husband->transform(true);\n\n        $this->assertEquals('mock', $transformed);\n    }\n\n}\n"
  },
  {
    "path": "tests/Iverberk/Larasearch/UtilsTest.php",
    "content": "<?php namespace Iverberk\\Larasearch;\n\n\nclass UtilsTest extends \\PHPUnit_Framework_TestCase {\n\n    public function testThatKeysCanBeFoundInAnArray()\n    {\n        $params = [\n            'test_key' => 'test_value'\n        ];\n\n        $this->assertEquals('test_value', Utils::findKey($params, 'test_key'));\n        $this->assertEquals('test_value', Utils::findKey((object)$params, 'test_key'));\n\n        $this->assertEquals('default_value', Utils::findKey($params, 'bad_key', 'default_value'));\n        $this->assertEquals('default_value', Utils::findKey((object)$params, 'bad_key', 'default_value'));\n\n        $this->assertEquals(null, Utils::findKey($params, 'bad_key'));\n        $this->assertEquals(null, Utils::findKey((object)$params, 'bad_key'));\n    }\n\n    public function testThatArraysAreMergedRecursivelyByOverwritingCommonKeys()\n    {\n        $arr1 = [\n            'key1' => 'value1',\n            'key2' => 'value2',\n            'key3' => [\n                'key4' => 'value4',\n                'key5' => 'value5',\n                'key6' => [\n                    'key7' => 'value7'\n                ]\n            ]\n        ];\n\n        $arr2 = [\n            'key1' => 'value_override_1',\n            'key8' => 'value8',\n            'key3' => [\n                'key4' => 'value_override_4',\n                'key9' => 'value9',\n                'key10' => [\n                    'key11' => 'value12'\n                ]\n            ]\n        ];\n\n        $arr = Utils::array_merge_recursive_distinct($arr1, $arr2);\n\n        $this->assertArrayHasKey('key1', $arr);\n        $this->assertArrayHasKey('key2', $arr);\n        $this->assertArrayHasKey('key8', $arr);\n\n        $this->assertEquals('value_override_1', $arr['key1']);\n        $this->assertEquals('value_override_4', $arr['key3']['key4']);\n    }\n\n    public function testThatSearchableModelsAreFoundInDirectories()\n    {\n        $models = Utils::findSearchableModels(array(__DIR__ . '/../../Support/Stubs'));\n\n        $this->assertContains('Husband', $models);\n        $this->assertContains('Wife', $models);\n        $this->assertContains('Toy', $models);\n        $this->assertContains('Child', $models);\n        $this->assertContains('House\\\\Item', $models);\n    }\n\n}\n"
  },
  {
    "path": "tests/Support/Dummy.php",
    "content": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Dummy {\n\n    use SearchableTrait;\n\n}"
  },
  {
    "path": "tests/Support/Stubs/Child.php",
    "content": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Child extends Illuminate\\Database\\Eloquent\\Model {\n\n    use SearchableTrait;\n\n    /**\n     * @follow UNLESS Husband\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\n     */\n    public function mother()\n    {\n        return $this->belongsTo('Wife');\n    }\n\n    /**\n     * @follow UNLESS Husband\n     * @follow UNLESS Wife\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\n     */\n    public function father()\n    {\n        return $this->belongsTo('Husband');\n    }\n\n    /**\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\n     */\n    public function toys()\n    {\n        return $this->belongsToMany('Toy');\n    }\n\n}\n\n"
  },
  {
    "path": "tests/Support/Stubs/Foo/Bar.php",
    "content": "<?php namespace House;\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Item extends \\Illuminate\\Database\\Eloquent\\Model {\n\n    use SearchableTrait;\n\n}"
  },
  {
    "path": "tests/Support/Stubs/Husband.php",
    "content": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Husband extends Illuminate\\Database\\Eloquent\\Model {\n\n    use SearchableTrait;\n\n    public static $__es_config = [\n        'autocomplete' => ['name', 'wife.name'],\n\n        'suggest' => ['name'],\n\n        'text_start' => ['name', 'wife.children.name'],\n        'text_middle' => ['name', 'wife.children.name'],\n        'text_end' => ['name', 'wife.children.name'],\n\n        'word_start' => ['name', 'wife.children.name'],\n        'word_middle' => ['name', 'wife.children.name'],\n        'word_end' => ['name', 'wife.children.name']\n    ];\n\n    /**\n     * @follow UNLESS Toy\n     * @follow UNLESS Child\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\n     */\n    public function wife()\n    {\n        return $this->hasOne('Wife');\n    }\n\n    /**\n     * @follow NEVER\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\n     */\n    public function children()\n    {\n        return $this->hasMany('Child', 'father_id');\n    }\n\n\tpublic function getEsId()\n\t{\n\t\treturn 'dummy_id';\n\t}\n\n}"
  },
  {
    "path": "tests/Support/Stubs/NamespaceDummy.php",
    "content": "<?php namespace DummyTest;\n\nclass NamespaceDummy {\n\n} "
  },
  {
    "path": "tests/Support/Stubs/Toy.php",
    "content": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Toy extends Illuminate\\Database\\Eloquent\\Model {\n\n    use SearchableTrait;\n\n    /**\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\n     */\n    public function children()\n    {\n        return $this->belongsToMany('Child');\n    }\n\n}"
  },
  {
    "path": "tests/Support/Stubs/Wife.php",
    "content": "<?php\n\nuse Iverberk\\Larasearch\\Traits\\SearchableTrait;\n\nclass Wife extends Illuminate\\Database\\Eloquent\\Model {\n\n    use SearchableTrait;\n\n    /**\n     * @follow UNLESS Toy\n     * @follow UNLESS Child\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\n     */\n    public function husband()\n    {\n        return $this->belongsTo('Husband');\n    }\n\n    /**\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\n     */\n    public function children()\n    {\n        return $this->hasMany('Child', 'mother_id');\n    }\n\n}"
  },
  {
    "path": "tests/bootstrap.php",
    "content": "<?php\n\n// Composer autoloader\n\nrequire __DIR__ . '/../vendor/autoload.php';\n\n// Boot Aspect Mock\n\n$kernel = \\AspectMock\\Kernel::getInstance();\n$src = __DIR__ . '/../src';\n$eloquent = __DIR__ . '/../vendor/illuminate/database/Illuminate/Database/Eloquent';\n\n$kernel->init([\n    'debug' => true,\n    'cacheDir'  => '/tmp/larasearch',\n    'includePaths' => [$src, $eloquent]\n]);\n\n// Boot the Eloquent component\n\n$capsule = new \\Illuminate\\Database\\Capsule\\Manager();\n\n$capsule->addConnection(array(\n        'driver'   => 'sqlite',\n        'database' => __DIR__ . '/database/testing.sqlite',\n        'prefix'   => '',\n    ));\n\n$capsule->bootEloquent();\n"
  }
]