2

I have a PHP Laravel app that has an Elequent Model for EmailTokenUrlLogin and a Controller to login a user by accessing a URL with a token value in the URL.

I would like to have a function that will create a new Model/DB record to generate the token for a user and be able to call this function from any other Controller or Model in my app.

Right now I have it in my Login Controller however I am not happy with this as it requires either a POST request to post all the required function parameters or else a GET request with a long complicated URL of parameters.

So I want my function below generateShortLifeEmailTokenUrl($user_id, $email, $expireType, $expireNumber = '') to live somewhere in the app in which I can call it from anywhere.

Where would a function like below best be located and how to make it callable from other models and controllers?

public function generateShortLifeEmailTokenUrl($user_id, $email, $expireType, $expireNumber = '')
{
    if(Auth::user()->isAdmin){

        // generate a new token
        // ... other logic here......

        // create model and DB record and return the created token value
        $emailTokenUrlLoginData = new EmailTokenUrlLogin;
        $emailTokenUrlLoginData->user_id = $user_id;
        $emailTokenUrlLoginData->email = $email;
        $emailTokenUrlLoginData->token = $createToken();
        $emailTokenUrlLoginData->expireType = $expireType;
        $emailTokenUrlLoginData->expireNumber = $expireNumber;
        $emailTokenUrlLoginData->save();

        // return generated token
        return $emailTokenUrlLoginData->token;            
    }

}
JasonDavis
  • 48,204
  • 100
  • 318
  • 537

3 Answers3

3

This really depends on how sophisticated you want to your code to be.

If you really just need this in one controller action, you can just place the code there. Or you can create a private method on that controller that does the job. Advanced programmers will consider this a bad practice, but for a small application it's good enough.

Alexeys suggestion with the global function works as well, but is considered an even worse practice because it's global. If you make all your functions global, your global scope and namespace will be full of unrelated stuff that will eventually get in the way of each other. Again, for a small application you will probably be fine, though.

Now, if you're curious about what a better practice would be: the keywords are services and dependency injection. That's not something I'm going to explain right here, but there are lots of resources on the web that will help you understand how these concepts work and what the benefits are.

Laravel has built in support for depencency injection, you can read all about it in the documentation.

LorenzSchaef
  • 1,523
  • 10
  • 16
3

Put it in a trait, and bind the trait to any other class where it is needed. You will not need to make it public that way, and can access it anywhere it is needed. Trait methods are compiled into the class as if there were native class methods, but can be overruled within the class as needed.

See: http://php.net/manual/en/language.oop5.traits.php

Trait EmailTokenTrait {
    protected function generateShortLifeEmailTokenUrl($user_id, $email, $expireType, $expireNumber = '')
{
    ...
}

Bind the trait to whatever class:

<?php
namespace \some\namespace;

class SomeClass {

    use \EmailTokenTrait;

    protected function someFunction() {
        $token = $this->generateShortLifeEmailTokenUrl($user_id, $email, $expireType);
    }
}

Then autoload the trait.

"autoload": {
    ....
    "files": [
        "app/traits/EmailTokenTrait.php"
    ]
},
mopsyd
  • 1,877
  • 3
  • 20
  • 30
1

If you're working with this function a lot, you can create global helper:

if (! function_exists('generateShortLifeEmailTokenUrl')) {
    function generateShortLifeEmailTokenUrl($user_id, $email, $expireType, $expireNumber = '')
    {
        ....
    }
}

Put it in helpers.php and add this to composer.json to load the helpers:

"autoload": {
    ....
    "files": [
        "app/someFolder/helpers.php"
    ]
},
Community
  • 1
  • 1
Alexey Mezenin
  • 158,981
  • 26
  • 290
  • 279
  • This is useful and I will likely do this in my app, even if not for this problem but for other parts of my app to use as well. You mentioned `If you're working with this function a lot,` In this case I actually will not need it a lot but only 1 call to the function from an admin controller or model to issue short life token based logins to be used in emails and stuff as an example. So if an email sent to a user could have a quick login URL from the email. I have seen this done before in large apps like facebook and other where a special link in an email would log you in automatically. – JasonDavis Dec 12 '16 at 22:02
  • So just curious I guess if it doesn't have a lot of usage, is there some other place to put the function you have in mind maybe? I saw in the docs you can call a controller function from with code but I am not sure if it ends up simply redirecting to a route or if it actually calls the method. If it calls the method and would allow to pass parameters as POST data then that might be another option for this particular case – JasonDavis Dec 12 '16 at 22:02
  • @JasonDavis if you're using it just in one model and one or few controllers, I guess the best way would be putting the method in that model. Definitely do not put it in a controller if you also call this method from model or another controller. – Alexey Mezenin Dec 12 '16 at 22:06