SilvaDreamdeal's avatar

Multitenancy and Storage - Getting Image from tenant

Since I started with multi tenant, I'm having problems getting the url path for images

My tenants can upload an image. Lets say its the logo With multi tenant it saved the folders like in this image:

https://prnt.sc/wXMQc1zjHErI

I save the file using the following line code:

$path = request()->file("file")->store('public');

Its automatic the generation of the tenant folder, the documentation explains that: https://tenancyforlaravel.com/docs/v2/filesystem-tenancy/

I save the path at my database. It saves a line as the following example:

public/JwsCeCCxgKiM8ZVYAMNt9gPJeZKDsb8NUKmPzak8.jpg

Now I want to get the URL of that file, in order to load the logo in my front application:

private function getLogoPath(){
    if($this->logo == null)
        return null;

    return asset(Storage::url($this->logo));
}

I receive the message

Tenant could not be identified on domain localhost

It was working without multi tenant. Now I'm having troubles because of multi tenancy

Can someone help me in order to know what to do or how can I do it?

0 likes
9 replies
SilvaDreamdeal's avatar

someone? Please. It is an important feature that is missing in this project, and for now, the only one that we can't find a solution

Jsanwo64's avatar

can you dump the function that handles getting url path?

Jsanwo64's avatar

Try Symlink first if you haven't.

To access the URL path for the stored file, you can make use of the Storage facade provided by Laravel. The url() method of the Storage facade allows you to generate a URL for a given file path.

Here's an example of how you can modify your code to retrieve the URL path for the stored file:

$file = request()->file("file");
$path = $file->store('public');

$url = Storage::url($path);

In the code above, $file represents the uploaded file obtained from the request. The store() method saves the file in the public disk and returns the file path. Then, the url() method is used to generate the URL path for the stored file. The resulting URL, stored in the variable $url, can be used to access the file in your application.

SilvaDreamdeal's avatar

@jsanwo64 thats the "normal" way of doing it. Without multi tenant I had it that way and everything was ok

From the moment I applied the multi tenant it started to fail because multi tenancy ads new folders and paths

This is what I do when I save the file. It stores the file in :

ROOT / storage / TENANT / app / public

and the variable $path = 'public/file.jpg' for example

This is inside the Tenant. I'm working with multi tenant and this actions are performed in a tenant

public function handle()
    {
        // COLOCAR AQUI O NOME DO TENANT
        $path = request()->file("file")->store('public');

        CompanyConfigurations::where('id', $this->id)->update([
            'logo'      =>  $path
        ]);
    }
SilvaDreamdeal's avatar

When I create the image, I use:

public function handle()
    {
        $path = request()->file("file")->store('public/');


        CompanyConfigurations::where('id', $this->id)->update([
            'logo'      =>  $path
        ]);
    }

To get the image, In the model I have:

private function getLogoPath(){
        if($this->logo == null)
            return null;
            
        
        return Storage::url($this->logo);
    }

my tenancy.php in config

(...)
'filesystem' => [
        /**
         * Each disk listed in the 'disks' array will be suffixed by the suffix_base, followed by the tenant_id.
         */
        'suffix_base' => 'tenant',
        'disks' => [
            'local',
            'public',
            // 's3',
        ],

        /**
         * Use this for local disks.
         *
         * See https://tenancyforlaravel.com/docs/v3/tenancy-bootstrappers/#filesystem-tenancy-boostrapper
         */
        'root_override' => [
            // Disks whose roots should be overriden after storage_path() is suffixed.
            'local' => '%storage_path%/app/',
            'public' => '%storage_path%/app/public/',
        ],
(...)

and the filesystems.php is the normal file, with no changes. With public, local a S3 disks created by default

With this, I'm able to save the image inside the ROOT / storage / tenantTENANT / app / public

and it saves in my database the following:

public//image.jpg

When I try to get the image, the model arrives with

path = /storage//image.jpg

Even if I try to put localhost:8080/ before the path, I cant reach the image.

I tried to use

private function getLogoPath(){
        if($this->logo == null)
            return null;
            
        
        return asset(Storage::url($this->logo));
    }

But it returns:

The url : http://localhost:8000/tenancy/assets/storage//image.jpg

"message": "Tenant could not be identified on domain localhost",
SilvaDreamdeal's avatar

ok, with this I can have the correct path inside my server. How can I create an URL now?

private function getLogoPath(){
        if($this->logo == null)
            return null;
        
        return Storage::disk('tenancy')->url($this->logo);
    }

I need to send this to vuejs api to load the image as an url to load the image

Jsanwo64's avatar

@SilvaDreamdeal try

private function getLogoPath(){
    if($this->logo == null)
        return null;

    $path = Storage::disk('tenancy')->path($this->logo);
    $url = url($path);

    return $url;
}

SilvaDreamdeal's avatar
SilvaDreamdeal
OP
Best Answer
Level 1

As an answer, I'm returning the URL

private function getLogoPath(){
        if($this->logo == null)
            return null;


        return \URL::to(tenancy()->tenant->id . "/storage/logo/" . $this->id);
    }

I use tenancy to identify the tenant where I want to go and then, and this is importantn, I created a controller:

class LogoController extends Controller
{
    public function __invoke(Request $request){

        $file = Storage::path($file->logo);

        return response()->file($file);
    }
}

And this controller runs inside a tenant, because in the web.php inside the route folder I have this:

\Route::name("logo.get")->middleware(["auth", InitializeTenancyByPath::class])
    ->get("{tenant}/storage/logo/{file_id}", "\App\Http\Controllers\LogoController");

As we can see, when I return the URL, the front makes another request to the returned URL. That request is executed by that route and, the TENANT is important. Because using the initialization by tenant, we can go inside the tenant storage folder and after that we can work normally

1 like

Please or to participate in this conversation.