add: full multi-tenancy control
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Webkul\Marketing\Helpers\Campaign;
|
||||
|
||||
class CampaignCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'campaign:process';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Process campaigns and send emails to the contact persons.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected Campaign $campaignHelper)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('🚀 Starting campaign processing...');
|
||||
|
||||
try {
|
||||
$this->campaignHelper->process();
|
||||
|
||||
$this->info('✅ Campaign processing completed successfully!');
|
||||
} catch (\Exception $e) {
|
||||
$this->error('❌ An error occurred during campaign processing: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
5
packages/Webkul/Marketing/src/Contracts/Campaign.php
Normal file
5
packages/Webkul/Marketing/src/Contracts/Campaign.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Contracts;
|
||||
|
||||
interface Campaign {}
|
||||
5
packages/Webkul/Marketing/src/Contracts/Event.php
Normal file
5
packages/Webkul/Marketing/src/Contracts/Event.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Contracts;
|
||||
|
||||
interface Event {}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('marketing_events', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->string('description');
|
||||
$table->date('date');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('marketing_events');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('marketing_campaigns', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->string('subject');
|
||||
$table->boolean('status')->default(0);
|
||||
$table->string('type');
|
||||
$table->string('mail_to');
|
||||
$table->string('spooling')->nullable();
|
||||
$table->unsignedInteger('marketing_template_id')->nullable();
|
||||
$table->unsignedInteger('marketing_event_id')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('marketing_template_id')->references('id')->on('email_templates')->onDelete('set null');
|
||||
$table->foreign('marketing_event_id')->references('id')->on('marketing_events')->onDelete('set null');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('marketing_campaigns');
|
||||
}
|
||||
};
|
||||
56
packages/Webkul/Marketing/src/Helpers/Campaign.php
Normal file
56
packages/Webkul/Marketing/src/Helpers/Campaign.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Helpers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
use Webkul\Marketing\Mail\CampaignMail;
|
||||
use Webkul\Marketing\Repositories\CampaignRepository;
|
||||
use Webkul\Marketing\Repositories\EventRepository;
|
||||
|
||||
class Campaign
|
||||
{
|
||||
/**
|
||||
* Create a new helper instance.
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected EventRepository $eventRepository,
|
||||
protected CampaignRepository $campaignRepository,
|
||||
protected PersonRepository $personRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Process the email.
|
||||
*/
|
||||
public function process(): void
|
||||
{
|
||||
$campaigns = $this->campaignRepository->getModel()
|
||||
->leftJoin('marketing_events', 'marketing_campaigns.marketing_event_id', 'marketing_events.id')
|
||||
->leftJoin('email_templates', 'marketing_campaigns.marketing_template_id', 'email_templates.id')
|
||||
->select('marketing_campaigns.*')
|
||||
->where('marketing_campaigns.status', 1)
|
||||
->where(function ($query) {
|
||||
$query->where('marketing_events.date', Carbon::now()->format('Y-m-d'))
|
||||
->orWhereNull('marketing_events.date');
|
||||
})
|
||||
->get();
|
||||
|
||||
collect($campaigns)->each(function ($campaign) {
|
||||
collect($this->getPersonsEmails())->each(fn ($email) => Mail::queue(new CampaignMail($email, $campaign)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email address.
|
||||
*/
|
||||
private function getPersonsEmails(): array
|
||||
{
|
||||
return $this->personRepository->pluck('emails')
|
||||
->flatMap(fn ($emails) => collect($emails)->pluck('value'))
|
||||
->all();
|
||||
}
|
||||
}
|
||||
45
packages/Webkul/Marketing/src/Mail/CampaignMail.php
Normal file
45
packages/Webkul/Marketing/src/Mail/CampaignMail.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Mail;
|
||||
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Webkul\Marketing\Contracts\Campaign;
|
||||
|
||||
class CampaignMail extends Mailable
|
||||
{
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
public string $email,
|
||||
public Campaign $campaign
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
to: [
|
||||
new Address($this->email),
|
||||
],
|
||||
subject: $this->campaign->subject,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
htmlString: $this->campaign->email_template->content,
|
||||
);
|
||||
}
|
||||
}
|
||||
47
packages/Webkul/Marketing/src/Models/Campaign.php
Normal file
47
packages/Webkul/Marketing/src/Models/Campaign.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\EmailTemplate\Models\EmailTemplateProxy;
|
||||
use Webkul\Marketing\Contracts\Campaign as CampaignContract;
|
||||
|
||||
class Campaign extends Model implements CampaignContract
|
||||
{
|
||||
/**
|
||||
* Define the table for the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'marketing_campaigns';
|
||||
|
||||
/**
|
||||
* The attributes that are fillable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'subject',
|
||||
'status',
|
||||
'marketing_template_id',
|
||||
'marketing_event_id',
|
||||
'spooling',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the email template
|
||||
*/
|
||||
public function email_template()
|
||||
{
|
||||
return $this->belongsTo(EmailTemplateProxy::modelClass(), 'marketing_template_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the event
|
||||
*/
|
||||
public function event()
|
||||
{
|
||||
return $this->belongsTo(EventProxy::modelClass(), 'marketing_event_id');
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Marketing/src/Models/CampaignProxy.php
Normal file
7
packages/Webkul/Marketing/src/Models/CampaignProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class CampaignProxy extends ModelProxy {}
|
||||
32
packages/Webkul/Marketing/src/Models/Event.php
Normal file
32
packages/Webkul/Marketing/src/Models/Event.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Marketing\Contracts\Event as EventContract;
|
||||
|
||||
class Event extends Model implements EventContract
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'marketing_events';
|
||||
|
||||
/**
|
||||
* The attributes that are fillable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
'date',
|
||||
];
|
||||
|
||||
public function campaigns()
|
||||
{
|
||||
return $this->hasMany(CampaignProxy::modelClass(), 'marketing_event_id');
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Marketing/src/Models/EventProxy.php
Normal file
7
packages/Webkul/Marketing/src/Models/EventProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class EventProxy extends ModelProxy {}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Providers;
|
||||
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Webkul\Marketing\Console\Commands\CampaignCommand;
|
||||
|
||||
class MarketingServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(__DIR__.'/../Database/Migrations');
|
||||
|
||||
$this->callAfterResolving(Schedule::class, function (Schedule $schedule) {
|
||||
$schedule->command('campaign:process')->daily();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->registerCommands();
|
||||
|
||||
$this->app->register(ModuleServiceProvider::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the commands.
|
||||
*/
|
||||
private function registerCommands(): void
|
||||
{
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
CampaignCommand::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Providers;
|
||||
|
||||
use Webkul\Core\Providers\BaseModuleServiceProvider;
|
||||
|
||||
class ModuleServiceProvider extends BaseModuleServiceProvider
|
||||
{
|
||||
/**
|
||||
* Define the module's array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $models = [
|
||||
\Webkul\Marketing\Models\Event::class,
|
||||
\Webkul\Marketing\Models\Campaign::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Marketing\Contracts\Campaign;
|
||||
|
||||
class CampaignRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name.
|
||||
*/
|
||||
public function model(): string
|
||||
{
|
||||
return Campaign::class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Marketing\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Marketing\Contracts\Event;
|
||||
|
||||
class EventRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name.
|
||||
*/
|
||||
public function model(): string
|
||||
{
|
||||
return Event::class;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user