Leaf 5 โ Mail, Fetch & HTTP Cache Reference โ
Mail โ
leaf install mailConnecting โ Basic App โ
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) โ
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.comFor advanced config (OAuth, etc.):
leaf config:publish mail # โ config/mail.phpCreating & Sending Mail โ
$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 โ
mailer()
->create([/* ... */])
->attach('./invoice.pdf')
->attach(['./file1.txt', './file2.txt'])
->send();Blade Templates (MVC) โ
mailer()->create([
'subject' => 'Welcome!',
'body' => view('emails.welcome', ['user' => $user]),
]);MVC Mailers โ
Generate a mailer class:
leaf g:mailer welcome # โ app/mailers/WelcomeMailer.phpnamespace 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:
use App\Mailers\WelcomeMailer;
WelcomeMailer::firstLogin($user)->send();Fetch (HTTP Client) โ
leaf install fetchInspired by JavaScript's Fetch API and Axios.
GET Requests โ
$res = fetch('https://jsonplaceholder.typicode.com/todos/1');
$res = fetch()->get('https://jsonplaceholder.typicode.com/todos/1');
response()->json($res->data); // data, status, headers, requestOther Methods โ
$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 โ
$res = fetch([
'method' => 'PUT',
'url' => 'https://api.example.com/resource/1',
'data' => ['firstName' => 'Fred'],
]);Base URL โ
fetch()->baseUrl('https://jsonplaceholder.typicode.com');
$res = fetch('/todos'); // โ typicode.com/todos
$res = fetch()->post('/posts', [...]);All Request Options โ
| Option | Default | Description |
|---|---|---|
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 |
timeout | 0 | Timeout in seconds (0 = no timeout) |
auth | [] | HTTP Basic auth: ['username' => ..., 'password' => ...] |
maxRedirects | 5 | Max redirects (0 = none) |
rawResponse | false | Skip JSON parsing |
verifyHost | true | SSL host verification |
verifyPeer | true | SSL 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 โ
use Leaf\Http\Cache;Use either
etag()ORlastModified()per route โ never both together. Call them before other route code.
ETag โ
app()->get('/resource', function () {
Cache::etag('unique-resource-tag'); // change tag when resource changes
echo 'Cached after first request';
});Last Modified โ
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:
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 โ
use Leaf\Http\Headers;
app()->get('/resource', function () {
Headers::set('Cache-Control', 'public, max-age=3600');
echo 'Cached for 1 hour';
});