diff --git a/modules/system/ServiceProvider.php b/modules/system/ServiceProvider.php index 3a8b58f301..da08fe3485 100644 --- a/modules/system/ServiceProvider.php +++ b/modules/system/ServiceProvider.php @@ -301,6 +301,8 @@ protected function registerConsole() $this->registerConsoleCommand('create.settings', \System\Console\CreateSettings::class); $this->registerConsoleCommand('create.test', \System\Console\CreateTest::class); + $this->registerConsoleCommand('model.prune', Console\PruneCommand::class); + $this->registerConsoleCommand('winter.up', \System\Console\WinterUp::class); $this->registerConsoleCommand('winter.down', \System\Console\WinterDown::class); $this->registerConsoleCommand('winter.update', \System\Console\WinterUpdate::class); diff --git a/modules/system/console/PruneCommand.php b/modules/system/console/PruneCommand.php new file mode 100644 index 0000000000..2454941259 --- /dev/null +++ b/modules/system/console/PruneCommand.php @@ -0,0 +1,75 @@ +option('model'))) { + return collect($models)->filter(function ($model) { + return class_exists($model); + })->values(); + } + + $except = $this->option('except'); + + return collect($this->findModels()) + ->when(! empty($except), function ($models) use ($except) { + return $models->reject(function ($model) use ($except) { + return in_array($model, $except); + }); + })->filter(function ($model) { + return class_exists($model) && $this->isPrunable($model); + })->values(); + } + + /** + * {@inheritDoc} + */ + protected function isPrunable($model): bool + { + try { + $uses = class_uses_recursive($model); + } catch (Exception $e) { + return false; + } + + return in_array(Prunable::class, $uses) || in_array(MassPrunable::class, $uses); + } + + /** + * Find all models. + */ + protected function findModels(): array + { + /** + * @event system.console.model.prune.findModels + * Give the opportunity to return an array of Models to prune. + * + * Example usage: + * + * Event::listen('system.console.model.prune.findModels', function () { + * return ['example model' => '\System\Models\File']; + * }); + * + */ + $models = Event::fire('system.console.model.prune.findModels', [$this], true); + if (is_array($models)) { + return $models; + } + + return ModelFinder::findModels(); + } +} diff --git a/modules/system/helpers/ModelFinder.php b/modules/system/helpers/ModelFinder.php new file mode 100644 index 0000000000..a3643f0f04 --- /dev/null +++ b/modules/system/helpers/ModelFinder.php @@ -0,0 +1,57 @@ +flatten()->all(); + } + + public static function findModuleModels(): array + { + $modulesPath = base_path() . '/modules'; + + $models = collect(Finder::create()->in($modulesPath)->notPath('/tests/')->files()->name('/^[A-Z]{1}.+\.php$/')) + ->map(function ($model) use ($modulesPath) { + $modelPath = str_replace(['/', '.php'], ['\\', ''], Str::after($model->getRealPath(), realpath($modulesPath).DIRECTORY_SEPARATOR)); + return ucwords($modelPath, '\\'); + }); + + return $models->values()->all(); + } + + public static function findActivePluginsModels(): array + { + $models = []; + $pm = \System\Classes\PluginManager::instance(); + + $pluginsPaths = collect($pm->getPlugins())->map(function ($plugin) use ($pm) { + return $pm->getPluginPath($plugin); + })->filter(function ($path) { + return File::exists($path . '/models'); + })->each(function ($path) use (&$models) { + $modelPaths = Finder::create()->in($path . '/models')->files()->name('/^[A-Z]{1}.+\.php$/'); + $models[] = collect($modelPaths)->map(function ($model) { + $modelPath = str_replace(['/', '.php'], ['\\', ''], Str::after($model->getRealPath(), plugins_path().DIRECTORY_SEPARATOR)); + return ucwords($modelPath, '\\'); + })->all(); + }); + + return collect($models)->flatten()->all(); + } +}