Scout APM is PHP application performance monitoring designed for developers. With tracing logic that ties issues back to the line of code causing them, you can pinpoint n+1 queries, memory leaks, and other abnormalities in real time so you can knock them out and get back to building a great product. Start your free 14-day trial today and get the performance insight you need in less than 4 minutes.

Media Library Pro makes uploading files to a Laravel app a breeze

Original – by Freek Van der Herten – 14 minute read

I'm proud to announce that Media Library Pro is now available. Media Library Pro is an add-on package for our free Media Library base package. It contains a set of Blade, Vue and React components that make it easy to upload files to media library and to manage files inside of a media library collection.

In this blog post, I'd like to introduce Media Library Pro to you.

Getting to know Laravel Media Library

Before getting into the Pro components, let's first get you up to speed with what the free version of Media Library can do for you. If you're already familiar with the free version of Media Library, you can skip this section.

Shortly said, Media Library can associate files with Eloquent models. You can, for instance, associate images with a blog post model.

$blogPost
   ->addMedia($pathToFile)
   ->toMediaCollection('images');

In your Blade view, you can retrieve URLs to the associated images.

@foreach($blogPost->getMedia('images') as $mediaItem)
   <img src="{{ $mediaItem->getUrl() }}" alt="my image" />
@endforeach

Media Library can also generate all sorts of conversions. Using the blog post example, you probably don't want to display the original image in a list of blog posts. It's more likely that you want to show a smaller version of the image, a thumbnail, on such a list.

You can let Media Library generate converted images by defining a conversion on the model. Here's a conversion that could be put in the BlogPost model.

// somewhere in the BlogPost model

public function registerMediaConversions(Media $media = null): void
{
    $this->addMediaConversion('thumb')
          ->width(300)
          ->height(300)
          ->sharpen(10);
}

With that in place, Media Library will generate a thumbnail that fits in a 300x300 square. The image is also sharpened a bit, so it looks crispy. Of course, that thumbnail will be much smaller than the original image. You can get to the URL of a conversion simply by using the conversion's name as an argument to getUrl.

@foreach($blogPost->getMedia('images') as $mediaItem)
   <img src="{{ $mediaItem->getUrl('thumb') }}" alt="my thumbnail" />
@endforeach

In the example above, we've defined a single thumb conversion, but you can add as many conversion to a model as you like.

The Media Library can do a whole lot more. It can handle multiple collections, work with multiple filesytems, create zips on the fly to download multiple files, use a customized directory structure, save bandwidth using responsive images and much more.

In these two videos, I show you the basics of Laravel Media Library.

Want to see more videos like this? Check out our free video course on how to use Laravel Media Library.

The problem with traditional uploads

Before exploring Media Library Pro, let's first explained why we built it in the first place. Here's how a traditional upload form might look like. It uses a regular input of type file.

screenshot

Here's the Blade view that renders that form. It was taken from this demo application

<form method="POST" enctype="multipart/form-data">
    <x-grid>
        @csrf

        <x-field label="name">
            <x-input id="name" name="name" placeholder="Your first name" />
        </x-field>

        <x-field label="file">
            <input type="file" name="file">
            @error('file')
                {{ $message }}
            @enderror
        </x-field>

        <x-button dusk="submit">Submit</x-button>
    </x-grid>
</form>

There are two big problems with this standard upload element.

First, the upload process only starts when the form is submitted. For small files in small forms, this might not be a problem. But imagine you're uploading a multi MB file in a form. When submitting the form, you now have to wait for the upload to complete before seeing the submission results.

The second problem is something that has bothered me for a long, long time. Imagine that the input field is part of a form of which some fields are required. You're selecting a file, submitting the form, leaving some of the required fields empty. You get redirected back to the form where error messages are now displayed. Your previous file selection is gone, and you need to select the file again. Over the years, I've said many curse words when this happened to me.

I'm also pretty sure that, as a developer, you probably lost time debugging uploads because you forgot to add enctype="multipart/form-data" to the form.

In this video, you'll see a demo of all these problems.

Let's look at how all of these problems are solved in Media Library Pro.

Introducing Media Library Pro

Media Library Pro is a paid add-on package that offers Blade, Vue, and React components to upload files to your application. It ships with two components. The first one is the attachment component. It is meant to be used on a public-facing page where you want users to upload one or multiple files.

screenshot

The second one is called the collection component. This one can manage the files in an existing collection. It is meant to be used in the admin part of your app.

screenshot

Both of these components are available as Vue, React and Blade components. Under the hood, the Blade components are powered by Caleb's excellent Livewire package.

These components are straightforward to install and are documented in great detail.

Let's take a look at both the Attachment and Collection component. In the remainder of the blog post, I'll use the Blade version of the examples, but rest assured that everything shown can also be done with the Vue and React counterparts.

The Attachment component

If you want to see a quick demo of the attachment component, check out this video.

You can find the code used in that video in this repo on GitHub. All further code examples are taken from that app.

To get started with the Attachment Blade component you'll have to use x-media-library-attachment in your view.

<form method="POST">
    @csrf

    <input id="name" name="name">

    <x-media-library-attachment name="avatar"/>

    <button type="submit">Submit</button>
</form>

Here's how it looks like after we've selected a file but before submitting the form.

Screenshot of the attachment component

The x-media-library-attachment has taken care of the upload. The file is now stored as a temporary upload. In case there are validation errors when submitting the form, the x-media-library-attachment will display the temporary upload when you get redirected back to the form. There's no need for the user to upload the file again.

Screenshot of the attachment component with validation error

Here's the form request used to validate the uploaded.

namespace App\Http\Requests\Blade;

use Illuminate\Foundation\Http\FormRequest;
use Spatie\MediaLibraryPro\Rules\Concerns\ValidatesMedia;

class StoreBladeAttachmentRequest extends FormRequest
{
    use ValidatesMedia;

    public function rules()
    {
        return [
            'name' => 'required',
            'media' => ['required', $this->validateSingleMedia()
                ->maxItemSizeInKb(3000),
            ],
        ];
    }
}

By applying the ValidatesMedia trait, you get access to the validateSingleMedia, which allows you to validate the upload. You can chain on many validation methods, which are documented here.

In your controller, you can associate the upload file to any model you'd like.

$formSubmission
    ->addFromMediaLibraryRequest($request->media)
    ->toMediaCollection('images');

And that is all you need to do!

The attachment component can be used to handle multiple uploads as well. In this video, you'll see how that is done.

The Collection component

You can manage the entire contents of a media library collection with x-media-library-collection component. This component is intended to use in admin sections.

Here is an example where we will administer an images collection of a $formSubmission model.

<form method="POST">
    @csrf
    <x-field label="name">
        <x-input id="name" name="name" autocomplete="off" placeholder="Your name"
                 value="{{ old('name', $formSubmission->name) }}"/>
    </x-field>

    <x-field label="Images">
        <x-media-library-collection
            name="images"
            :model="$formSubmission"
            collection="images"
            max-items="3"
            rules="mimes:png,jpeg"
        />
    </x-field>

    <x-button dusk="submit" type="submit">Submit</x-button>
</form>

Here's how that component looks like:

Screenshot of the attachment component with validation error

This component will display the contents of the entire collection. Files can be added, removed, updated, and reordered.

In this video, you'll see the collection component in action.

To validate the response of the form, a form request like this one can be used:

namespace App\Http\Requests\Blade;

use Illuminate\Foundation\Http\FormRequest;
use Spatie\MediaLibraryPro\Rules\Concerns\ValidatesMedia;

class StoreBladeCollectionRequest extends FormRequest
{
    use ValidatesMedia;

    public function rules()
    {
        return [
            'name' => 'required',
            'images' => [$this->validateMultipleMedia()
                ->maxItems(3)
                ->itemName('required'),
            ],
        ];
    }
}

Again, you need to ValidatesMedia trait. This time the validateMultipleMedia should be used. You can chain on the other validation methods, which are documented here.

In the controller, you can associate the media in the collection component with your model using the syncFromMediaLibraryRequest method.

Here's the relevant code in the controller of the demo app.

$formSubmission
    ->syncFromMediaLibraryRequest($request->images)
    ->toMediaCollection('images');

Adding custom properties

When using the collection component, you probably want to add some extra fields to be displayed. We've made this a straightforward thing to do.

In the screenshot below, we added the Extra field field.

Extra field

You can achieve this by passing a blade view to the fields-view prop of the x-media-library-collection.

<x-media-library-collection
    name="images"
    :model="$formSubmission"
    collection="images"
    max-items="3"
    rules="mimes:png,jpeg"
    fields-view="uploads.blade.partials.custom-properties"
/>

In that custom-properties view, you can put anything that should be displayed in the right half of the collection component.

Here's the content of that custom-properties view.

@include('media-library::livewire.partials.collection.fields')

<div class="media-library-field">
    <label class="media-library-label">Extra field</label>
    <input
        dusk="media-library-extra-field"
        class="media-library-input"
        type="text"
        {{ $mediaItem->customPropertyAttributes('extra_field')  }}
    />

    @error($mediaItem->customPropertyErrorName('extra_field'))
        <span class="media-library-text-error">
               {{ $message }}
        </span>
    @enderror
</div>

In the form request, you can use the customProperty to validate any extra custom attributes. The second argument of the function can take any validator in Laravel.

namespace App\Http\Requests\Blade;

use Illuminate\Foundation\Http\FormRequest;
use Spatie\MediaLibraryPro\Rules\Concerns\ValidatesMedia;

class StoreBladeCollectionCustomPropertyRequest extends FormRequest
{
    use ValidatesMedia;

    public function rules()
    {
        return [
            'name' => 'required',
            'images' => [$this->validateMultipleMedia()
                ->maxItems(3)
                ->itemName('required|max:30')
                ->customProperty('extra_field', 'required|max:30'),
            ],
        ];
    }
}

In the controller where you process the form submission, you should use the withCustomProperties method to whitelist any extra attributes that you want to sync with your media.

$formSubmission
    ->syncFromMediaLibraryRequest($request->images)
    ->withCustomProperties('extra_field')
    ->toMediaCollection('images');

Here's a video where you see all of this in action.

Customizing the look and feel

By default, both the Attachment and Collection components already look good. Probably you'd like to adapt them so they match the look of your app.

Luckily, this is easy to do. The styles that ship with Media Library Pro can be used by importing or linking dist/styles.css. The styles were built with a default tailwind.config.js.

You can customize the styles by importing src/styles.css and run every @apply rule through your own tailwind.config.js

/* app.css */

@tailwind base;

@tailwind components;

@tailwind utilities;

@import "src/styles.css";

…

To view this in action, watch this video.

How temporary files are used

To achieve that behavior where uploaded files are preserved when a form validation error occurs, we use temporary uploads. In this video, I explain how that works.

Testing the components

Inside the private spatie/laravel-medialibrary-pro repo, there are a lot of tests to make sure the back end integration and the Vue, React, and Blade front end components are working as expected.

We also wanted to have browser tests that ensure that front end components work perfectly with the back end and vice versa. That's why we added Dusk tests in our demo application. You can see them here.

Let's take a look at one of them:

/**
 * @test
 *
 * @dataProvider routeNames
 */
public function it_can_handle_a_single_upload(string $routeName)
{
    $this->browse(function (Browser $browser) use ($routeName) {
        $browser
            ->visit(route($routeName))
            ->type('name', 'My name')
            ->attach('@main-uploader', $this->getStubPath('space.png'))
            ->waitForText('Remove')
            ->waitUntilMissing('.media-library-progress-wrap.media-library-progress-wrap-loading')
            ->press('@submit')
            ->assertSee('Your form has been submitted');

        $this->assertCount(1, FormSubmission::get());

        $this->assertEquals('space.png', FormSubmission::first()->getFirstMedia('images')->file_name);
    });
}

This test will upload a file and make sure that the file is associated with a model after the form is submitted.

A thing to note here is that @dataProvider attribute. This will make PHPUnit run the test for each result returned by the routeNames function defined in the same file.

public function routeNames(): array
{
    return [
        ['vue.attachment'],
        ['react.attachment'],
        ['blade.attachment'],
    ];
}

You can see that in combination with the routeNames function, the it_can_handle_a_single_upload will run for the vue.attachment, react.attachment and blade.attachment routes. Visiting these routes will display the form that will use the Vue, React, or Blade component, respectively. So, this one test covers a lot of logic. It makes sure that the component work using any technology. This gives us a lot of confidence that all of the components are working correctly.

Another cool thing to note is that the Dusk tests also run on GitHub Actions. Here's the workflow contained in the repo.

Tests

In closing

In my mind, these front end components were a final missing part in the media library experience. I'm delighted how they turned out and how easy it now becomes to upload and manage media in a Laravel app.

Because we invested quite some time in getting these components just right, we decided to make spatie/laravel-media-library-pro a paid package. You can buy a license on our website. As mentioned previously, the package contains Blade, Vue, and React components. You'll find the extensive documentation [here].

After you've bought a license, you'll immediately get access to the private spatie/laravel-medialibrary-pro repo. Even if you're not in the market for kick-ass upload components, it still might be worthwhile to buy them: the source code contains many interesting things you might learn from.

At the time of writing, we are running a launch promo. Use this coupon code when buying Media Library Pro to get a 20% discount:

MEDIA-LIBRARY-PRO-IS-HERE

Our whole team gave input on these components, so I consider it a team effort. My colleague Adriaan coded up most of the JavaScript. Willem, as always, made everything look gorgeous.

For those wondering, the base media library package is still free, and we'll always keep it free.

Be sure also to check out our other paid products and our extensive collection of free open source packages.

Stay up to date with all things Laravel, PHP, and JavaScript.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

Webmentions

Saad M. liked on 16th November 2020
Christopher Dosin liked on 16th November 2020
Thomas liked on 16th November 2020
Mozammil liked on 16th November 2020
Erik Slooff liked on 16th November 2020
حسام عبد liked on 16th November 2020
Gaurav Makhecha replied on 16th November 2020
3) The team at @spatie_be has already made out life easy with the Laravel Media library package Now they are here to make it even easier with 'Media Library Pro': front end components for file uploads. My fav feature is Temporary file uploads twitter.com/freekmurze/sta…
Amir Rehman liked on 16th November 2020
Ansari Zubair Ahmad liked on 16th November 2020
Ansari Zubair Ahmad retweeted on 16th November 2020
tona.castelan liked on 16th November 2020
Viral Ghodadara liked on 16th November 2020
{{ Hello_Artisan }} liked on 15th November 2020
K PradeepKumar 🚀 liked on 15th November 2020
Claus Lehmann Munch liked on 15th November 2020
علاء الدين retweeted on 15th November 2020
Sheikh Talha Hussain Siddiqui liked on 14th November 2020
chetan kharel liked on 14th November 2020
Nicolas Rodriguez M liked on 13th November 2020
Ernesto Aides liked on 13th November 2020
Anees Khan liked on 13th November 2020
Kurt Erauw liked on 13th November 2020
Diar liked on 13th November 2020
Simon Ellensohn liked on 13th November 2020
Ahmad. liked on 13th November 2020
Mustafa liked on 13th November 2020
kirill stryaponoff liked on 13th November 2020
Maxcelos liked on 13th November 2020
Bezhan Salleh liked on 13th November 2020
Tuginho liked on 13th November 2020
KhaN NaN liked on 13th November 2020
K. liked on 13th November 2020
Nguyễn Hồng Thế liked on 13th November 2020
Camiant liked on 13th November 2020
Mohammad Aktaa🌃 liked on 13th November 2020
danlee liked on 13th November 2020
Marcos Timm Rossow liked on 13th November 2020
Ben Cavens liked on 13th November 2020
Arslan Ramay retweeted on 13th November 2020
Arslan Ramay liked on 13th November 2020
Mahmoud Elnaggar liked on 13th November 2020
Carlos Meneses retweeted on 13th November 2020
Carlos Meneses liked on 13th November 2020
JNicolasRivera retweeted on 13th November 2020
Артем Маковецкий liked on 13th November 2020
Harun Baş liked on 13th November 2020
JNicolasRivera liked on 13th November 2020
didinka johnson retweeted on 13th November 2020
Loyd RG Tafireyi retweeted on 13th November 2020
audetcameron liked on 13th November 2020
Alan lam liked on 13th November 2020
newwave liked on 13th November 2020
Geert Lucas Drenthe retweeted on 13th November 2020
Enzo Notario liked on 13th November 2020
Freek Van der Herten 🐘 replied on 13th November 2020
You can upload and store webp file in the medialibrary. Out of the box, it can’t generate a thumbnail for those, but the medialib is extendable and you can add support for this in your own project.
Marc Carlucci 🚀 retweeted on 12th November 2020
Norbert Tóth liked on 12th November 2020
Rafael Hernandez liked on 12th November 2020
Hardik Shah liked on 12th November 2020
Fantomius liked on 12th November 2020
Nathanael McDaniel liked on 12th November 2020
Atiq Samtia liked on 12th November 2020
Jorge González liked on 12th November 2020
Flam1ngo liked on 12th November 2020
Edwin I Arellano liked on 12th November 2020
Rafael Lunardelli 🐧 liked on 12th November 2020
Sjoerd Stottelaar liked on 12th November 2020
Adriaan Marain liked on 12th November 2020
Yann Haefliger liked on 12th November 2020
Tauseef shah liked on 12th November 2020
koro liked on 12th November 2020
/dev/prabakaran liked on 12th November 2020
Oilmone liked on 12th November 2020
Jesil Jose liked on 12th November 2020
Fabrice Yopa liked on 12th November 2020
Runar Jørgensen liked on 12th November 2020
Adam 🤙🏼 Mench liked on 12th November 2020
JCCZMETAL liked on 12th November 2020
El feo liked on 12th November 2020
Edward B liked on 12th November 2020
David Cortés Toledano liked on 12th November 2020
Jr 👨‍💻 liked on 12th November 2020
Helder Willian liked on 12th November 2020
Jesus Guerrero liked on 12th November 2020
NerdWithDopeHair liked on 12th November 2020
Alex liked on 12th November 2020
Richard Radermacher liked on 12th November 2020
Scorp974 liked on 12th November 2020
Wyatt liked on 12th November 2020
Jose Luis Alonso liked on 12th November 2020
Mitchell Johnson 🛠 liked on 12th November 2020
Muhammad Ibnuh liked on 12th November 2020
Julio Serpone liked on 12th November 2020
Efren Colín ✨🤖✨ liked on 12th November 2020
Woeler liked on 12th November 2020
Atiq Samtia retweeted on 12th November 2020
Ari bobo retweeted on 12th November 2020
Hardik Shah retweeted on 12th November 2020
Jose Luis Alonso retweeted on 12th November 2020
Adriaan Marain retweeted on 12th November 2020
Sebastiaan Luca 🤖 replied on 12th November 2020
Is there an advised approach on how to handle the package's license key? Say you've got 3 devs, GitHub Actions CI, staging and production environments, etc. Each needs the key, but that opens the door to some security issues. A guest is given access to the repo, a dev leaves, …
Kamil Karkoszka retweeted on 12th November 2020
Miguel Manzano García retweeted on 12th November 2020
Chris retweeted on 12th November 2020
Andy Newhouse retweeted on 12th November 2020
Simon Lincoln retweeted on 12th November 2020
Andrés Santibáñez retweeted on 12th November 2020
Alex Vargas retweeted on 12th November 2020
Salisu Ibn Alli retweeted on 12th November 2020
Madiou BAH retweeted on 12th November 2020
Yann Haefliger retweeted on 12th November 2020
Mohit Panjwani liked on 12th November 2020
Julio Serpone retweeted on 12th November 2020
Niko Halink liked on 12th November 2020
H N O O Z liked on 12th November 2020
Irving Aguilar liked on 12th November 2020
Anwar Kamel liked on 12th November 2020
GavTheDev liked on 12th November 2020
Incubux liked on 12th November 2020
Ọmọ ìyá tíṣà liked on 12th November 2020
Brendan Quinlan liked on 12th November 2020
Andrés Santibáñez liked on 12th November 2020
Stefan Zweifel liked on 12th November 2020
Oke Michael liked on 12th November 2020
Madiou BAH liked on 12th November 2020
Luka Peharda liked on 12th November 2020
BurtonJ liked on 12th November 2020
Chris liked on 12th November 2020
Swapnil Bhavsar liked on 12th November 2020
Simon Lincoln liked on 12th November 2020
Waqar Zafar Tarar liked on 12th November 2020
Tashi Tam's liked on 12th November 2020
bambamboole liked on 12th November 2020
Miguel Manzano García liked on 12th November 2020
José Francisco liked on 12th November 2020
Willan Correia liked on 12th November 2020
Andy Newhouse liked on 12th November 2020
Ajith Lal liked on 12th November 2020
Rushil Ramautar liked on 12th November 2020
Bernardo liked on 12th November 2020
GavTheDev replied on 12th November 2020
Same question
Santosh Khanal replied on 12th November 2020
When I checked the demo on the attachment. After selecting a file, and then if I remove it then try to re upload, it does not do anything? Is that a bug?
Hashman.Hashimoto liked on 12th November 2020
Martijn replied on 12th November 2020
Looks great :) Will there also be a plugin for editors like ckeditor?
Dries Vints liked on 12th November 2020
Do Hoang Dinh Tien retweeted on 12th November 2020
Christoph Rumpel 🤠 retweeted on 12th November 2020
Dries Vints retweeted on 12th November 2020
Jef retweeted on 12th November 2020
Nuno Maduro 🐘 retweeted on 12th November 2020
Ahmed retweeted on 12th November 2020
Taylor Otwell 🛸 retweeted on 12th November 2020
Mohamed Said retweeted on 12th November 2020
laboré retweeted on 12th November 2020
Laravel retweeted on 12th November 2020
Roberto Luna Rojas retweeted on 12th November 2020
Hardiansyah retweeted on 12th November 2020
Spatie retweeted on 12th November 2020
Maple retweeted on 12th November 2020
Dan Abend retweeted on 12th November 2020
Daniel Alves retweeted on 12th November 2020
Sebastian De Deyne retweeted on 12th November 2020
Brandon Williams liked on 12th November 2020
Haneef Ansari 🍭 liked on 12th November 2020
Conrad Fuhrman liked on 12th November 2020
Niels liked on 12th November 2020
Tony Messias liked on 12th November 2020
Steve Bauman liked on 12th November 2020
Alexander Makhaev liked on 12th November 2020
Mohamed Said liked on 12th November 2020
Daniel Gehn liked on 12th November 2020
Fran.php liked on 12th November 2020
Daniel Alves liked on 12th November 2020
laboré liked on 12th November 2020
nethask liked on 12th November 2020
Ciro Lo Sapio liked on 12th November 2020
Mosh liked on 12th November 2020
Grant Williams liked on 12th November 2020
Roberto Luna Rojas liked on 12th November 2020
Nuno Maduro 🐘 liked on 12th November 2020
Brett R liked on 12th November 2020
TECHNICAL KD liked on 12th November 2020
/e/halil 💻🎧📌 liked on 12th November 2020
Nael Ammar liked on 12th November 2020
Ktimporta liked on 12th November 2020
Peter Brinck 🤘 liked on 12th November 2020
Ammly Fredrick liked on 12th November 2020
Do Hoang Dinh Tien liked on 12th November 2020
Ahmed liked on 12th November 2020
Thibeault 👨🏻‍💻 liked on 12th November 2020
Alex Rowe liked on 12th November 2020
fatizahra liked on 12th November 2020
Batbayar B. liked on 12th November 2020
Diego liked on 12th November 2020
Ahmed Fawzy liked on 12th November 2020
Sarah Mount liked on 12th November 2020
WaveHack liked on 12th November 2020
Volkan Baskın liked on 12th November 2020
Baspa liked on 12th November 2020
Johannes Brückner liked on 12th November 2020
redaready liked on 12th November 2020
Fred C. liked on 12th November 2020
Flamur Mavraj liked on 12th November 2020
J---- liked on 12th November 2020
jaccogardner7 liked on 12th November 2020
midnightelf18 liked on 12th November 2020
Daniel Naxon liked on 12th November 2020
André Breia liked on 12th November 2020
haplologist liked on 12th November 2020
Qooh0 liked on 12th November 2020
Nick Ciske liked on 12th November 2020
Freek Van der Herten 🐘 replied on 12th November 2020
Yes! spatie.be/docs/laravel-m…
Miguel Piedrafita 🚀 liked on 12th November 2020
Isaac Pitwa liked on 12th November 2020
Freek Van der Herten 🐘 replied on 12th November 2020
Contact us (info@spatie.be) for usage in open source apps. Mention in which app you want to use it, and if users see the source code
Alexander Makhaev replied on 12th November 2020
Is it possible to use “One application” license for one Open Source app?
Alexander Makhaev replied on 12th November 2020
Will it work for Nuxt based frontend out of the box? With Laravel as an API backend.
Vaggelis Yfantis retweeted on 12th November 2020
Alan retweeted on 12th November 2020
Aryeh Feld liked on 12th November 2020
Rias Van der Veken retweeted on 12th November 2020
Uncommon Name 🇧🇧 retweeted on 12th November 2020
Owen Voke retweeted on 12th November 2020
Gus retweeted on 12th November 2020
Faruk Nasir liked on 12th November 2020
liagason liked on 12th November 2020
Owen Voke liked on 12th November 2020
Piotr Gumienny liked on 12th November 2020
Alan liked on 12th November 2020
Tiago Rodrigues liked on 12th November 2020
Elliot (Raison) liked on 12th November 2020
Mark Myers liked on 12th November 2020
Mark Topper liked on 12th November 2020
Stefan Galescu liked on 12th November 2020
Vaggelis Yfantis liked on 12th November 2020
Rias Van der Veken liked on 12th November 2020
Aryeh Feld replied on 12th November 2020
Is it possible to associate the same media item to multiple models? 🙏
Aaron Heath liked on 12th November 2020
Uncommon Name 🇧🇧 replied on 12th November 2020
Damn, I was hoping I could afford it. 😭😭😭. But good work as usual from Spatie and Freek. 👍