diff --git a/app/Console/Commands/RebuildSearchIndex.php b/app/Console/Commands/RebuildSearchIndex.php new file mode 100644 index 00000000..ec583e4c --- /dev/null +++ b/app/Console/Commands/RebuildSearchIndex.php @@ -0,0 +1,93 @@ +. + */ + +namespace Poniverse\Ponyfm\Console\Commands; + +use Illuminate\Console\Command; +use Illuminate\Database\Eloquent\Collection; +use Poniverse\Ponyfm\Models\Album; +use Poniverse\Ponyfm\Models\Playlist; +use Poniverse\Ponyfm\Models\Track; +use Poniverse\Ponyfm\Models\User; + +class RebuildSearchIndex extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'rebuild:search'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Rebuilds the Elasticsearch index.'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $totalTracks = Track::withTrashed()->count(); + $totalAlbums = Album::withTrashed()->count(); + $totalPlaylists = Playlist::withTrashed()->count(); + $totalUsers = User::count(); + + Track::withTrashed()->chunk(200, function(Collection $tracks) { + foreach($tracks as $track) { + $this->info("Processing track #{$track->id}..."); + $track->ensureElasticsearchEntryIsUpToDate(); + } + }); + + Album::withTrashed()->chunk(200, function(Collection $albums) { + foreach($albums as $album) { + $this->info("Processing album #{$album->id}..."); + $album->ensureElasticsearchEntryIsUpToDate(); + } + }); + +// Playlist::withTrashed()->chunk(200, function(Collection $playlists) { +// foreach($playlists as $playlist) { +// $this->info("Processing playlist #{$playlist->id}..."); +// $playlist->ensureElasticsearchEntryIsUpToDate(); +// } +// }); +// +// User::withTrashed()->chunk(200, function(User $user) { +// $user->ensureElasticsearchEntryIsUpToDate(); +// }); + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 4b1d2233..93446c6d 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -42,6 +42,7 @@ class Kernel extends ConsoleKernel \Poniverse\Ponyfm\Console\Commands\RebuildTrackCache::class, \Poniverse\Ponyfm\Console\Commands\RebuildTrack::class, \Poniverse\Ponyfm\Console\Commands\RebuildFilesizes::class, + \Poniverse\Ponyfm\Console\Commands\RebuildSearchIndex::class, \Poniverse\Ponyfm\Console\Commands\MergeDuplicateAccounts::class, ]; diff --git a/app/Http/Controllers/Api/Web/SearchController.php b/app/Http/Controllers/Api/Web/SearchController.php new file mode 100644 index 00000000..5025259c --- /dev/null +++ b/app/Http/Controllers/Api/Web/SearchController.php @@ -0,0 +1,59 @@ +. + */ + +namespace Poniverse\Ponyfm\Http\Controllers\Api\Web; + +use Elasticsearch; +use Poniverse\Ponyfm\Http\Controllers\ApiControllerBase; +use Input; +use Response; + +class SearchController extends ApiControllerBase +{ + public function getSearch() + { + $input = Input::all(); + + $elasticsearch = Elasticsearch::connection(); + + $results = $elasticsearch->search([ + 'index' => 'ponyfm', + 'type' => 'track,album', + 'body' => [ + 'query' => [ + 'multi_match' => [ + 'query' => $input['query'], + 'fields' => [ + 'track.title', + 'album.title', + 'track.artist', + 'album.artist', + 'track.genre', + ] + ] + ] + ] + ]); + + return Response::json([ + 'results' => $results, + ], 200); + } +} diff --git a/app/Http/routes.php b/app/Http/routes.php index ec54763b..57f3edb5 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -82,8 +82,7 @@ Route::group(['prefix' => 'api/v1', 'middleware' => 'json-exceptions'], function Route::group(['prefix' => 'api/web'], function() { Route::get('/taxonomies/all', 'Api\Web\TaxonomiesController@getAll'); - - Route::get('/playlists/show/{id}', 'Api\Web\PlaylistsController@getShow'); + Route::get('/search', 'Api\Web\SearchController@getSearch'); Route::get('/tracks', 'Api\Web\TracksController@getIndex'); Route::get('/tracks/{id}', 'Api\Web\TracksController@getShow')->where('id', '\d+'); @@ -94,6 +93,7 @@ Route::group(['prefix' => 'api/web'], function() { Route::get('/albums/cached/{id}/{format}', 'Api\Web\AlbumsController@getCachedAlbum')->where(['id' => '\d+', 'format' => '.+']); Route::get('/playlists', 'Api\Web\PlaylistsController@getIndex'); + Route::get('/playlists/show/{id}', 'Api\Web\PlaylistsController@getShow'); Route::get('/playlists/{id}', 'Api\Web\PlaylistsController@getShow')->where('id', '\d+'); Route::get('/playlists/cached/{id}/{format}', 'Api\Web\PlaylistsController@getCachedPlaylist')->where(['id' => '\d+', 'format' => '.+']); diff --git a/app/Models/Album.php b/app/Models/Album.php index 6666a4eb..023ce002 100644 --- a/app/Models/Album.php +++ b/app/Models/Album.php @@ -28,6 +28,7 @@ use Illuminate\Foundation\Bus\DispatchesJobs; use Auth; use Cache; use Poniverse\Ponyfm\Exceptions\TrackFileNotFoundException; +use Poniverse\Ponyfm\Traits\IndexedInElasticsearch; use Poniverse\Ponyfm\Traits\TrackCollection; use Poniverse\Ponyfm\Traits\SlugTrait; use Venturecraft\Revisionable\RevisionableTrait; @@ -61,7 +62,9 @@ use Venturecraft\Revisionable\RevisionableTrait; */ class Album extends Model { - use SoftDeletes, SlugTrait, DispatchesJobs, TrackCollection, RevisionableTrait; + use SoftDeletes, SlugTrait, DispatchesJobs, TrackCollection, RevisionableTrait, IndexedInElasticsearch; + + protected $elasticsearchType = 'album'; protected $dates = ['deleted_at']; protected $fillable = ['user_id', 'title', 'slug']; @@ -403,4 +406,18 @@ class Album extends Model protected function recountTracks() { $this->track_count = $this->tracks->count(); } + + /** + * Returns this model in Elasticsearch-friendly form. The array returned by + * this method should match the current mapping for this model's ES type. + * + * @return array + */ + public function toElasticsearch() { + return [ + 'title' => $this->title, + 'artist' => $this->user->display_name, + 'tracks' => $this->tracks->pluck('title'), + ]; + } } diff --git a/app/Models/Playlist.php b/app/Models/Playlist.php index cc3c3be2..d84080d8 100644 --- a/app/Models/Playlist.php +++ b/app/Models/Playlist.php @@ -27,6 +27,7 @@ use Illuminate\Foundation\Bus\DispatchesJobs; use Auth; use Cache; use Poniverse\Ponyfm\Exceptions\TrackFileNotFoundException; +use Poniverse\Ponyfm\Traits\IndexedInElasticsearch; use Poniverse\Ponyfm\Traits\TrackCollection; use Poniverse\Ponyfm\Traits\SlugTrait; use Venturecraft\Revisionable\RevisionableTrait; @@ -60,10 +61,11 @@ use Venturecraft\Revisionable\RevisionableTrait; */ class Playlist extends Model { - use SoftDeletes, SlugTrait, DispatchesJobs, TrackCollection, RevisionableTrait; + use SoftDeletes, SlugTrait, DispatchesJobs, TrackCollection, RevisionableTrait, IndexedInElasticsearch; + + protected $elasticsearchType = 'playlist'; protected $table = 'playlists'; - protected $dates = ['deleted_at']; public static function summary() @@ -285,4 +287,14 @@ class Playlist extends Model { return 'playlist-' . $this->id . '-' . $key; } + + /** + * Returns this model in Elasticsearch-friendly form. The array returned by + * this method should match the current mapping for this model's ES type. + * + * @return array + */ + public function toElasticsearch() { + return $this->toArray(); + } } diff --git a/app/Models/Track.php b/app/Models/Track.php index c32c5aba..b977be4a 100644 --- a/app/Models/Track.php +++ b/app/Models/Track.php @@ -24,7 +24,9 @@ use Auth; use Cache; use Config; use DB; +use Elasticsearch; use Poniverse\Ponyfm\Exceptions\TrackFileNotFoundException; +use Poniverse\Ponyfm\Traits\IndexedInElasticsearch; use Poniverse\Ponyfm\Traits\SlugTrait; use Exception; use External; @@ -95,7 +97,9 @@ use Venturecraft\Revisionable\RevisionableTrait; */ class Track extends Model { - use SoftDeletes; + use SoftDeletes, IndexedInElasticsearch; + + protected $elasticsearchType = 'track'; protected $dates = ['deleted_at', 'published_at', 'released_at']; protected $hidden = ['original_tags', 'metadata']; @@ -826,4 +830,15 @@ class Track extends Model { return 'track-' . $this->id . '-' . $key; } + + public function toElasticsearch() { + return [ + 'title' => $this->title, + 'artist' => $this->user->display_name, + 'published_at' => $this->published_at ? $this->published_at->toIso8601String() : null, + 'genre' => $this->genre->name, + 'track_type' => $this->trackType->title, + 'show_songs' => $this->showSongs->pluck('title') + ]; + } } diff --git a/app/Models/User.php b/app/Models/User.php index 9a956028..97b86b05 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -29,6 +29,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Auth\Access\Authorizable; use Auth; use Illuminate\Support\Str; +use Poniverse\Ponyfm\Traits\IndexedInElasticsearch; use Venturecraft\Revisionable\RevisionableTrait; /** @@ -64,7 +65,9 @@ use Venturecraft\Revisionable\RevisionableTrait; */ class User extends Model implements AuthenticatableContract, CanResetPasswordContract, \Illuminate\Contracts\Auth\Access\Authorizable { - use Authenticatable, CanResetPassword, Authorizable, RevisionableTrait; + use Authenticatable, CanResetPassword, Authorizable, RevisionableTrait, IndexedInElasticsearch; + + protected $elasticsearchType = 'user'; protected $table = 'users'; protected $casts = [ @@ -247,4 +250,14 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon return false; } + + /** + * Returns this model in Elasticsearch-friendly form. The array returned by + * this method should match the current mapping for this model's ES type. + * + * @return array + */ + public function toElasticsearch() { + return $this->toArray(); + } } diff --git a/app/Traits/IndexedInElasticsearch.php b/app/Traits/IndexedInElasticsearch.php new file mode 100644 index 00000000..7e94b2d2 --- /dev/null +++ b/app/Traits/IndexedInElasticsearch.php @@ -0,0 +1,92 @@ +. + */ + +namespace Poniverse\Ponyfm\Traits; + +use Elasticsearch; + +/** + * Class IndexedInElasticsearch + * + * Classes using this trait must declare the `$elasticsearchType` property + * and use the `SoftDeletes` trait. + * + * @package Poniverse\Ponyfm\Traits + */ +trait IndexedInElasticsearch +{ + /** + * Returns this model in Elasticsearch-friendly form. The array returned by + * this method should match the current mapping for this model's ES type. + * + * @return array + */ + abstract public function toElasticsearch(); + + public static function bootIndexedInElasticsearch() { + static::saved(function ($model) { + $model->createOrUpdateElasticsearchEntry(); + }); + + static::deleted(function ($model) { + $model->deleteElasticsearchEntry(); + }); + } + + /** + * @param bool $includeBody set to false when deleting documents + * @return array + */ + private function getElasticsearchParameters(bool $includeBody = true) { + $parameters = [ + 'index' => 'ponyfm', + 'type' => $this->elasticsearchType, + 'id' => $this->id, + ]; + + if ($includeBody) { + $parameters['body'] = $this->toElasticsearch(); + } + + return $parameters; + } + + private function createOrUpdateElasticsearchEntry() { + Elasticsearch::connection()->index($this->getElasticsearchParameters()); + } + + private function deleteElasticsearchEntry() { + try { + Elasticsearch::connection()->delete($this->getElasticsearchParameters(false)); + + } catch (\Elasticsearch\Common\Exceptions\Missing404Exception $e) { + // If the track we're trying to delete isn't indexed in Elasticsearch, + // that's fine. + } + } + + public function ensureElasticsearchEntryIsUpToDate() { + if ($this->trashed()) { + $this->deleteElasticsearchEntry(); + } else { + $this->createOrUpdateElasticsearchEntry(); + } + } +} diff --git a/composer.json b/composer.json index 3c072416..bae0215b 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "guzzlehttp/guzzle": "~6.0", "doctrine/dbal": "^2.5", "venturecraft/revisionable": "^1.23", - "pda/pheanstalk": "~3.0" + "pda/pheanstalk": "~3.0", + "cviebrock/laravel-elasticsearch": "^1.0" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/composer.lock b/composer.lock index 56be2782..6066c1cd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "d99fa4165b8a1c9e929248bbb16183ad", - "content-hash": "31347c82515003f78f1f9adef010f1f5", + "hash": "0deb7713636ee82aadee47da3a9217cc", + "content-hash": "9dea148233d815e53eb636413f2bcaed", "packages": [ { "name": "barryvdh/laravel-ide-helper", @@ -168,6 +168,55 @@ ], "time": "2013-05-05 09:10:04" }, + { + "name": "cviebrock/laravel-elasticsearch", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/cviebrock/laravel-elasticsearch.git", + "reference": "52aa1f8228006cb0bb60954e26c068af523bf47b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cviebrock/laravel-elasticsearch/zipball/52aa1f8228006cb0bb60954e26c068af523bf47b", + "reference": "52aa1f8228006cb0bb60954e26c068af523bf47b", + "shasum": "" + }, + "require": { + "elasticsearch/elasticsearch": "^2.0", + "illuminate/support": "~4|~5", + "monolog/monolog": "~1", + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cviebrock\\LaravelElasticsearch\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Colin Viebrock", + "email": "colin@viebrock.ca" + }, + { + "name": "Brandon Martel", + "email": "brandonmartel@gmail.com" + } + ], + "description": "An easy way to use the official PHP ElasticSearch client in your Laravel applications", + "keywords": [ + "client", + "elasticsearch", + "laravel", + "search" + ], + "time": "2016-01-06 15:58:07" + }, { "name": "danielstjules/stringy", "version": "1.10.0", @@ -726,6 +775,60 @@ ], "time": "2014-09-09 13:34:57" }, + { + "name": "elasticsearch/elasticsearch", + "version": "v2.1.3", + "source": { + "type": "git", + "url": "https://github.com/elastic/elasticsearch-php.git", + "reference": "7086a86cab241a77f19cdd653ae3d2e023b41699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/7086a86cab241a77f19cdd653ae3d2e023b41699", + "reference": "7086a86cab241a77f19cdd653ae3d2e023b41699", + "shasum": "" + }, + "require": { + "guzzlehttp/ringphp": "~1.0", + "php": ">=5.4", + "psr/log": "~1.0" + }, + "require-dev": { + "athletic/athletic": "~0.1", + "cpliakas/git-wrapper": "~1.0", + "mockery/mockery": "0.9.4", + "phpunit/phpunit": "~4.7", + "symfony/yaml": "2.4.3 as 2.4.2", + "twig/twig": "1.*" + }, + "suggest": { + "ext-curl": "*", + "monolog/monolog": "Allows for client-level logging and tracing" + }, + "type": "library", + "autoload": { + "psr-4": { + "Elasticsearch\\": "src/Elasticsearch/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache 2" + ], + "authors": [ + { + "name": "Zachary Tong" + } + ], + "description": "PHP Client for Elasticsearch", + "keywords": [ + "client", + "elasticsearch", + "search" + ], + "time": "2015-12-15 18:42:26" + }, { "name": "guzzlehttp/guzzle", "version": "6.1.1", @@ -897,6 +1000,107 @@ ], "time": "2015-11-03 01:34:55" }, + { + "name": "guzzlehttp/ringphp", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/RingPHP.git", + "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "shasum": "" + }, + "require": { + "guzzlehttp/streams": "~3.0", + "php": ">=5.4.0", + "react/promise": "~2.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "ext-curl": "Guzzle will use specific adapters if cURL is present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Ring\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", + "time": "2015-05-20 03:37:09" + }, + { + "name": "guzzlehttp/streams", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/streams.git", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple abstraction over streams of data", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "stream" + ], + "time": "2014-10-12 19:18:40" + }, { "name": "intouch/laravel-newrelic", "version": "2.0.0", @@ -1864,6 +2068,50 @@ ], "time": "2015-11-12 16:18:56" }, + { + "name": "react/promise", + "version": "v2.2.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/3b6fca09c7d56321057fa8867c8dbe1abf648627", + "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "time": "2015-07-03 13:48:55" + }, { "name": "swiftmailer/swiftmailer", "version": "v5.4.1", diff --git a/config/app.php b/config/app.php index 8fcbfdd7..119b1bf4 100644 --- a/config/app.php +++ b/config/app.php @@ -147,6 +147,7 @@ return [ Intouch\LaravelNewrelic\NewrelicServiceProvider::class, Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, + Cviebrock\LaravelElasticsearch\ServiceProvider::class, ], @@ -197,6 +198,7 @@ return [ 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, + 'Elasticsearch' => Cviebrock\LaravelElasticsearch\Facade::class, 'Newrelic' => Intouch\LaravelNewrelic\Facades\Newrelic::class, ], diff --git a/config/elasticsearch.php b/config/elasticsearch.php new file mode 100644 index 00000000..faa27549 --- /dev/null +++ b/config/elasticsearch.php @@ -0,0 +1,167 @@ + 'default', + + /** + * These are the connection parameters used when building a client. + */ + + 'connections' => [ + + 'default' => [ + + /** + * Hosts + * + * This is an array of hosts that the client will connect to. It can be a + * single host name, or an array if you are running a cluster of Elasticsearch + * instances. + * + * This is the only configuration value that is mandatory. + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_host_configuration + */ + + 'hosts' => [ + 'localhost:9200' + ], + + /** + * SSL + * + * If your Elasticsearch instance uses an out-dated or self-signed SSL + * certificate, you will need to pass in the certificate bundle. This can + * either be the path to the certificate file (for self-signed certs), or a + * package like https://github.com/Kdyby/CurlCaBundle. See the documentation + * below for all the details. + * + * If you are using SSL instances, and the certificates are up-to-date and + * signed by a public certificate authority, then you can leave this null and + * just use "https" in the host path(s) above and you should be fine. + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_security.html#_ssl_encryption_2 + */ + + 'sslVerification' => null, + + /** + * Logging + * + * Logging is handled by passing in an instance of Monolog\Logger (which + * coincidentally is what Laravel's default logger is). + * + * If logging is enabled, you either need to set the path and log level + * (some defaults are given for you below), or you can use a custom logger by + * setting 'logObject' to an instance of Psr\Log\LoggerInterface. In fact, + * if you just want to use the default Laravel logger, then set 'logObject' + * to \Log::getMonolog(). + * + * Note: 'logObject' takes precedent over 'logPath'/'logLevel', so set + * 'logObject' null if you just want file-based logging to a custom path. + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#enabling_logger + */ + + 'logging' => false, + + // If you have an existing instance of Monolog you can use it here. + //'logObject' => \Log::getMonolog(), + + 'logPath' => storage_path('logs/elasticsearch.log'), + + 'logLevel' => Monolog\Logger::INFO, + + /** + * Retries + * + * By default, the client will retry n times, where n = number of nodes in + * your cluster. If you would like to disable retries, or change the number, + * you can do so here. + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_set_retries + */ + + 'retries' => null, + + /** + * The remainder of the configuration options can almost always be left + * as-is unless you have specific reasons to change them. Refer to the + * appropriate sections in the Elasticsearch documentation for what each option + * does and what values it expects. + */ + + /** + * Sniff On Start + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html + */ + + 'sniffOnStart' => false, + + /** + * HTTP Handler + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_configure_the_http_handler + * @see http://ringphp.readthedocs.org/en/latest/client_handlers.html + */ + + 'httpHandler' => null, + + /** + * Connection Pool + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_setting_the_connection_pool + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_connection_pool.html + */ + + 'connectionPool' => null, + + /** + * Connection Selector + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_setting_the_connection_selector + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_selectors.html + */ + + 'connectionSelector' => null, + + /** + * Serializer + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_setting_the_serializer + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_serializers.html + */ + + 'serializer' => null, + + /** + * Connection Factory + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_setting_a_custom_connectionfactory + */ + + 'connectionFactory' => null, + + /** + * Endpoint + * + * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_set_the_endpoint_closure + */ + + 'endpoint' => null, + + ] + ] + +]; diff --git a/database/migrations/2016_01_14_021607_setup_elasticsearch.php b/database/migrations/2016_01_14_021607_setup_elasticsearch.php new file mode 100644 index 00000000..f021afff --- /dev/null +++ b/database/migrations/2016_01_14_021607_setup_elasticsearch.php @@ -0,0 +1,88 @@ +. + */ + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; +use Poniverse\Ponyfm\Console\Commands\RebuildSearchIndex; + +class SetupElasticsearch extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + $elasticsearch = Elasticsearch::connection(); + + $elasticsearch->indices()->create([ + 'index' => 'ponyfm', + 'body' => [ + 'mappings' => [ + 'track' => [ + '_source' => ['enabled' => true], + 'dynamic' => 'strict', + 'properties' => [ + 'title' => ['type' => 'string'], + 'artist' => ['type' => 'string'], + 'published_at' => ['type' => 'date'], + 'genre' => ['type' => 'string'], + 'track_type' => ['type' => 'string'], + + // This field is intended to be used as an array. + // Note that all Elasticsearch fields can technically be used as arrays. + // See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html + 'show_songs' => ['type' => 'string'], + ] + ], + + 'album' => [ + '_source' => ['enabled' => true], + 'dynamic' => 'strict', + 'properties' => [ + 'title' => ['type' => 'string'], + 'artist' => ['type' => 'string'], + + // This field is intended to be used as an array. + // Note that all Elasticsearch fields can technically be used as arrays. + // See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html + 'tracks' => ['type' => 'string'] + ] + ] + ] + ] + ]); + + Artisan::call('rebuild:search'); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $elasticsearch = Elasticsearch::connection(); + + $elasticsearch->indices()->delete(['index' => 'ponyfm']); + } +} diff --git a/vagrant/install.sh b/vagrant/install.sh index 4b913554..654b251e 100755 --- a/vagrant/install.sh +++ b/vagrant/install.sh @@ -1,13 +1,28 @@ #!/usr/bin/env bash + +if type java &>/dev/null; then + echo "Java is installed!" +else + sudo add-apt-repository -y ppa:webupd8team/java + echo /usr/bin/debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections + echo /usr/bin/debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections +fi + + +if type /usr/share/elasticsearch/bin/elasticsearch &>/dev/null; then + echo "ElasticSearch is installed!" +else + wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add - + echo "deb http://packages.elastic.co/elasticsearch/2.x/debian stable main" | sudo tee -a /etc/apt/sources.list.d/elasticsearch-2.x.list +fi + + echo "Running apt-get update..." sudo apt-get -qq update -echo "Installing tagging tools..." -sudo apt-get -qq install -y AtomicParsley flac vorbis-tools imagemagick - -echo "Installing ffmpeg dependencies.." -sudo apt-get -qq install -y pkg-config yasm libfaac-dev libmp3lame-dev libvorbis-dev libtheora-dev +echo "Installing tagging tools & other dependencies..." +sudo apt-get -qq install -y AtomicParsley flac vorbis-tools imagemagick oracle-java8-installer pkg-config yasm libfaac-dev libmp3lame-dev libvorbis-dev libtheora-dev if type ffmpeg &>/dev/null; then