JezK
Edit File: PolicyDiscovery.php
<?php /** * Discovers authorization policy classes in app/Policies and associates them with model classes by naming convention. * Caches the policy map for production and validates policy class names. * Feeds PolicyManager with model-to-policy bindings. * * @package Framework * @subpackage Discovery * @since 1.0.0 */ namespace Kirki\Framework\Discovery; \defined('ABSPATH') || exit; use Kirki\Framework\Contracts\Cacheable; use Kirki\Framework\Contracts\Discoverable; use Kirki\Framework\Supports\Facades\File; use function Kirki\Framework\app; use function Kirki\Framework\app_path; use function Kirki\Framework\config_path; use function Kirki\Framework\Polyfill\str_ends_with; class PolicyDiscovery implements Discoverable, Cacheable { /** * The discovered policies array. * * @var array * * @since 1.0.0 */ protected array $policies = []; /** * Discover the policies from the file system. * * @return self * * @since 1.0.0 */ public function discover() { // For the production mode we will cache the policies to improve the performance. // So don't need to discover the policies from the filesystem. if (!app()->is_dev_mode()) { return $this; } return $this->create_cache_file(); } /** * Create the cache file. * * @return self * * @since 1.0.0 */ protected function create_cache_file() { $policies_directory = app_path('Policies'); if (!\file_exists($policies_directory)) { return $this; } $policy_files = \glob($policies_directory . '/*.php'); if (empty($policy_files)) { return $this; } foreach ($policy_files as $policy_file) { $policy_name = $this->filename($policy_file); if (!$this->is_valid_policy_name($policy_name)) { continue; } $policy = $this->policy_class($policy_name); $model = $this->associated_model($policy_name); $this->add_policy($model, $policy); } return $this; } /** * Get the filename of the policy. * * @param string $path The path. * * @return string * * @since 1.0.0 */ protected function filename(string $path) { return \basename($path, '.php'); } /** * Add a policy to the policies array. * * @param string $model The model instance. * @param string $policy The policy. * * @return void * * @since 1.0.0 */ protected function add_policy(string $model, string $policy) { $this->policies[] = \compact('model', 'policy'); } /** * Get the policies array. * * @return array * * @since 1.0.0 */ public function policies() { return $this->policies; } /** * Get the policy class from the policy name. * * @param string $policy_name The policy name. * * @return string * * @since 1.0.0 */ protected function policy_class(string $policy_name) { $app_namespace = \rtrim(app()->get_namespace(), '\\'); $policy_base_namespace = $app_namespace . '\\Policies\\'; return $policy_base_namespace . $policy_name; } /** * Get the model class from the policy name. * * @param string $policy_name The policy name. * * @return string * * @since 1.0.0 */ protected function associated_model(string $policy_name) { $app_namespace = \rtrim(app()->get_namespace(), '\\'); $model_base_namespace = $app_namespace . '\\Models\\'; $model_name = \str_replace('Policy', '', $policy_name); return $model_base_namespace . $model_name; } /** * Check if the policy name is valid. * * @param string $policy_name The policy name. * * @return bool * * @since 1.0.0 */ protected function is_valid_policy_name(string $policy_name) { if (!str_ends_with($policy_name, 'Policy')) { return \false; } $model_class = $this->associated_model($policy_name); if (!\class_exists($model_class)) { return \false; } return \true; } /** * Cache the policies. * * @param ?string $path The path. * * @return $this * * @since 1.0.0 */ public function cache(?string $path = null) { $path = $path ?? config_path('policies.cache.php'); if (!$this->is_cacheable($path)) { return $this; } File::put($path, "<?php \r\n\r\n/** Auto generated by discovering the policies. Don't edit this file manually." . " */\r\n\r\nreturn " . \var_export($this->policies(), \true) . ';'); return $this; } /** * Check if the policies are cacheable. * * @param string $path The path. * * @return bool * * @since 1.0.0 */ public function is_cacheable(string $path) { return app()->is_dev_mode() || File::missing($path); } }