File: /home/xedaptot/ai.naniguide.com/app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Schema;
use AppUrl;
use App\Model\Setting;
use App\Library\HookManager;
use App\Model\Plugin;
use App\Library\Facades\Hook;
use App\Services\Subscription\SubscriptionManagementService;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
// Check if the app is in distributed mode and its conditions are met
distributed_mode_check();
// Replace Laravel's default DatabaseChannel with our channel so
// `$user->notify(new AppNotification(...))` writes rows matching the
// redesigned schema (audience/category/severity/group_key/...).
// See docs/notifications/NOTIFICATIONS-COMPREHENSIVE-DESIGN.md.
$this->app->extend(\Illuminate\Notifications\Channels\DatabaseChannel::class, function () {
return $this->app->make(\App\Notifications\Channels\AppDatabaseChannel::class);
});
// Register refactor-namespaced anonymous Blade components so
// <x-mc-*> tags resolve to resources/views/refactor/components/*.blade.php
// (Laravel default only searches resources/views/components/).
Blade::anonymousComponentPath(resource_path('views/refactor/components'));
// Teak default settings (PHP, Laravel, etc.)
$this->changeDefaultSettings();
// Add custom validation rules
// @deprecated
$this->addCustomValidationRules();
// Load custom DB connections from config/sharding.php
$this->loadShardingDbConnections();
// Just finish if the application is not set up
if (!isInitiated()) {
return;
}
// Load application's plugins
// Disabled plugin may also register hooks
Plugin::autoloadWithoutDbQuery();
// Register plugins' registered translation folders
foreach (Hook::collect('add_translation_file') as $source) {
if (array_key_exists('translation_prefix', $source)) {
$prefix = $source['translation_prefix'];
$folder = $source['translation_folder'];
$this->loadTranslationsFrom($folder, $prefix);
}
}
}
/**
* Register any application services.
*
* @return void
*/
public function register(): void
{
$this->app->singleton(HookManager::class, function ($app) {
return new HookManager();
});
$this->app->singleton(SubscriptionManagementService::class, function ($app) {
return new SubscriptionManagementService();
});
$this->app->bind(
\App\Library\Assets\AssetRepositoryInterface::class,
\App\Library\Assets\EloquentAssetRepository::class
);
// Subscriber import — register spreadsheet readers by file extension.
// Mirror of App\Verification\DriverRegistry / App\SendingServers\DriverRegistry.
\App\Library\Import\DriverRegistry::register('csv', \App\Library\Import\Readers\CsvReader::class);
\App\Library\Import\DriverRegistry::register('txt', \App\Library\Import\Readers\CsvReader::class);
\App\Library\Import\DriverRegistry::register('xlsx', \App\Library\Import\Readers\XlsxReader::class);
Hook::add('add_translation_file', function () {
return [
"id" => "acelle_messages",
"plugin_name" => "Application/Core",
"file_title" => "Messages",
"translation_folder" => base_path('resources/lang'),
"file_name" => "messages.php",
"master_translation_file" => resource_path('lang/default/messages.php'),
];
});
Hook::add('add_translation_file', function () {
return [
"id" => "acelle_auth",
"plugin_name" => "Application/Core",
"file_title" => "Auth",
"translation_folder" => base_path('resources/lang'),
"file_name" => "auth.php",
"master_translation_file" => resource_path('lang/default/auth.php'),
];
});
Hook::add('add_translation_file', function () {
return [
"id" => "acelle_pagination",
"plugin_name" => "Application/Core",
"file_title" => "Pagination",
"translation_folder" => base_path('resources/lang'),
"file_name" => "pagination.php",
"master_translation_file" => resource_path('lang/default/pagination.php'),
];
});
Hook::add('add_translation_file', function () {
return [
"id" => "acelle_passwords",
"plugin_name" => "Application/Core",
"file_title" => "Passwords",
"translation_folder" => base_path('resources/lang'),
"file_name" => "passwords.php",
"master_translation_file" => resource_path('lang/default/passwords.php'),
];
});
Hook::add('add_translation_file', function () {
return [
"id" => "acelle_builder",
"plugin_name" => "Application/Core",
"file_title" => "Builder",
"translation_folder" => base_path('resources/lang'),
"file_name" => "builder.php",
"master_translation_file" => resource_path('lang/default/builder.php'),
];
});
Hook::add('add_translation_file', function () {
return [
"id" => "acelle_validation",
"plugin_name" => "Application/Core",
"file_title" => "Validation",
"translation_folder" => base_path('resources/lang'),
"file_name" => "validation.php",
"master_translation_file" => resource_path('lang/default/validation.php'),
];
});
Hook::add('add_translation_file', function () {
return [
"id" => "acelle_warmup",
"plugin_name" => "Application/Core",
"file_title" => "Warmup",
"translation_folder" => base_path('resources/lang'),
"file_name" => "warmup.php",
"master_translation_file" => resource_path('lang/default/warmup.php'),
];
});
foreach (['common', 'dashboard', 'permission', 'store', 'subscription'] as $coreFile) {
Hook::add('add_translation_file', function () use ($coreFile) {
return [
"id" => "acelle_{$coreFile}",
"plugin_name" => "Application/Core",
"file_title" => ucfirst($coreFile),
"translation_folder" => base_path('resources/lang'),
"file_name" => "{$coreFile}.php",
"master_translation_file" => resource_path("lang/default/{$coreFile}.php"),
];
});
}
// Translation files under the resources/lang/{code}/refactor/ subfolder.
// Registered the same as any other translation file — no special format handling.
$refactorTranslationFiles = [
// admin_plan_verifications intentionally dropped (PlanVerification feature deleted
// as part of the subscription refactor — see SUBSCRIPTION-COMPREHENSIVE-DESIGN.md).
'account', 'admin_account', 'admin_admin_groups', 'admin_admins', 'admin_api_docs', 'admin_bounce_handlers', 'admin_common', 'admin_email_templates', 'admin_email_verification_plans', 'admin_fbl_handlers', 'admin_form_templates', 'admin_page_templates', 'admin_geoip', 'admin_http_config', 'admin_languages', 'admin_notifications', 'admin_system_pages', 'admin_plugins', 'admin_remote_plan_mappings', 'admin_search', 'admin_translation', 'admin_verification_servers', 'admin_warmup_strategies', 'admin_webhooks', 'admin_currencies', 'admin_customers', 'admin_sending_credit_plans', 'admin_dashboard', 'admin_invoices', 'admin_logs', 'admin_payment_gateways', 'admin_plans', 'admin_sending_servers', 'admin_settings', 'admin_subscriptions', 'api', 'auth', 'automations', 'campaigns', 'common',
'admin_blacklist', 'admin_monitor', 'admin_verification_tool', 'admin_sub_admins',
'notifications',
'api_docs',
'checkout',
'dashboard', 'fields', 'forms', 'lists', 'segments', 'sending',
'subscribers', 'templates', 'templates_pages', 'verification', 'websites',
'builder',
'forms_builder',
'activity_log',
'builder_js',
'pagination',
'ads',
'ads_platforms',
'ads_activity',
'ads_audiences',
'ads_ab_tests',
'ads_automations',
'ads_pixels',
'ads_catalogs',
'ads_lead_forms',
'ads_templates',
'ads_creative',
'ads_admin_settings',
'ads_admin_observability',
'ads_emergency',
'admin_ads_emergency',
'admin_customer_dashboard',
'admin_payment_gateway_remote',
'admin_roles',
'dashboard_v2',
'funnels',
'payment_gateways',
'search',
// AI lang files (`refactor/ai_*`, `refactor/admin_ai_*`,
// `refactor/ai_settings`) moved into the acelle/ai plugin
// (W5 of the AI-extraction plan). The plugin's
// ServiceProvider registers them via loadTranslationsFrom.
'credits',
'assets',
];
foreach ($refactorTranslationFiles as $file) {
Hook::add('add_translation_file', function () use ($file) {
return [
"id" => "acelle_refactor_{$file}",
"plugin_name" => "Application/Core",
"file_title" => "Refactor — " . ucfirst(str_replace('_', ' ', $file)),
"translation_folder" => base_path('resources/lang'),
"file_name" => "refactor/{$file}.php",
"master_translation_file" => resource_path("lang/default/refactor/{$file}.php"),
];
});
}
// default captcha method
Hook::add('captcha_method', function () {
return [
"id" => 'recaptcha',
"title" => trans('messages.recaptcha.v2'),
];
});
// default captcha method
Hook::add('captcha_method', function () {
return [
"id" => 'recaptcha_v3',
"title" => trans('messages.recaptcha.v3'),
];
});
// customer added
Hook::on('customer_added', function ($customer) {
// run webhook
\App\Library\Webhook\NewCustomer::run($customer->uid);
});
// subscription terminated
Hook::on('subscription_terminated', function ($subscription) {
// run webhook
\App\Library\Webhook\TerminateSubscription::run($subscription->customer->uid, $subscription->plan->uid);
});
// change plan
Hook::on('plan_changed', function ($customer, $oldPlan, $newPlan) {
// run webhook
\App\Library\Webhook\ChangePlan::run($customer->uid, $oldPlan->uid, $newPlan->uid);
});
// new subscription
Hook::on('new_subscription', function ($subscription) {
// run webhook
\App\Library\Webhook\NewSubscription::run($subscription->customer->uid, $subscription->plan->uid);
});
// cancel subscription
Hook::on('subscription_cancelled', function ($subscription) {
// run webhook
\App\Library\Webhook\CancelSubscription::run($subscription->customer->uid, $subscription->plan->uid);
});
}
// @deprecated
private function addCustomValidationRules()
{
// extend substring validator
Validator::extend('substring', function ($attribute, $value, $parameters, $validator) {
$tag = $parameters[0];
if (strpos($value, $tag) === false) {
return false;
}
return true;
});
Validator::replacer('substring', function ($message, $attribute, $rule, $parameters) {
return str_replace(':tag', $parameters[0], $message);
});
// License validator
Validator::extend('license', function ($attribute, $value, $parameters, $validator) {
return $value == '' || true;
});
// License error validator
Validator::extend('license_error', function ($attribute, $value, $parameters, $validator) {
return false;
});
Validator::replacer('license_error', function ($message, $attribute, $rule, $parameters) {
return str_replace(':error', $parameters[0], $message);
});
}
private function changeDefaultSettings()
{
ini_set('memory_limit', '-1');
ini_set('pcre.backtrack_limit', 1000000000);
// Laravel 5.5 to 5.6 compatibility
Blade::withoutDoubleEncoding();
// Check if HTTPS (including proxy case)
$isSecure = false;
if (isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') == 0) {
$isSecure = true;
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') == 0 || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_SSL'], 'on') == 0) {
$isSecure = true;
}
if ($isSecure) {
// To deal with Ajax pagination link issue (always use HTTP)
$this->app['request']->server->set('HTTPS', 'on');
AppUrl::forceScheme('https');
}
// HTTP or HTTPS
// parse_url will return either 'http' or 'https'
//$scheme = parse_url(config('app.url'), PHP_URL_SCHEME);
//if (!empty($scheme)) {
// AppUrl::forceScheme($scheme);
//}
// Fix Laravel 5.4 error
// [Illuminate\Database\QueryException]
// SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
Schema::defaultStringLength(191);
}
private function loadShardingDbConnections()
{
if (!config('sharding.enabled')) {
return;
}
$configFile = base_path(config('sharding.connections_config'));
if (!file_exists($configFile)) {
throw new \Exception("DB SHARDING mode is on, but the config file '{$configFile}' does not exist");
}
$connections = require $configFile;
if (!is_array($connections)) {
throw new \Exception("Invalid config file for DB SHARDING: '{$configFile}'. Expect an array of connections");
}
foreach ($connections as $name => $settings) {
\Config::set("database.connections.{$name}", $settings);
}
}
}