Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for third-party packages #98

Open
3 of 16 tasks
ollieread opened this issue Feb 2, 2025 · 6 comments
Open
3 of 16 tasks

Support for third-party packages #98

ollieread opened this issue Feb 2, 2025 · 6 comments
Assignees
Labels
status: investigating The issue is being investigated status: need info The issue requires more information status: planning The issue is being planned for the future type: meta The work relates to the running of the package or some other meta topic

Comments

@ollieread
Copy link
Member

ollieread commented Feb 2, 2025

Some third-party packages will require some additional work to support. While supporting every package is unfeasible, it's perhaps worth looking into some additional addons to at least support Laravel's first-party packages.

This is a non-exhaustive list of packages to look into supporting.

Note

Some of these packages won't require any work, or may require so much work that they cannot be supported.

Discussion: https://github.com/orgs/sprout-laravel/discussions/72

@ollieread ollieread self-assigned this Feb 2, 2025
@ollieread ollieread converted this from a draft issue Feb 2, 2025
@ollieread ollieread added status: need info The issue requires more information status: investigating The issue is being investigated type: meta The work relates to the running of the package or some other meta topic status: planning The issue is being planned for the future labels Feb 2, 2025
@ollieread
Copy link
Member Author

ollieread commented Feb 2, 2025

Livewire

I've looked into this briefly and found the following:

  • The livewire.update route needs to be registered using a custom route, which is wrapped in the tenanted route group.
  • If the generated route requires parameters, they should have a default value set.
  • It's possible that using this will prevent you from having Livewire function in multiple tenancies

I need to find out:

  • Exactly how the Livewire route is used - Added on a <script> tag
  • Whether it's possible to set the route during runtime - It is
  • If not, how difficult would it be to override the functionality that does? - Not needed

@ollieread
Copy link
Member Author

Filament

I've also looked briefly into Filament and found the following:

  • It would require a solution for Livewire, as it's built on it
  • Filaments multitenancy functionality may work for a cross tenant panel
  • To create a portal per tenant, it is most likely that the Panel class needs to be extended to add Sprout-specific functionality

Things to do:

  • Read about Filament multitenancy more
  • Look into what would need to be added to have a Panel function

@ollieread
Copy link
Member Author

Telescope

Looking into Laravel Telescope, I've discovered the following:

  • It's possible to tag requests with the 'tenancy' and 'tenant' for a simple less-intrusive solution
  • It may be possible to override Telescopes request watcher to have specific sections for tenants

I need to:

  • Look further into customising the Telescope request watcher
  • Look further into creating a custom watcher/panel/section for Sprout, and whether it's even required

@ollieread
Copy link
Member Author

ollieread commented Feb 8, 2025

Livewire Cont...

Update Route

Since it is possible to dynamically set the Livewire update route, a route needs to be created during the tenancy setup phase, which adds a route parameter. By default, this should be the path resolver.

An example implementation of a Livewire service override is as follows.

namespace App;

use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
use Livewire\Mechanisms\HandleRequests\HandleRequests;
use Sprout\Contracts\IdentityResolver;
use Sprout\Contracts\Tenancy;
use Sprout\Contracts\Tenant;
use Sprout\Overrides\BaseOverride;

class LivewireOverride extends BaseOverride
{
    public function setup(Tenancy $tenancy, Tenant $tenant): void
    {
        $resolver = $this->getResolverForLivewire();

        // We need to call setup so that the URL generator can be updated
        // with default parameters for the tenant.
        $resolver->setup($tenancy, $tenant);

        $this->getApp()
             ->make(HandleRequests::class)
             ->setUpdateRoute(function (array $handler) use ($tenancy, $resolver) {
                 $route = null;

                 // We won't use the helper here, and we'll use the resolver
                 // directly to ensure that the route is created with the
                 // correct URL parameters.
                 $resolver->routes(
                     $this->getApp()->make(Router::class),
                     static function () use ($handler, &$route) {
                         $route = Route::name('sprout.livewire.update')
                                       ->post('/livewire/update/', $handler);
                     },
                     $tenancy
                 );

                 return $route;
             });
    }

    protected function getResolverForLivewire(): IdentityResolver
    {
        return $this->getSprout()
                    ->resolvers()
                    ->get($this->config['resolver'] ?? 'path');
    }
}

File Upload

The disk to use for upload needs to be set via the config option livewire.temporary_file_upload.disk. Unfortunately, the upload controller does something different depending on whether it's an S3 disk, GCS disk or other disk. The logic for determining this is less than ideal for Sprouts filesystem override.

The class that sets all this up is Livewire\Features\SupportFileUploads\SupportFileUploads, which is a component hook, which is entirely static so can't be overridden via DI.

It looks like the best solution is to redefine the already existing routes when defining the update route for the path resolver.

// Create the upload and preview routes
Route::name('livewire.upload-file')
     ->post('/livewire/upload-file', [FileUploadController::class, 'handle']);

Route::name('livewire.preview-file')
     ->get('/livewire/preview-file/{filename}', [FilePreviewController::class, 'handle']);

As for the filesystem handling, it looks like the only solution to that is a hacky workaround using composers autoload classmap, to map to a fake Sprout controlled version of FileUploadConfiguration.

@ollieread
Copy link
Member Author

ollieread commented Feb 10, 2025

Filament Cont...

To override filament, there are two options.

  1. Add filament/filament to dont-discover in composer.json and register a service provider which overrides the default filament one, providing a custom set of routes.
public function configurePackage(Package $package): void
{
    $package
        ->name('filament-panels')
        ->hasCommands($this->getCommands())
        ->hasRoutes('web')
        ->hasTranslations()
        ->hasViews();
}
  1. Extend the Panel class and others that are used to generate routes, to be tenant-aware.

@ollieread
Copy link
Member Author

Fortify

To make Fortify multitenanted, the automatic routing needs to be disabled by setting Fortify::$registersRoutes to false, and then manually registering the routes in a tenanted route group like so:

Route::tenanted(function () {
    Route::group([
        'namespace' => 'Laravel\Fortify\Http\Controllers',
        'domain' => config('fortify.domain', null),
        'prefix' => config('fortify.prefix'),
    ], function () {
        $this->loadRoutesFrom(base_path('vendor/laravel/fortify/routes/routes.php'));
    });
});

@ollieread ollieread moved this from Ready to Backlog in Sprout Development Feb 12, 2025
@ollieread ollieread moved this from Backlog to Ready in Sprout Development Feb 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: investigating The issue is being investigated status: need info The issue requires more information status: planning The issue is being planned for the future type: meta The work relates to the running of the package or some other meta topic
Projects
Status: Ready
Development

No branches or pull requests

1 participant