We’ve already covered a lot of ground, so we’re going to change gears and talk about helpers. In short, helpers are functions we can use from anywhere that do things for us quicker or more efficiently than we could otherwise do. It’s tricky to explain their use without looking at code, so that’s what we’re going to do.
These helpers are available, globally, so you won’t need to import most of them. I’ll tell you what the exceptions are, when it’s important.
The Request and Auth Helpers
This code can be found at https://github.com/assertchris/friday-server/tree/chapter-10.
We’re no stranger to the Request
class. It’s common for us to inject it into a controller action:
def show(self, request: Request, view: View):
return view.render('home', {
'name': request.param('name'),
})
What if we wanted to use the request from somewhere else? I’m not talking about whether we should, or not, but rather, “could we?”
An obvious place we might want to use it would be in the view:
@block content
hello {{ request().param('name') }}
@endblock
If you like this style, you may like using the
request helper in actions, as well:
from masonite.auth import Auth
from masonite.view import View
class HomeController:
def show(self, view: View, auth: Auth):
return view.render('home', {
'name': request().param('name') or request().input('name'),
})
Similarly, we can shorten the auth code by using an
Auth helper:
from masonite.view import View
class HomeController:
def show(self, view: View):
return view.render('home', {
'name': request().param('name') or auth().email,
})
This is from app/http/controllers/HomeController.py.
The
auth() function
can be super helpful, but be careful using it. If the user isn’t logged in, then
auth() will return
False. Your code should take that into account. It’s also great in the view layer:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link href="/static/style.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container mx-auto p-4">
@if (auth())
<a href="{{ route('logout') }}">log out</a>
@else
<a href="{{ route('login') }}">log in</a>
@endif
@block content
<!-- template content will be put here-->
@endblock
</div>
</body>
</html>
This is from resources/templates/layout.html.
The auth() function will return None if the user isn’t logged in, which can be reused to toggle UI based on the presence of a user session. This is also an example of another helper.
The Route Helper
The
Route helper is essential for larger apps, but you have to name your routes for it to work:
Get('/profile/@id', 'ProfileController@show').name('profile')
We can use the
route() function to build out any named route, including routes that we’ve defined parameters for:
<a href="{{ route('profile', { 'id': auth().id }) }}">public profile</a>
The Container and Resolve Helpers
Sometimes we may want to add our own classes and functions to the service container, we learned about in Chapter
. You may not always be inside an action with access to “the app,” but you can access the
container helper:
from app.Service import Service
container().bind('Service', Service)
container().make('Service')
Service is an example, here. Think of it as a placeholder for whatever custom class your next application may need.
This is great for extending things already in the container and for accessing things stored in the container from other contexts, like views and models. In a similar vein, it can be useful to resolve dependencies of a function, like Masonite does automatically for actions.
Here’s an example of how a controller action’s
request parameter is automatically
resolved:
from masonite.helpers import compact
def respond(request: Request):
action = request.param('action')
name = request.param('name')
if (action == 'read'):
return view('read.html', compact(name))
if (action == 'write'):
return view('write.html', compact(name))
def handle(self):
return resolve(respond)
The resolve helper takes another function and resolves the parameters it needs out of the container. This is also an example of our first non-global helper (the compact() function), which takes a list of variables and returns a dictionary where each key is the string variable name and each value is the variable’s value.
Non-global helpers are just helpers you still need to import in every file where they are used. Here, we’re importing the compact helper. You can make non-global helpers globally available by following a similar pattern to this: https://docs.masoniteproject.com/the-basics/helper-functions#introduction.
The Env and Config Helpers
env() and config() are closely related helpers, which pull configuration variables out of the environment (or .env files) and files within the config folder, respectively. The main difference between them, other than that they look in different files, is that data returned from env() is aggressively cached, whereas data returned from config() can be changed and lazy-loaded.
When using these, it’s best to only use
env() inside config files and only use
config() everywhere else:
FROM = {
'name': env('MAIL_FROM_NAME', 'Masonite')
}
This is from config/mail.py.
As this demonstrates, the second parameter to the
env() function
is a default value. This is great if or when the environment variable isn’t guaranteed to exist. Once the configuration variables are in a config file, we can pull them out with the
config() function
:
from config import mail as mail_config
print(mail_config.FROM['address'])
The Dump-and-Die Helper
Like so much of Masonite, the dump-and-die
helper is inspired by the same helper in Laravel:
https://laravel.com/docs/6.x/helpers#method-dd. It’s a quick way to stop what’s going on, so you can inspect the contents of multiple variables:
dd(User.find(1).email, request().params('email'))
It’s not a step debugger, but it’s great in a pinch!
Summary
In this chapter, we’ve taken a look at the most popular helper functions. They’re certainly not the only helper functions, so I encourage you to take a look at the documentation to learn more: https://docs.masoniteproject.com/the-basics/helper-functions. Chances are you’ll find something there that you like.
In the next chapter, we’re going to learn about all the different ways we can send notifications from our applications.