diff --git a/UPGRADING.md b/UPGRADING.md index 1a6bcd5cd..bfcef207c 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,5 +1,30 @@ # Upgrade Guide +## Version 1.0.0-beta.7 to 1.0.0-beta.8 + +### Mandatory Config Changes + +#### Helper Autoloading + +Helper autoloading has been changed to be done by CodeIgniter's autoloader +instead of Composer. + +So you need to update the settings. Run `php spark shield:setup` again, and the +following steps will be done. + +1. Add `auth` and `setting` to the `$helpers` array in **app/Config/Autoload.php**: + + ```php + public $helpers = ['auth', 'setting']; + ``` + +2. Remove the following code in the `initController()` method in + `**app/Controllers/BaseController.php**: + + ```php + $this->helpers = array_merge($this->helpers, ['setting']); + ``` + ## Version 1.0.0-beta.6 to 1.0.0-beta.7 ### The minimum CodeIgniter version diff --git a/composer.json b/composer.json index d7a4327bd..a412e5817 100644 --- a/composer.json +++ b/composer.json @@ -52,9 +52,6 @@ "psr-4": { "CodeIgniter\\Shield\\": "src" }, - "files": [ - "src/Helpers/auth_helper.php" - ], "exclude-from-classmap": [ "**/Database/Migrations/**" ] diff --git a/docs/getting_started/install.md b/docs/getting_started/install.md index c608bd3f3..2f9534e3f 100644 --- a/docs/getting_started/install.md +++ b/docs/getting_started/install.md @@ -72,7 +72,8 @@ your project. ### Manual Setup -1. Copy the **Auth.php**, **AuthGroups.php**, and **AuthToken.php** from **vendor/codeigniter4/shield/src/Config/** into your project's config folder and update the namespace to `Config`. You will also need to have these classes extend the original classes. See the example below. These files contain all the settings, group, and permission information for your application and will need to be modified to meet the needs of your site. +1. **Config Setup:** + Copy the **Auth.php**, **AuthGroups.php**, and **AuthToken.php** from **vendor/codeigniter4/shield/src/Config/** into your project's config folder and update the namespace to `Config`. You will also need to have these classes extend the original classes. See the example below. These files contain all the settings, group, and permission information for your application and will need to be modified to meet the needs of your site. ```php // new file - app/Config/Auth.php @@ -91,29 +92,26 @@ your project. } ``` -2. **Helper Setup** The `setting` helper needs to be included in almost every page. The simplest way to do this is to add it to the `BaseController::initController()` method: +2. **Helper Setup:** + The `auth` and `setting` helpers need to be included in almost every page. + The simplest way to do this is to add it to the **app/Config/Autoload.php** file: ```php - public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) - { - $this->helpers = array_merge($this->helpers, ['setting']); - - // Do Not Edit This Line - parent::initController($request, $response, $logger); - } + public $helpers = ['auth', 'setting']; ``` - This requires that all of your controllers extend the `BaseController`, but that's a good practice anyway. - -3. **Routes Setup** The default auth routes can be setup with a single call in **app/Config/Routes.php**: +3. **Routes Setup:** + The default auth routes can be setup with a single call in **app/Config/Routes.php**: ```php service('auth')->routes($routes); ``` -4. **Security Setup** Set `Config\Security::$csrfProtection` to `'session'` for security reasons, if you use Session Authenticator. +4. **Security Setup:** + Set `Config\Security::$csrfProtection` to `'session'` for security reasons, if you use Session Authenticator. -5. Configure **app/Config/Email.php** to allow Shield to send emails with the [Email Class](https://codeigniter.com/user_guide/libraries/email.html). +5. **Email Setup:** + Configure **app/Config/Email.php** to allow Shield to send emails. ```php getProvider(); !!! note - The `auth_helper` is autoloaded by Composer. If you want to *override* the functions, - you need to define them in **app/Common.php**. + The `auth_helper` is autoloaded by CodeIgniter's autoloader if you follow the + installation instruction. If you want to *override* the functions, create + **app/Helpers/auth_helper.php**. ## Authenticator Responses diff --git a/src/Authentication/Authenticators/Session.php b/src/Authentication/Authenticators/Session.php index c5e9ba138..e15fba3ae 100644 --- a/src/Authentication/Authenticators/Session.php +++ b/src/Authentication/Authenticators/Session.php @@ -73,8 +73,6 @@ class Session implements AuthenticatorInterface public function __construct(UserModel $provider) { - helper('setting'); - $this->provider = $provider; $this->loginModel = model(LoginModel::class); diff --git a/src/Authorization/Groups.php b/src/Authorization/Groups.php index 918168ec3..ae223fb44 100644 --- a/src/Authorization/Groups.php +++ b/src/Authorization/Groups.php @@ -13,13 +13,6 @@ */ class Groups { - public function __construct() - { - if (! function_exists('setting')) { - helper('setting'); - } - } - /** * Grabs a group info from settings. */ diff --git a/src/Authorization/Traits/Authorizable.php b/src/Authorization/Traits/Authorizable.php index 6cee326ce..eb57cd788 100644 --- a/src/Authorization/Traits/Authorizable.php +++ b/src/Authorization/Traits/Authorizable.php @@ -259,9 +259,7 @@ public function can(string ...$permissions): bool return false; } - $matrix = function_exists('setting') - ? setting('AuthGroups.matrix') - : config('AuthGroups')->matrix; + $matrix = setting('AuthGroups.matrix'); foreach ($this->groupCache as $group) { // Check exact match @@ -396,9 +394,7 @@ private function saveGroupsOrPermissions(string $type, $model, array $cache): vo */ private function getConfigGroups(): array { - return function_exists('setting') - ? array_keys(setting('AuthGroups.groups')) - : array_keys(config('AuthGroups')->groups); + return array_keys(setting('AuthGroups.groups')); } /** @@ -406,8 +402,6 @@ private function getConfigGroups(): array */ private function getConfigPermissions(): array { - return function_exists('setting') - ? array_keys(setting('AuthGroups.permissions')) - : array_keys(config('AuthGroups')->permissions); + return array_keys(setting('AuthGroups.permissions')); } } diff --git a/src/Commands/Setup.php b/src/Commands/Setup.php index a39e7de10..f4b14657e 100644 --- a/src/Commands/Setup.php +++ b/src/Commands/Setup.php @@ -8,6 +8,7 @@ use CodeIgniter\Commands\Database\Migrate; use CodeIgniter\Shield\Commands\Setup\ContentReplacer; use CodeIgniter\Test\Filters\CITestStreamFilter; +use Config\Autoload as AutoloadConfig; use Config\Email as EmailConfig; use Config\Services; @@ -78,7 +79,7 @@ private function publishConfig(): void $this->publishConfigAuthGroups(); $this->publishConfigAuthToken(); - $this->setupHelper(); + $this->setAutoloadHelpers(); $this->setupRoutes(); $this->setSecurityCSRF(); @@ -236,24 +237,55 @@ private function replace(string $file, array $replaces): bool return false; } - private function setupHelper(): void + private function setAutoloadHelpers(): void { - $file = 'Controllers/BaseController.php'; - $check = '$this->helpers = array_merge($this->helpers, [\'setting\']);'; + $file = 'Config/Autoload.php'; + + $path = $this->distPath . $file; + $cleanPath = clean_path($path); + + $config = new AutoloadConfig(); + $helpers = $config->helpers; + $newHelpers = array_unique(array_merge($helpers, ['auth', 'setting'])); + + $pattern = '/^ public \$helpers = \[.*\];/mu'; + $replace = ' public $helpers = [\'' . implode("', '", $newHelpers) . '\'];'; + $content = file_get_contents($path); + $output = preg_replace($pattern, $replace, $content); + + // check if the content is updated + if ($output === $content) { + $this->write(CLI::color(' Autoload Setup: ', 'green') . 'Everything is fine.'); + + return; + } + + if (write_file($path, $output)) { + $this->write(CLI::color(' Updated: ', 'green') . $cleanPath); + + $this->removeHelperLoadingInBaseController(); + } else { + $this->error(" Error updating file '{$cleanPath}'."); + } + } + + private function removeHelperLoadingInBaseController(): void + { + $file = 'Controllers/BaseController.php'; + + $check = ' $this->helpers = array_merge($this->helpers, [\'setting\']);'; // Replace old helper setup $replaces = [ '$this->helpers = array_merge($this->helpers, [\'auth\', \'setting\']);' => $check, ]; - if ($this->replace($file, $replaces)) { - return; - } - - // Add helper setup - $pattern = '/(' . preg_quote('// Do Not Edit This Line', '/') . ')/u'; - $replace = $check . "\n\n " . '$1'; + $this->replace($file, $replaces); - $this->add($file, $check, $pattern, $replace); + // Remove helper setup + $replaces = [ + "\n" . $check . "\n" => '', + ]; + $this->replace($file, $replaces); } private function setupRoutes(): void diff --git a/src/Controllers/ActionController.php b/src/Controllers/ActionController.php index 805df0b88..8bcbb4f80 100644 --- a/src/Controllers/ActionController.php +++ b/src/Controllers/ActionController.php @@ -18,7 +18,6 @@ class ActionController extends BaseController { protected ?ActionInterface $action = null; - protected $helpers = ['setting']; /** * Perform an initial check if we have a valid action or not. diff --git a/src/Controllers/LoginController.php b/src/Controllers/LoginController.php index e38fa3817..0dc49436e 100644 --- a/src/Controllers/LoginController.php +++ b/src/Controllers/LoginController.php @@ -14,8 +14,6 @@ class LoginController extends BaseController { use Viewable; - protected $helpers = ['setting']; - /** * Displays the form the login to the site. * diff --git a/src/Controllers/MagicLinkController.php b/src/Controllers/MagicLinkController.php index 25ab09d99..3357f3d7d 100644 --- a/src/Controllers/MagicLinkController.php +++ b/src/Controllers/MagicLinkController.php @@ -34,8 +34,6 @@ class MagicLinkController extends BaseController public function __construct() { - helper('setting'); - /** @var class-string $providerClass */ $providerClass = setting('Auth.userProvider'); diff --git a/src/Controllers/RegisterController.php b/src/Controllers/RegisterController.php index 20daf5f73..43761b990 100644 --- a/src/Controllers/RegisterController.php +++ b/src/Controllers/RegisterController.php @@ -27,8 +27,6 @@ class RegisterController extends BaseController { use Viewable; - protected $helpers = ['setting']; - public function initController( RequestInterface $request, ResponseInterface $response, diff --git a/src/Filters/ForcePasswordResetFilter.php b/src/Filters/ForcePasswordResetFilter.php index bfa3d21aa..ce64492b4 100644 --- a/src/Filters/ForcePasswordResetFilter.php +++ b/src/Filters/ForcePasswordResetFilter.php @@ -32,8 +32,6 @@ public function before(RequestInterface $request, $arguments = null) return; } - helper('setting'); - /** @var Session $authenticator */ $authenticator = auth('session')->getAuthenticator(); diff --git a/src/Filters/HmacAuth.php b/src/Filters/HmacAuth.php index f655d0264..986175caa 100644 --- a/src/Filters/HmacAuth.php +++ b/src/Filters/HmacAuth.php @@ -23,8 +23,6 @@ public function before(RequestInterface $request, $arguments = null) { $authenticator = auth('hmac')->getAuthenticator(); - helper('setting'); - $requestParams = [ 'token' => $request->getHeaderLine(setting('Auth.authenticatorHeader')['hmac'] ?? 'Authorization'), 'body' => $request->getBody() ?? '', diff --git a/src/Filters/JWTAuth.php b/src/Filters/JWTAuth.php index 84914511b..735bf2f2d 100644 --- a/src/Filters/JWTAuth.php +++ b/src/Filters/JWTAuth.php @@ -33,8 +33,6 @@ public function before(RequestInterface $request, $arguments = null) return; } - helper('setting'); - /** @var JWT $authenticator */ $authenticator = auth('jwt')->getAuthenticator(); diff --git a/src/Filters/SessionAuth.php b/src/Filters/SessionAuth.php index b7d449666..18ec1a571 100644 --- a/src/Filters/SessionAuth.php +++ b/src/Filters/SessionAuth.php @@ -39,8 +39,6 @@ public function before(RequestInterface $request, $arguments = null) return; } - helper('setting'); - /** @var Session $authenticator */ $authenticator = auth('session')->getAuthenticator(); diff --git a/src/Filters/TokenAuth.php b/src/Filters/TokenAuth.php index 4425c14ff..8094f8f38 100644 --- a/src/Filters/TokenAuth.php +++ b/src/Filters/TokenAuth.php @@ -39,8 +39,6 @@ public function before(RequestInterface $request, $arguments = null) return; } - helper('setting'); - /** @var AccessTokens $authenticator */ $authenticator = auth('tokens')->getAuthenticator(); diff --git a/src/Helpers/email_helper.php b/src/Helpers/email_helper.php index 0e4961790..09a99e480 100644 --- a/src/Helpers/email_helper.php +++ b/src/Helpers/email_helper.php @@ -12,8 +12,6 @@ */ function emailer(array $overrides = []): Email { - helper('setting'); - $config = [ 'userAgent' => setting('Email.userAgent'), 'protocol' => setting('Email.protocol'), diff --git a/src/Validation/ValidationRules.php b/src/Validation/ValidationRules.php index 33ab171f2..4f38a7c64 100644 --- a/src/Validation/ValidationRules.php +++ b/src/Validation/ValidationRules.php @@ -27,8 +27,6 @@ public function __construct() public function getRegistrationRules(): array { - helper('setting'); - $setting = setting('Validation.registration'); if ($setting !== null) { return $setting; @@ -59,8 +57,6 @@ public function getRegistrationRules(): array public function getLoginRules(): array { - helper('setting'); - return setting('Validation.login') ?? [ // 'username' => $this->config->usernameValidationRules, 'email' => $this->config->emailValidationRules, diff --git a/tests/Commands/SetupTest.php b/tests/Commands/SetupTest.php index 648f0f12e..3401295a0 100644 --- a/tests/Commands/SetupTest.php +++ b/tests/Commands/SetupTest.php @@ -65,6 +65,9 @@ public function testRun(): void $this->assertStringContainsString('namespace Config;', $authToken); $this->assertStringContainsString('use CodeIgniter\Shield\Config\AuthToken as ShieldAuthToken;', $authToken); + $autoload = file_get_contents($appFolder . 'Config/Autoload.php'); + $this->assertStringContainsString('$helpers = [\'auth\', \'setting\'];', $autoload); + $routes = file_get_contents($appFolder . 'Config/Routes.php'); $this->assertStringContainsString('service(\'auth\')->routes($routes);', $routes); @@ -77,7 +80,7 @@ public function testRun(): void ' Created: vfs://root/Config/Auth.php Created: vfs://root/Config/AuthGroups.php Created: vfs://root/Config/AuthToken.php - Updated: vfs://root/Controllers/BaseController.php + Updated: vfs://root/Config/Autoload.php Updated: vfs://root/Config/Routes.php Updated: We have updated file \'vfs://root/Config/Security.php\' for security reasons. Updated: vfs://root/Config/Email.php', @@ -112,7 +115,7 @@ public function testRunEmailConfigIsFine(): void ' Created: vfs://root/Config/Auth.php Created: vfs://root/Config/AuthGroups.php Created: vfs://root/Config/AuthToken.php - Updated: vfs://root/Controllers/BaseController.php + Updated: vfs://root/Config/Autoload.php Updated: vfs://root/Config/Routes.php Updated: We have updated file \'vfs://root/Config/Security.php\' for security reasons.', $result diff --git a/tests/_support/TestCase.php b/tests/_support/TestCase.php index 22ba985d6..021fccfd9 100644 --- a/tests/_support/TestCase.php +++ b/tests/_support/TestCase.php @@ -26,8 +26,10 @@ protected function setUp(): void $settings = new Settings($configSettings); Services::injectMock('settings', $settings); + // Load helpers that should be autoloaded + helper(['auth', 'setting']); + // Ensure from email is available anywhere during Tests - helper('setting'); setting('Email.fromEmail', 'foo@example.com'); setting('Email.fromName', 'John Smith');