diff --git a/.styleci.yml b/.styleci.yml index fa0ae5c3..fe42f6da 100755 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,3 +1,2 @@ preset: laravel -disabled: - - self_accessor + diff --git a/CHANGELOG.md b/CHANGELOG.md index 824852a6..743a2a51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/) ## [Unreleased] +## [3.0.4] - 2020-12-03 +### Fixed +- Compatible with Laravel Telescope as dev requirement [#135](https://github.com/matchish/laravel-scout-elasticsearch/issues/135) ## [3.0.3] - 2020-03-14 ### Added diff --git a/composer.json b/composer.json index b3cf74b2..59e95bd5 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "matchish/laravel-scout-elasticsearch", "description": "Search among multiple models with ElasticSearch and Laravel Scout", - "version": "3.0.3", + "version": "3.0.4", "keywords": [ "laravel", "scout", diff --git a/src/Searchable/SearchableListFactory.php b/src/Searchable/SearchableListFactory.php index ad3fecb5..bbfe22ad 100644 --- a/src/Searchable/SearchableListFactory.php +++ b/src/Searchable/SearchableListFactory.php @@ -61,16 +61,75 @@ private function isSearchableModel($class): bool private function getProjectClasses(): array { if (self::$declaredClasses === null) { + self::$declaredClasses = []; + $configFiles = Finder::create()->files()->name('*.php')->in($this->appPath); + foreach ($configFiles->files() as $file) { - require_once $file; + if ($className = $this->classNameFromFileContents($file->getPathname())) { + self::$declaredClasses[] = $className; + } } - self::$declaredClasses = get_declared_classes(); } return self::$declaredClasses; } + /** + * @param string $path + * @return string|null + * @link https://stackoverflow.com/a/7153391/1359273 + */ + private function classNameFromFileContents($path) + { + $fp = fopen($path, 'r'); + + if (false === $fp) { + return null; + } + + $class = $namespace = $buffer = ''; + + while (! $class) { + if (feof($fp)) { + break; + } + + $buffer .= fread($fp, 512); + $tokens = token_get_all($buffer); + + if (strpos($buffer, '{') === false) { + continue; + } + + for ($i = 0, $iMax = count($tokens); $i < $iMax; $i++) { + if ($tokens[$i][0] === T_NAMESPACE) { + for ($j = $i + 1, $jMax = count($tokens); $j < $jMax; $j++) { + if ($tokens[$j][0] === T_STRING) { + $namespace .= $tokens[$j][1]; + } elseif ($tokens[$j] === '{' || $tokens[$j] === ';') { + break; + } + } + } + + if ($tokens[$i][0] === T_CLASS) { + for ($j = $i + 1, $jMax = count($tokens); $j < $jMax; $j++) { + if ($tokens[$j] === '{') { + $class = $tokens[$i + 2][1]; + } + } + } + } + } + + if (! $class) { + return null; + } + + return $namespace ? "{$namespace}\\{$class}" : $class; + } + /** * @return Collection */ diff --git a/tests/Feature/ImportCommandTest.php b/tests/Feature/ImportCommandTest.php index 22ca3e0d..49cf3ba3 100644 --- a/tests/Feature/ImportCommandTest.php +++ b/tests/Feature/ImportCommandTest.php @@ -172,12 +172,9 @@ public function test_progress_report_in_queue() $output = new BufferedOutput(); Artisan::call('scout:import', [], $output); - $output = explode("\n", $output->fetch()); - $this->assertEquals( - trans('scout::import.start', ['searchable' => Product::class]), - trim($output[0])); - $this->assertEquals( - '[OK] '.trans('scout::import.done.queue', ['searchable' => Product::class]), - trim($output[2])); + $output = array_map('trim', explode("\n", $output->fetch())); + + $this->assertContains(trans('scout::import.start', ['searchable' => Product::class]), $output); + $this->assertContains('[OK] '.trans('scout::import.done.queue', ['searchable' => Product::class]), $output); } } diff --git a/tests/Unit/Searchable/SearchableListFactoryTest.php b/tests/Unit/Searchable/SearchableListFactoryTest.php new file mode 100644 index 00000000..306ddc8c --- /dev/null +++ b/tests/Unit/Searchable/SearchableListFactoryTest.php @@ -0,0 +1,22 @@ +assertFileExists(app()->path().'/Providers/TelescopeServiceProvider.php'); + + // This should NOT throw "Error: Class 'Laravel\Telescope\TelescopeApplicationServiceProvider' not found" + $factory = new SearchableListFactory(app()->getNamespace(), app()->path()); + + $searchable = $factory->make(); + + // There are 4 searchable models: Book, BookWithCustomKey, Product and Ticket + $this->assertCount(4, $searchable); + } +} diff --git a/tests/laravel/app/library/CustomHitsIteratorAggregate.php b/tests/laravel/app/Library/CustomHitsIteratorAggregate.php similarity index 100% rename from tests/laravel/app/library/CustomHitsIteratorAggregate.php rename to tests/laravel/app/Library/CustomHitsIteratorAggregate.php diff --git a/tests/laravel/app/Providers/TelescopeServiceProvider.php b/tests/laravel/app/Providers/TelescopeServiceProvider.php new file mode 100644 index 00000000..b36d243e --- /dev/null +++ b/tests/laravel/app/Providers/TelescopeServiceProvider.php @@ -0,0 +1,75 @@ +hideSensitiveRequestDetails(); + + Telescope::filter(function (IncomingEntry $entry) { + if ($this->app->environment('local')) { + return true; + } + + return $entry->isReportableException() || + $entry->isFailedRequest() || + $entry->isFailedJob() || + $entry->isScheduledTask() || + $entry->hasMonitoredTag(); + }); + } + + /** + * Prevent sensitive request details from being logged by Telescope. + * + * @return void + */ + protected function hideSensitiveRequestDetails() + { + if ($this->app->environment('local')) { + return; + } + + Telescope::hideRequestParameters(['_token']); + + Telescope::hideRequestHeaders([ + 'cookie', + 'x-csrf-token', + 'x-xsrf-token', + ]); + } + + /** + * Register the Telescope gate. + * + * This gate determines who can access Telescope in non-local environments. + * + * @return void + */ + protected function gate() + { + Gate::define('viewTelescope', function ($user) { + return in_array($user->email, [ + // + ]); + }); + } +}