Search code examples
phplaravelstripe-paymentsmulti-tenant

Getting unexpected data from central domain inside the tenants domain in Stancl/ Laravel Tenancy


I am using the Stancl/TenancyforLaravel tenancy system.

I have created a model and migration called PaymentSettings for both tenants and central domain users.

For central Users = app\Models\System\Admin\PaymentSettings.php

For tenants users = app\Models\Tenant\Admin\PaymentSettings.php

I have added the crud operation which is running absolutely fine. I am facing the challenge while setting up the stripe API on boot, in the service provider. When I am fetching the settings data from the database

File: app\Providers\TenancyServiceProvider.php

namespace App\Providers;
use App\Models\System\Admin\SmtpSettings as AdminSmtpSettings;
use App\Models\Tenant\Admin\AdvanceSettings;
use App\Models\Tenant\Admin\GeneralSettings;
use App\Models\Tenant\Admin\PaymentSettings;
use App\Models\Tenant\Admin\SmtpSettings;
 ...

public function boot()
    {
        $this->bootEvents();
        $this->mapRoutes();        
        $this->makeTenancyMiddlewareHighestPriority();
        $this->viewResource();
    }
 ....
   protected function viewResource(){
        View::composer('*', function ($view) {
            $this->setConfigData();
            if(Schema::hasTable('general_settings')){
                $generalSettings = GeneralSettings::findOrFail(1);
                $advanceSettings = AdvanceSettings::findOrFail(1);
                $view->with([
                        'tenant_general' => $generalSettings,
                        'tenant_advance' => $advanceSettings,
                ]);
            }
        });
    }
 protected function setConfigData()
    {

        // When tenancy exists fetch the data from the tenants data;
        $smtpTableExists = Schema::hasTable('smtp_settings');
        $smtpSettings = null;
        if(tenancy()->tenant){
            if($smtpTableExists){  $smtpSettings = SmtpSettings::findOrFail(1); }
           
            // Stripe Payment settings
            $paymentTableExists = Schema::hasTable('payment_settings');
            if($paymentTableExists){
                $paymentSettings = PaymentSettings::findOrFail(1);
                // return dd($paymentSettings->key);
                if($paymentSettings && $paymentSettings->method === 'Stripe'){
                    Config::set('services.stripe.key', $paymentSettings->key);
                    Config::set('services.stripe.secret', $paymentSettings->secret);
                    Config::set('services.stripe.webhook_secret', $paymentSettings->webhook_secret);
                    Stripe::setApiKey($paymentSettings->key);
                }
            }
        } // ends tenants config
        else { // fetch data from the central domain
            if($smtpTableExists){  $smtpSettings = AdminSmtpSettings::findOrFail(1); }
        }

        // set configs
        if($smtpSettings){
            Config::set('mail.mailers.smtp.host', $smtpSettings->host);
            Config::set('mail.mailers.smtp.port', $smtpSettings->port);
            Config::set('mail.mailers.smtp.encryption', $smtpSettings->encryption);
            Config::set('mail.mailers.smtp.username', $smtpSettings->username);
            Config::set('mail.mailers.smtp.password', $smtpSettings->password);
            Config::set('mail.from.address', $smtpSettings->from_address);
            Config::set('mail.from.name', $smtpSettings->from_name);
        }

    }
....

As I have already set up the API key, I should get this inside the controllers, but is not so, I am getting the value null inside the other controllers when I am calling Stripe::getApiKey()

I thought maybe the boot file is not running properly, to I tried to manually write this inside the controllers' constructor inside the tenant's domain as

use App\Models\Tenant\Admin\PaymentSettings;

public function __construct()
    {
        $this->middleware('auth');
        $paymentSettings = PaymentSettings::findOrFail(1);
        Stripe::setApiKey($paymentSettings->key);
       return dd(Stripe::getApiKey()); // showing the incorrect value from the central domain
   } 

But the problem did not end here, The value that I am getting is the value from the Central domain not the tenant domain inside the controllers. BUT when I am writing a similar thing inside any other method in the tenant's controller, it's giving the correct value.

use App\Models\Tenant\Admin\PaymentSettings;

public function index()
    {
         // return dd(Stripe::getApiKey()); // showing the incorrect correct value from central domain

        $paymentSettings = PaymentSettings::findOrFail(1);
        Stripe::setApiKey($paymentSettings->key);

          return dd(Stripe::getApiKey()); // showing the correct value

        return view(someviewfilename);
   } 
Expected behavior

I want to fetch the tenant's database data when I am on the tenant's domain, not the central domain DB data.

Your setup
  • Laravel version: ^7.0
  • stancl/tenancy version: ^3.2
  • Storage driver: DB
  • laravel/cashier: ^12.5

Solution

  • I got the answer from the creator. https://github.com/stancl/tenancy/issues/558

    Think about how the Laravel request lifecycle works.

    Here you're defining some middleware specifics: enter image
description here

    And on the next line, you expect the middleware to be already executed? Of course it's not, Laravel first executes service providers and controller constructors, and only then does it know what middleware to use.