PHP code example of eugenefvdm / multi-tenancy-pwa

1. Go to this page and download the library: Download eugenefvdm/multi-tenancy-pwa library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

eugenefvdm / multi-tenancy-pwa example snippets


$table->foreignId('tenant_id')->constrained('tenants');



namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Tenant extends Model
{
    /** @use HasFactory<\Database\Factories\TenantFactory> */
    use HasFactory;
    
    protected $fillable = [
        'name',
    ];

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class);
    }
}

use Eugenefvdm\MultiTenancyPWA\Traits\HasTenantRelationship;



namespace App\Http\Middleware;

use App\Models\Category;
use App\Models\Todo;
use Closure;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class ApplyTenantScopes
{
    /**
     * Handle an incoming request.
     *
     * @param  Closure(Request): (Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        Category::addGlobalScope(
            fn (Builder $query) => $query->whereBelongsTo(Filament::getTenant()),
        );
        
        Todo::addGlobalScope(
            fn (Builder $query) => $query->whereBelongsTo(Filament::getTenant()),
        );

        return $next($request);
    }
}

use App\Http\Middleware\ApplyTenantScopes;
use App\Models\Tenant;
use Eugenefvdm\MultiTenancyPWA\Filament\Pages\Tenancy\RegisterNewTenant;

// Filament AdminPanelProvider extra sections
->colors([ // Already exists
    'primary' => Color::Cyan
]);
->profile(\App\Filament\Pages\Auth\EditProfile::class);
->tenant(Tenant::class)
->registration()
->tenantRegistration(RegisterNewTenant::class)
->tenantProfile(EditMyTenantProfile::class)
->renderHook( 
    'panels::auth.login.form.after',
    fn () => view('multi-tenancy-pwa::auth.socialite.google')
->tenantMiddleware([
    ApplyTenantScopes::class,
], isPersistent: true)
->databaseNotifications();



namespace App\Notifications;

use Filament\Facades\Filament;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use NotificationChannels\WebPush\WebPushChannel;
use NotificationChannels\WebPush\WebPushMessage;

class WebpushNotification extends Notification
{
    use Queueable;

    /**
     * Create a new notification instance.
     */
    public function __construct(private string $title = 'Default Title', private string $body = 'Default Body Text')
    {
        //
    }

    /**
     * Get the notification's delivery channels.
     *
     * @return array<int, string>
     */
    public function via(object $notifiable): array
    {
        return [WebPushChannel::class];
    }

    public function toWebPush($notifiable, $notification): WebPushMessage
    {
        $tenantId = Filament::getTenant()->id ?? 1;

        return (new WebPushMessage)
            ->title($this->title)            
            ->body($this->body)
            ->action('Call to action', 'do_something') // This appears as a button on the notification
            ->options(['TTL' => 10000])
            ->vibrate([300, 100, 400])
            ->data(['url' => config('app.url') . '/admin/' . $tenantId . '/notifications']);
        // ->icon('/approved-icon.png')
        // ->data(['id' => $notification->id])
        // ->badge()
        // ->dir()
        // ->image()
        // ->lang()
        // ->renotify()
        // ->

use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasDefaultTenant;
use Filament\Models\Contracts\HasTenants;
use Filament\Panel;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;

class User extends Authenticatable implements FilamentUser, HasDefaultTenant, HasTenants
{
    use HasPushSubscriptions;

    // ...
    protected $fillable = [
        'google_id'        
    ];

    // ...
    public function canAccessPanel(Panel $panel): bool
    {
        return true;
    }

    public function tenants(): BelongsToMany
    {
        return $this->belongsToMany(Tenant::class);
    }

    public function getTenants(Panel $panel): Collection
    {
        return $this->tenants;
    }

    public function canAccessTenant(Model $tenant): bool
    {
        return $this->tenants()->whereKey($tenant)->exists();
    }

    public function getDefaultTenant(): ?Model
    {
        return $this->latestTenant()->first();
    }

    public function latestTenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'latest_tenant_id');
    }
}

use Filament\Resources\Resource;

protected static bool $isScopedToTenant = false;
bash
php artisan vendor:publish --tag=eloquent-sortable-config
bash
php artisan filament:install --panels
bash
php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="config"
bash
php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="migrations"
bash
php artisan vendor:publish --tag="multi-tenancy-pwa-migrations"

OPENSSL_CONF=/opt/homebrew/opt/openssl@3/etc/openssl.cnf \
php -r 'var_dump(openssl_pkey_new(["private_key_type"=>OPENSSL_KEYTYPE_RSA]));'