Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filejet Bundle Laravel Package

filejet/filejet-bundle

FileJet Bundle integrates the FileJet file upload and delivery service into Symfony/PHP applications, providing configuration and service wiring for uploads, transformations, storage, and asset delivery with minimal setup, helping developers add FileJet-powered file handling quickly.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: this is a Symfony bundle, not a Laravel package. There is no Illuminate\Support\ServiceProvider, no package discovery, and no config/filejet.php merge. If you composer require filejet/filejet-bundle into a Laravel app you will get the classes but nothing wired up. Two realistic paths:

  1. You actually have a Symfony app (or a Symfony microservice sitting next to your Laravel app) — use the bundle as intended.
  2. You are staying in Laravel — skip the bundle and pull the underlying FileJet PHP client directly, then wrap it in your own service provider. You lose the DI sugar but gain a normal Laravel integration. Roughly:
// composer require filejet/filejet-php  (or whatever the SDK package is named)
// app/Providers/FileJetServiceProvider.php
public function register(): void
{
    $this->app->singleton(FileJetClient::class, fn ($app) => new FileJetClient(
        apiKey: config('services.filejet.key'),
        storageId: config('services.filejet.storage'),
    ));
    $this->app->alias(FileJetClient::class, 'filejet');
}
// config/services.php
'filejet' => [
    'key'     => env('FILEJET_API_KEY'),
    'storage' => env('FILEJET_STORAGE_ID'),
],

Minimal Symfony steps (if that's your context):

composer require filejet/filejet-bundle
// config/bundles.php
FileJet\Bundle\FileJetBundle::class => ['all' => true],
# config/packages/filejet.yaml
filejet:
    api_key: '%env(FILEJET_API_KEY)%'
    storage_id: '%env(FILEJET_STORAGE_ID)%'

Where to look first: open vendor/filejet/filejet-bundle/src/ and read the DependencyInjection/ folder — the extension class tells you the exact config keys, and the service definition file tells you the exact service IDs to inject. With 0 stars and 0 dependents, the source is the only reliable documentation; the README will likely be a stub. Budget 20 minutes for that read before writing any code.

First use case: the highest-value thing FileJet does is URL mutation — you store a file once and request derived variants by appending operations to the URL. Get that working end-to-end (upload one file, render three sizes in a template) before touching anything else.

Implementation Patterns

Inject the client, don't reach for the container. The bundle registers a service; type-hint it and let autowiring do the rest. If you're porting to Laravel, keep the same discipline — inject a typed client, not app('filejet').

Upload once, store the reference, mutate forever. The pattern that pays off:

// store the file identifier, not a pre-rendered URL
$file = $fileJet->upload($request->file('avatar'), '/avatars');
$user->update(['avatar_ref' => $file->getId()]);

Then derive variants at render time. Storing the reference (not the URL) means you can change mutation parameters later without a data migration — this is the single biggest architectural decision and it's easy to get wrong on day one.

Centralize mutation strings. Mutation syntax is a string DSL and it will be repeated across templates, API resources, and emails. Wrap it:

class ImageUrl
{
    public function __construct(private FileJetClient $fileJet) {}

    public function avatar(?string $ref, int $size = 128): ?string
    {
        if (! $ref) {
            return null;
        }

        return $this->fileJet->url($ref, "resize:{$size}x{$size}/quality:80");
    }
}

Then {{ $imageUrl->avatar($user->avatar_ref) }} in Blade, or a Twig extension on the Symfony side. One class owns the mutation vocabulary; everyone else calls methods with names.

Bind a facade for Blade ergonomics (Laravel path) if you're doing this a lot:

// app/Facades/FileJet.php — thin, no logic
class FileJet extends Facade {
    protected static function getFacadeAccessor() { return FileJetClient::class; }
}

Integration tip — mirror into Storage when you need local semantics. If parts of your app expect Storage::disk('...') behaviour (temporary URLs, exists(), streams), write a small adapter rather than sprinkling FileJet calls through the codebase. FileJet is a CDN/delivery layer; your Storage abstraction is a persistence layer. Keeping the seam at one adapter class means you can swap providers later without touching controllers.

Config: treat it as environment-driven and immutable. Both Symfony's config/packages/*.yaml and a Laravel config/services.php entry should be env-backed only. Never branch on config inside a service — pass the resolved values in the constructor so tests can instantiate without a container.

Testing pattern: bind a fake in the test container. In Laravel:

$this->app->instance(FileJetClient::class, new class extends FileJetClient {
    public function url(string $ref, string $mutations = ''): string {
        return "https://cdn.test/{$ref}?m={$mutations}";
    }
});

Assert on the reference stored and the mutation string produced — not on the full CDN URL. That keeps tests stable if the base domain or account changes.

Workflow tip for teams: put the mutation vocabulary in one markdown file in the repo (docs/filejet-mutations.md) listing the named presets (avatar, hero, thumb) with their exact strings and rendered dimensions. Nobody remembers whether it's resize:300x or width:300.

Gotchas and Tips

No Laravel package discovery. Composer will not register anything in a Laravel app. If you're in Symfony, config/bundles.php is manual. Either way, "I installed it and nothing happened" is the expected first outcome — not a bug.

Service IDs differ from class names. Symfony bundles routinely register services under string IDs like filejet.client with an alias to the FQCN. Autowiring usually works, but if you get "cannot autowire" check Resources/config/services.xml (or the PHP/YAML equivalent) for the actual ID and alias it explicitly in services.yaml:

FileJet\Client: '@filejet.client'

The Laravel equivalent is $this->app->alias(...) in your provider — forget it and app(FileJetClient::class) throws.

env() outside config files is a trap. In Laravel, env() returns null once config:cache runs. In Symfony, %env()% resolution happens at container compile time and behaves differently under cache:warmup. Resolve once in config/, never in a service or a Blade template.

This package has essentially zero adoption. 0 stars, 0 dependents, no community answers. Consequences: pin the exact version in composer.json (no ^), read the changelog before every bump, and assume no one has hit your bug before you. The release date is recent-but-irregular, so verify the tag actually matches the code you're reading.

Symfony version compatibility is the most likely install failure. Check the require block for the symfony/* constraint range before you commit to it; a bundle pinned to 5.4 will fight a 7.x app. In a Laravel app this is moot — you're not installing the bundle at all.

Mutation order matters. Mutations generally apply left-to-right; resize then quality is not the same pipeline as quality then resize in terms of final bytes. Also, changing a mutation string changes the CDN cache key — which is good (no stale variants) but means a "cosmetic" tweak to quality invalidates every edge cache for that preset. Treat mutation strings as a public contract.

Signed/private URLs are a separate concern from mutations. If files need access control, the signature is computed over a specific URL shape. Do not hand-append query params to a signed URL — you'll invalidate the signature. Build the mutation string first, then sign the final URL.

Exception types will leak. The client likely throws HTTP-client-specific exceptions (Guzzle or Symfony HttpClient). Catch them at your service boundary and rethrow as a domain exception (FileUploadFailed) so controllers don't depend on transport details and so you can swap the underlying client later.

Extension points worth knowing:

  • Decorate, don't fork. Wrap the bundle's client service in your own class implementing the same interface and register it as a decorator — keeps the vendor package updatable.
  • Custom mutation presets belong in your app, not in the vendor config. The bundle's config is for credentials and storage identity.
  • Event/listener hooks (if the bundle dispatches upload events) are the clean place to write audit logs or trigger thumbnailing — check EventDispatcher usage in the source before adding observers to the client class.
  • If the bundle assumes Symfony's HttpClient, you can inject a mocked client in tests rather than mocking FileJet itself — often lower friction than faking the whole API surface.

Debugging checklist when a URL 404s or renders wrong: (1) is the storage ID correct in config, (2) does the file reference exist and belong to that storage, (3) does the mutation string have a typo or a trailing slash, (4) is the URL signed and has it expired, (5) are you hitting a stale edge cache from an earlier mutation string. In practice it's #3 or #5 more often than anything else.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json