Skip to content

Leaf 5 โ€” Mail, Fetch & HTTP Cache Reference โ€‹

Mail โ€‹

bash
leaf install mail

Connecting โ€” Basic App โ€‹

php
mailer()->connect([
    'host'      => 'smtp.mailtrap.io',
    'port'      => 2525,
    'security'  => 'STARTTLS',
    'auth'      => ['username' => '...', 'password' => '...'],
    'debug'     => 'SERVER',   // 'SERVER', false, or PHPMailer SMTPDebug value
    'keepAlive' => true,
    'defaults'  => [
        'senderName'    => 'My App',
        'senderEmail'   => 'no-reply@myapp.com',
        'replyToName'   => 'Support',
        'replyToEmail'  => 'support@myapp.com',
    ],
]);

Connecting โ€” MVC (via .env) โ€‹

env
MAIL_HOST=sandbox.smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=xxx
MAIL_PASSWORD=xxx
MAIL_DEBUG=SERVER
MAIL_SENDER_NAME='Leaf MVC'
MAIL_SENDER_EMAIL=user@example.com

For advanced config (OAuth, etc.):

bash
leaf config:publish mail   # โ†’ config/mail.php

Creating & Sending Mail โ€‹

php
$mail = mailer()->create([
    'subject'        => 'Hello!',
    'body'           => 'This is the email body.',
    'recipientEmail' => 'user@example.com',
    'recipientName'  => 'John Doe',
    'senderName'     => 'My App',        // optional if set in defaults
    'senderEmail'    => 'app@myapp.com', // optional if set in defaults
    'replyToName'    => 'Support',
    'replyToEmail'   => 'support@myapp.com',
    'cc'             => 'cc@example.com',
    'bcc'            => 'bcc@example.com',
    'isHtml'         => true,
    'altBody'        => 'Plain text fallback for clients without HTML support.',
]);

$mail->send();

if (!$mail->send()) {
    $errors = $mail->errors();  // errors tied to this specific mail object
}

Attachments โ€‹

php
mailer()
    ->create([/* ... */])
    ->attach('./invoice.pdf')
    ->attach(['./file1.txt', './file2.txt'])
    ->send();

Blade Templates (MVC) โ€‹

php
mailer()->create([
    'subject' => 'Welcome!',
    'body'    => view('emails.welcome', ['user' => $user]),
]);

MVC Mailers โ€‹

Generate a mailer class:

bash
leaf g:mailer welcome   # โ†’ app/mailers/WelcomeMailer.php
php
namespace App\Mailers;

class WelcomeMailer
{
    public static function firstLogin($user)
    {
        return mailer()->create([
            'subject'        => 'Welcome to Leaf MVC!',
            'body'           => 'We are excited to have you on board.',
            'recipientEmail' => $user->email,
            'recipientName'  => $user->name,
        ]);
    }
}

Use from a controller, job, or anywhere:

php
use App\Mailers\WelcomeMailer;

WelcomeMailer::firstLogin($user)->send();

Fetch (HTTP Client) โ€‹

bash
leaf install fetch

Inspired by JavaScript's Fetch API and Axios.

GET Requests โ€‹

php
$res = fetch('https://jsonplaceholder.typicode.com/todos/1');
$res = fetch()->get('https://jsonplaceholder.typicode.com/todos/1');

response()->json($res->data);  // data, status, headers, request

Other Methods โ€‹

php
$res = fetch()->post('https://api.example.com/posts', [
    'title' => 'foo',
    'body'  => 'bar',
]);
fetch()->put($url, $data);
fetch()->patch($url, $data);
fetch()->delete($url);
fetch()->head($url);
fetch()->options($url);

response()->json($res->data);

Full Options โ€‹

php
$res = fetch([
    'method' => 'PUT',
    'url'    => 'https://api.example.com/resource/1',
    'data'   => ['firstName' => 'Fred'],
]);

Base URL โ€‹

php
fetch()->baseUrl('https://jsonplaceholder.typicode.com');

$res = fetch('/todos');               // โ†’ typicode.com/todos
$res = fetch()->post('/posts', [...]);

All Request Options โ€‹

OptionDefaultDescription
urlโ€”Request URL
method'GET'HTTP method
baseUrl''Prepended to url unless url is absolute
headers[]Custom headers
params[]URL query parameters (appended for any method)
data[]Request body, JSON-encoded by default; form-encoded with a application/x-www-form-urlencoded Content-Type header; becomes query params on GET
timeout0Timeout in seconds (0 = no timeout)
auth[]HTTP Basic auth: ['username' => ..., 'password' => ...]
maxRedirects5Max redirects (0 = none)
rawResponsefalseSkip JSON parsing
verifyHosttrueSSL host verification
verifyPeertrueSSL peer verification
curl[]Additional curl options, applied last so they win

Non-2xx statuses return normally (check $res->status); only network-level failures (unreachable host, timeout) throw \Exception. Response header names are lower cased. Non-JSON bodies are returned as the raw string. Fetch::config([...]) updates defaults app-wide.


HTTP Cache โ€‹

php
use Leaf\Http\Cache;

Use either etag() OR lastModified() per route โ€” never both together. Call them before other route code.

ETag โ€‹

php
app()->get('/resource', function () {
    Cache::etag('unique-resource-tag');  // change tag when resource changes
    echo 'Cached after first request';
});

Last Modified โ€‹

php
app()->get('/resource', function () {
    Cache::lastModified(1617383991);     // UNIX timestamp of last modification
    echo 'Cached after first request';
});

Expires โ€‹

Use with etag() or lastModified() to set client-side cache expiry:

php
app()->get('/resource', function () {
    Cache::etag('unique-tag');
    Cache::expires('+1 week');    // string (strtotime) or UNIX timestamp
    echo 'Cached for one week';
});

Custom Cache Headers โ€‹

php
use Leaf\Http\Headers;

app()->get('/resource', function () {
    Headers::set('Cache-Control', 'public, max-age=3600');
    echo 'Cached for 1 hour';
});