Skip to main content

Helpers & Functions

Helper functions provide convenient shortcuts for common operations. This guide covers creating, registering, and using helper functions.

Creating Helper Files

Helper files are stored in the Helpers/ directory:

Helpers/
├── functions.php # General helpers
├── validation.php # Validation-specific helpers
└── api.php # API-related helpers

Registering Helpers

Via module.json

Add helper files to the files array in module.json:

{
"name": "EmailValidator",
"alias": "emailvalidator",
"files": [
"Helpers/functions.php",
"Helpers/validation.php"
]
}

Files listed here are autoloaded globally and available throughout the application.

Via Composer

Add to your addon's composer.json:

{
"autoload": {
"psr-4": {
"Addons\\EmailValidator\\": ""
},
"files": [
"Helpers/functions.php"
]
}
}

Then run composer dump-autoload.

Writing Helper Functions

Basic Pattern

Always check if the function exists to prevent conflicts:

// Helpers/functions.php
<?php

if (!function_exists('email_validator_version')) {
/**
* Get the addon version
*/
function email_validator_version(): string
{
return config('emailvalidator.version', '1.0.0');
}
}

if (!function_exists('email_validator_enabled')) {
/**
* Check if email validation is enabled
*/
function email_validator_enabled(): bool
{
return config('emailvalidator.enabled', true);
}
}

Validation Helpers

// Helpers/validation.php
<?php

if (!function_exists('is_valid_email_format')) {
/**
* Check if email has valid format
*/
function is_valid_email_format(string $email): bool
{
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
}

if (!function_exists('is_disposable_email')) {
/**
* Check if email is from a disposable domain
*/
function is_disposable_email(string $email): bool
{
$domain = strtolower(substr(strrchr($email, '@'), 1));

return \Addons\EmailValidator\Entities\DisposableDomain::where('domain', $domain)->exists();
}
}

if (!function_exists('is_role_based_email')) {
/**
* Check if email is role-based (info@, admin@, etc.)
*/
function is_role_based_email(string $email): bool
{
$rolePatterns = [
'admin', 'administrator', 'info', 'contact', 'support',
'sales', 'marketing', 'help', 'webmaster', 'postmaster',
'hostmaster', 'abuse', 'noreply', 'no-reply'
];

$localPart = strtolower(explode('@', $email)[0]);

return in_array($localPart, $rolePatterns);
}
}

if (!function_exists('get_email_domain')) {
/**
* Extract domain from email address
*/
function get_email_domain(string $email): ?string
{
if (!is_valid_email_format($email)) {
return null;
}

return strtolower(substr(strrchr($email, '@'), 1));
}
}

if (!function_exists('normalize_email')) {
/**
* Normalize email address (lowercase, trim, handle plus addressing)
*/
function normalize_email(string $email, bool $removePlus = false): string
{
$email = strtolower(trim($email));

if ($removePlus) {
$parts = explode('@', $email);
$local = explode('+', $parts[0])[0];
$email = $local . '@' . $parts[1];
}

return $email;
}
}

API Helpers

// Helpers/api.php
<?php

if (!function_exists('email_validator_api_call')) {
/**
* Make API call to validation service
*/
function email_validator_api_call(string $endpoint, array $data = []): array
{
$baseUrl = config('emailvalidator.api.endpoint');
$apiKey = config('emailvalidator.api.key');
$timeout = config('emailvalidator.api.timeout', 30);

$client = new \GuzzleHttp\Client([
'base_uri' => $baseUrl,
'timeout' => $timeout,
'headers' => [
'Authorization' => 'Bearer ' . $apiKey,
'Content-Type' => 'application/json',
],
]);

try {
$response = $client->post($endpoint, [
'json' => $data,
]);

return json_decode($response->getBody(), true);
} catch (\Exception $e) {
\Log::error('Email Validator API Error', [
'endpoint' => $endpoint,
'error' => $e->getMessage(),
]);

throw $e;
}
}
}

if (!function_exists('email_validator_check_quota')) {
/**
* Check if user has validation quota remaining
*/
function email_validator_check_quota(?int $userId = null): array
{
$user = $userId ? \App\Models\User::find($userId) : auth()->user();

if (!$user) {
return ['has_quota' => false, 'remaining' => 0, 'limit' => 0];
}

$credits = $user->email_validation_credits ?? 0;

return [
'has_quota' => $credits > 0,
'remaining' => $credits,
'limit' => $user->package->email_validation_limit ?? 0,
];
}
}

User/Permission Helpers

// Helpers/functions.php
<?php

if (!function_exists('email_validator_can')) {
/**
* Check if current user can perform validation action
*/
function email_validator_can(string $action): bool
{
$user = auth()->user();

if (!$user) {
return false;
}

// Admin can do everything
if ($user->role_id === 1) {
return true;
}

// Check package permissions
$package = $user->package;
if (!$package) {
return false;
}

$permissions = json_decode($package->addon_permissions ?? '{}', true);

return $permissions['emailvalidator'][$action] ?? false;
}
}

if (!function_exists('email_validator_user_settings')) {
/**
* Get user-specific addon settings
*/
function email_validator_user_settings(?int $userId = null): array
{
$user = $userId ? \App\Models\User::find($userId) : auth()->user();

if (!$user) {
return [];
}

$settings = \Addons\EmailValidator\Entities\UserSetting::where('user_id', $user->id)
->pluck('value', 'key')
->toArray();

return array_merge([
'auto_validate' => true,
'notify_invalid' => false,
'validation_level' => 'standard',
], $settings);
}
}

View Helpers

// Helpers/functions.php
<?php

if (!function_exists('email_validator_asset')) {
/**
* Get addon asset URL
*/
function email_validator_asset(string $path): string
{
return asset('vendor/emailvalidator/' . ltrim($path, '/'));
}
}

if (!function_exists('email_validator_route')) {
/**
* Generate addon route URL
*/
function email_validator_route(string $name, array $params = []): string
{
return route('emailvalidator.' . $name, $params);
}
}

if (!function_exists('email_validator_view')) {
/**
* Render addon view
*/
function email_validator_view(string $view, array $data = []): \Illuminate\View\View
{
return view('emailvalidator::' . $view, $data);
}
}

Formatting Helpers

// Helpers/functions.php
<?php

if (!function_exists('format_validation_score')) {
/**
* Format validation score with color indicator
*/
function format_validation_score(int $score): string
{
$color = match(true) {
$score >= 80 => 'success',
$score >= 50 => 'warning',
default => 'danger',
};

return "<span class=\"text-{$color}\">{$score}%</span>";
}
}

if (!function_exists('format_validation_status')) {
/**
* Format validation status as badge
*/
function format_validation_status(string $status): string
{
$classes = [
'valid' => 'kt-badge--success',
'invalid' => 'kt-badge--danger',
'unknown' => 'kt-badge--warning',
'pending' => 'kt-badge--info',
];

$labels = [
'valid' => 'Valid',
'invalid' => 'Invalid',
'unknown' => 'Unknown',
'pending' => 'Pending',
];

$class = $classes[$status] ?? 'kt-badge--secondary';
$label = $labels[$status] ?? ucfirst($status);

return "<span class=\"kt-badge {$class} kt-badge--inline\">{$label}</span>";
}
}

if (!function_exists('format_validation_count')) {
/**
* Format large numbers for display
*/
function format_validation_count(int $count): string
{
if ($count >= 1000000) {
return round($count / 1000000, 1) . 'M';
}

if ($count >= 1000) {
return round($count / 1000, 1) . 'K';
}

return (string) $count;
}
}

Addon Lifecycle Functions

The functions.php file in the addon root contains lifecycle functions:

// functions.php (in addon root)
<?php

/**
* Called during addon installation
*/
function install_addon($addon_name)
{
// Run installation SQL files
$installDir = addonInstallDir($addon_name);

if (is_dir($installDir)) {
$sqlFiles = glob($installDir . '/*.sql');
sort($sqlFiles); // Ensure version order

foreach ($sqlFiles as $file) {
$sql = file_get_contents($file);
\DB::unprepared($sql);
}
}

// Set default settings
\Addons\EmailValidator\Entities\Setting::create([
'key' => 'installed_at',
'value' => now()->toIso8601String(),
]);

// Clear caches
\Artisan::call('cache:clear');
\Artisan::call('config:clear');

return true;
}

/**
* Called during addon update
*/
function update_addon($addon_name, $currentVersion, $newVersion)
{
// Run update SQL files newer than current version
$installDir = addonInstallDir($addon_name);

if (is_dir($installDir)) {
$sqlFiles = glob($installDir . '/v*.sql');
sort($sqlFiles);

foreach ($sqlFiles as $file) {
// Extract version from filename (e.g., v1.1.sql -> 1.1)
preg_match('/v([\d.]+)\.sql$/', $file, $matches);
$fileVersion = $matches[1] ?? '0';

if (version_compare($fileVersion, $currentVersion, '>')) {
$sql = file_get_contents($file);
\DB::unprepared($sql);
}
}
}

// Run migrations
\Artisan::call('module:migrate', ['module' => $addon_name]);

// Clear caches
\Artisan::call('cache:clear');

return true;
}

/**
* Called during addon uninstall
*/
function uninstall_addon($addon_name)
{
// Run uninstall SQL
$uninstallFile = addonUnInstallDir($addon_name) . '/uninstall.sql';

if (file_exists($uninstallFile)) {
$sql = file_get_contents($uninstallFile);
\DB::unprepared($sql);
}

// Rollback migrations
\Artisan::call('module:migrate-reset', ['module' => $addon_name]);

return true;
}

/**
* Check addon dependencies
*/
function check_addon_dependencies($addon_name): array
{
$missing = [];

// Check PHP extensions
$requiredExtensions = ['curl', 'json', 'mbstring'];
foreach ($requiredExtensions as $ext) {
if (!extension_loaded($ext)) {
$missing[] = "PHP extension: {$ext}";
}
}

// Check composer packages
if (!class_exists('\GuzzleHttp\Client')) {
$missing[] = "Composer package: guzzlehttp/guzzle";
}

return $missing;
}

Using Built-in Helpers

Mumara Campaigns provides several helper functions you can use:

// Addon path helpers
$path = addonDir('EmailValidator'); // /var/www/.../Addons/EmailValidator
$settingsPath = addonSettingDir('EmailValidator'); // .../Settings
$installPath = addonInstallDir('EmailValidator'); // .../Settings/install

// Module helpers
$isEnabled = moduleCheck('EmailValidator'); // Check if addon is enabled

// Hook helpers
add_hook('HookName', 5, $callback);
listen_hook('HookName', $args);
hook_get_output('HookName', $args);
hook_get('HookName', $args);
hook_exist('HookName');
run_hook_in_background('HookName', $args);

Helper Class Alternative

For more complex functionality, use a helper class:

// Helpers/ValidationHelper.php
<?php

namespace Addons\EmailValidator\Helpers;

class ValidationHelper
{
public static function validate(string $email): array
{
// Validation logic
}

public static function batchValidate(array $emails): array
{
return array_map([self::class, 'validate'], $emails);
}

public static function getStats(int $userId): array
{
// Get validation statistics
}
}

Usage:

use Addons\EmailValidator\Helpers\ValidationHelper;

$result = ValidationHelper::validate($email);
$stats = ValidationHelper::getStats(auth()->id());

Best Practices

  1. Always check function_exists - Prevents conflicts with other addons
  2. Use descriptive prefixes - Prefix functions with addon name
  3. Keep functions focused - One function, one purpose
  4. Document with PHPDoc - Describe parameters and return values
  5. Handle errors gracefully - Return sensible defaults
  6. Use type hints - PHP 7.4+ type declarations
  7. Consider helper classes - For complex related functionality