lonnieezell / myth-auth

One-stop Auth package for CodeIgniter 4
MIT License
632 stars 207 forks source link

Helper not loading in BaseController - Call to undefined function logged_in() #486

Closed amityweb closed 2 years ago

amityweb commented 2 years ago

Sorry for my ignorance, but I can't get the auth helper to load sitewide. Added auth to helpers in BaseController, but still get the error Call to undefined function logged_in(). I dont want to add <?php helper('auth');?> in all my views, nor in any controller class. In fact I need it in the layout and there is no controller for that. Should I be adding it to your AuthController.php, as it works when in there, although I wouldn't want to edit any of your source files (apart from config to change to my own views). Thanks

class BaseController extends Controller
{
    protected $helpers = ['auth'];
bedrijfsportaal commented 2 years ago

I think it has to do something with non-standard paths

see: https://codeigniter.com/user_guide/general/helpers.html#loading-from-non-standard-locations

amityweb commented 2 years ago

According to that, I guess this would work but it doesn't: helper('Myth\Auth\auth'); I put this in the BaseController->initController

P.S. I didnt realise there was a Discussions tab when creating this. The question would have been better suited in there I guess.

MGatner commented 2 years ago

Are you sure all controllers are extending BaseController? If you use third-party modules or other namespaces they might not load your helpers.

For helpers that I know I need super-globally I usually add them to app/Config/Events.php which ensures they are available during Filters, etc.

E.g. https://github.com/duke-bluesmith/bluesmith/blob/develop/app/Config/Events.php

amityweb commented 2 years ago

But I am using this mythauth package, so the helper is needed on those pages. I should have been more clear...

If I put helper('auth'); in my BaseController, then the pages I have created in my app, for example, Home, About etc. which I have created controllers for does work.

But if I go to a Login page that is using MythAuth controllers, then it shows the issue.

Looking in the myth auth code, the AuthController does not extend BaseController, it extends Controller.

So I guess this is the issue, even though mythauth states add helper('auth'); to use it site wide, it wont work on its own package views as its not extending BaseController.

And I dont want to change mythauth code.

amityweb commented 2 years ago

Changing myth AuthController to the following works, but I would not want to change it:


use App\Controllers\BaseController;

class AuthController extends BaseController
{
amityweb commented 2 years ago

Extending AuthController works, but I would prefer not to just for this. I would think it best AuthController extend BaseController??

Add this to Config/Routes.php

$routes->get('login', 'AuthController::login', ['as' => 'login']);
$routes->post('login', 'AuthController::attemptLogin');
$routes->get('logout', 'AuthController::logout');

// Registration
$routes->get('register', 'AuthController::register', ['as' => 'register']);
$routes->post('register', 'AuthController::attemptRegister');

// Activation
$routes->get('activate-account', 'AuthController::activateAccount', ['as' => 'activate-account']);
$routes->get('resend-activate-account', 'AuthController::resendActivateAccount', ['as' => 'resend-activate-account']);

// Forgot/Resets
$routes->get('forgot', 'AuthController::forgotPassword', ['as' => 'forgot']);
$routes->post('forgot', 'AuthController::attemptForgot');
$routes->get('reset-password', 'AuthController::resetPassword', ['as' => 'reset-password']);
$routes->post('reset-password', 'AuthController::attemptReset');

Then create Controllers/AuthController.php

<?php namespace App\Controllers;

use Myth\Auth\Controllers\AuthController As mythAuthController;

class AuthController extends mythAuthController
{
    public function __construct()
    {
        parent::__construct();
        helper('auth');
    }
}
bedrijfsportaal commented 2 years ago

BaseController isn't something that works on default, Controller does so I think that's the reason it's extending Controller class.

amityweb commented 2 years ago

Well, its just the docs state the following which is not quite the case. The following works on my own controllers, but not when on any Myth Auth page so its wrong to state this. Perhaps its the last sentence that has the issue, in that it is not working on Myth Auth routes automatically. Not when I call it in my layout view anyway. Hint: Add 'auth' to any controller's $helper property to have it loaded automatically, or the same in app/Controllers/BaseController.php to have it globally available. the auth filters all pre-load the helper so it is available on any filtered routes.

MGatner commented 2 years ago

What part of that do you consider "wrong"? The "globally available"? They will apply to any controller that extends BaseController - if it feels misleading to say "globally" that should be tweaked. The filters definitely all load the helper (e.g. https://github.com/lonnieezell/myth-auth/blob/e84d0660cd42bbe84077613e141d5acf683020cd/src/Filters/LoginFilter.php#L22).

amityweb commented 2 years ago

By wrong I mean it says if I add it in my basecontroller it’s available globally. But it’s not available on the myth auth pages like login etc. I have a is_logged() in helper in my view layout in the header and it when I load the login, register pages it shows the error that logged_in() is not defined. So it’s not calling the helper.

So adding to base controller does not make it available globally because it’s not loading it in myth.

If myth loads it on its own pages then I seem to have the added issue that the myth one is not loading. Could it be due to me using my own view files for myth?

MGatner commented 2 years ago

Seems to be two issues here. For "globally available" you would need to send a PR to the framework repo to change the wording so it isn't misleading. That makes sense.

For your View issue, are you using your own helper in addition to Myth's? Or have you overridden Myth's helper with your own "auth_helper.php"?

amityweb commented 2 years ago

No we dont have our own auth_helper file. What we have done to override Myth is:

Override it's views by placing them in our own Views folder, because we wan't to use our own layout and form styling classes.

Added this to Config/Routes.php:-

/* Override MythAuth Controller so we can extend BaseController to add helper */
$routes->get('login', 'AuthController::login', ['as' => 'login']);
$routes->post('login', 'AuthController::attemptLogin');
$routes->get('logout', 'AuthController::logout');

// Registration
$routes->get('register', 'AuthController::register', ['as' => 'register']);
$routes->post('register', 'AuthController::attemptRegister');

// Activation
$routes->get('activate-account', 'AuthController::activateAccount', ['as' => 'activate-account']);
$routes->get('resend-activate-account', 'AuthController::resendActivateAccount', ['as' => 'resend-activate-account']);

// Forgot/Resets
$routes->get('forgot', 'AuthController::forgotPassword', ['as' => 'forgot']);
$routes->post('forgot', 'AuthController::attemptForgot');
$routes->get('reset-password', 'AuthController::resetPassword', ['as' => 'reset-password']);
$routes->post('reset-password', 'AuthController::attemptReset');

Created a Config/Auth.php file:

<?php
namespace Config;

use Myth\Auth\Config\Auth as MythAuth;

class Auth extends MythAuth
{
    // Add extra fields to $validFields
    function __construct()
    {
        parent::__construct();

        // Only use email for login
        $this->validFields = [
            'email',
            'username',
            'name'
        ];
    }

    /**
     * --------------------------------------------------------------------
     * Views used by Auth Controllers
     * --------------------------------------------------------------------
     *
     * @var array
     */
    public $views = [
        'login'        => '/auth/login',
        'register'      => '/auth/register',
        'forgot'          => '/auth/forgot',
        'reset'        => '/auth/reset',
        'emailForgot'    => '/auth/emails/forgot',
        'emailActivation' => '/auth/emails/activation',
    ];

    /**
     * --------------------------------------------------------------------
     * Layout for the views to extend
     * --------------------------------------------------------------------
     *
     * @var string
     */
    public $viewLayout = '/layouts/default';

}

Add Auth Filter to Config/Filters.php:

    public $aliases = [
        'csrf'          => CSRF::class,
        'toolbar'       => DebugToolbar::class,
        'honeypot'      => Honeypot::class,
        'invalidchars'  => InvalidChars::class,
        'secureheaders' => SecureHeaders::class,
    'login'         => \Myth\Auth\Filters\LoginFilter::class,
    'role'          => \Myth\Auth\Filters\RoleFilter::class,
    'permission'    => \Myth\Auth\Filters\PermissionFilter::class,
   ];
amityweb commented 2 years ago

Another issue with Myth not using BaseController is I can't load other helpers for the login pages.

I have helpers I want to use in my layouts navigation which is on all pages, and so want to load it "globally" in the BaseController, but its not found on Myth views.

So for the moment, I think the only way is overriding the AuthController?

<?php namespace App\Controllers;

use Myth\Auth\Controllers\AuthController As mythAuthController;

class AuthController extends mythAuthController
{
    public function __construct()
    {
        parent::__construct();
        helper(['auth', 'general']);
    }
}
MGatner commented 2 years ago

It seems to me like there is something fishy going on, but your configuration looks good. Since the crux of your issues seems to be all about the helper files, let's just address that directly and see if other things crop up later.

There is nothing special about BaseController's relationship with Helpers. You can load a helper anywhere you need it. If you want some more global then stick their loading in one of the places earlier in the bootstrap process. I personally like to use app/Config/Events.php for "global helpers", either loading them during post_controller_constructor or pre_system. You could see if that solution works for you. Here is an example:

https://github.com/duke-bluesmith/bluesmith/blob/develop/app/Config/Events.php

amityweb commented 2 years ago

I didn't know how to add it in Events, until you sent that link above, so now I know I have done that and its working. Looks a better approach than overriding AuthController, so thanks a lot for your help.