Skip to content

Media

Introduction

Qore.works Business comes default with Filament Spatie Media Library plugin. The plugin is build on top of the Spatie Laravel MediaLibrary. The plugin is extending the Filament File Upload.

Configuration

There is a default public and private disk. Those are automatically configured. If you would like to change the public disks to s3, you can add that to your config/filesystems.php:

php
'disks' => [
    's3_public' => [ 
        'driver' => 's3', 
        'key' => env('AWS_ACCESS_KEY_ID'), 
        'secret' => env('AWS_SECRET_ACCESS_KEY'), 
        'region' => env('AWS_DEFAULT_REGION'), 
        'bucket' => env('AWS_BUCKET'), 
        'url' => env('AWS_URL'), 
        'endpoint' => env('AWS_ENDPOINT'), 
        'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), 
        'visibility' => 'private', 
        'throw' => false, 
    ], 
],

Change the default public disk with you environment:

shell
FILAMENT_FILESYSTEM_DISK_PUBLIC=s3_public

Note; if you would like to change the disk on assets, that can be done per asset type.

Configuring S3 bucket on Amazone

We want to create a S3 bucket for our development local environment. First we need to create a policy.

  1. Create policy

First we create a new policy. You can use the following JSON to configure the policy at ease. Give it the name with suffix Policy, for example: DevelopmentQw-Policy.

Click to view the JSON policy example
json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "acm:ListCertificates",
                "cloudfront:GetDistribution",
                "cloudfront:GetStreamingDistribution",
                "cloudfront:GetDistributionConfig",
                "cloudfront:ListDistributions",
                "cloudfront:ListCloudFrontOriginAccessIdentities",
                "cloudfront:CreateInvalidation",
                "cloudfront:GetInvalidation",
                "cloudfront:ListInvalidations",
                "elasticloadbalancing:DescribeLoadBalancers",
                "iam:ListServerCertificates",
                "sns:ListSubscriptionsByTopic",
                "sns:ListTopics",
                "waf:GetWebACL",
                "waf:ListWebACLs"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListAllMyBuckets"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::development.qw.local"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::development.qw.local/*"
            ]
        }
    ]
}
  1. Create a user-group

Next we will create a new user group for the system. The group we give it a suffix with Group. For example: DevelopmentQwGroup. Attach the created policy DevelopmentQw-Policy to the group.

  1. Create user

Now that we have a policy and user group, we can create a new user. The user we will give a suffix of User. For example: DevelopmentQw-User. Attach the user to the new created group DevelopmentQwGroup.

  1. Create access key

View the created user DevelopmentQw-User and go to the tab Security credentials. There you can view and create a new access key. Create a new access key and select the use case: Third-party service. Store the newly generated access keys in Ncr.pt.

  1. Create bucket

Now we can create a new bucket for storing the media files. Give the bucket a unique name, for example: development.qw.local. Keep all settings as is:

  • ACLs disabled
  • Block all public access (file are accessed through own php scripts, so no public access is needed)
  • Bucket Versioning: disable
  • Server-side encryption with Amazon S3 managed keys
  • Bucket Key: enable

Preparing model first

To associate media with a model, the model must implement the following interface and trait:

php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class YourModel extends Model implements HasMedia
{
    use InteractsWithMedia;
}

Filament integration

To upload files in Filament, you can add the following:

php
use QoreWorksBusiness\QoreAdminBase\Fields\MediaFileUpload;

return [
    MediaFileUpload::make('media'),
],

By default all media will be stored on a private disk, but if you wish to change the disk, you can do it like this:

php
use QoreWorksBusiness\QoreAdminBase\Fields\MediaFileUpload;

return [
    MediaFileUpload::make('media')
        ->public(),
],

Default path structure

The path structure is default with some subfolders to prevent heavily load on viewing large directories. The first 2 characters of the uuid are used for the subfolders followed by the id of the media record.

Example:

text
uuid: b30b820f-4009-4102-9d23-efc81b052bbc
id: 7
calculated path: {uuid}/{id}/{filename}.{extension}

Calculated path: storage/app/private/media/b/3/7/01HGTJZ74VN6Y14R9XBGXYZ4AT.jpg

Delete or replace media

Default the media is being removed from the server and database when replaced or deleted.

Mimetype restrictions

php
use QoreWorksBusiness\QoreAdminBase\Fields\MediaFileUpload;

return [
    MediaFileUpload::make('media')
        ->image(),
],

Or if you need more control:

php
use QoreWorksBusiness\QoreAdminBase\Fields\MediaFileUpload;

return [
    MediaFileUpload::make('media')
        ->acceptedFileTypes([
            'application/pdf',
        ])
        ->openable();
],

Create thumbnails on uploading

On your model, specify the conversions you would like to do:

php
use Spatie\Image\Enums\Fit;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

class YourModel extends Model implements HasMedia
{
    use InteractsWithMedia;

    public function registerMediaConversions(Media $media = null): void
    {
        $this
            ->addMediaConversion('thumb')
            ->fit(Fit::Crop, 300, 300)
            ->nonQueued();
    }
}

After that you can call the conversion on your field

php
use QoreWorksBusiness\QoreAdminBase\Fields\MediaFileUpload;

return [
    MediaFileUpload::make('media')
        ->image()
        ->conversion('thumb')
],

File will be stored with separate conversions:

text
storage/app/private/media/b/3/7/01HGTJZ74VN6Y14R9XBGXYZ4AT.jpg
storage/app/private/media/b/3/7/conversions/01HGTJZ74VN6Y14R9XBGXYZ4AT-thumb.jpg

Resize image on uploading

This can be done with the default Filament options.

php
use QoreWorksBusiness\QoreAdminBase\Fields\MediaFileUpload;

return [
    MediaFileUpload::make('media')
        ->image()
        ->imageResizeMode('cover')
        ->imageCropAspectRatio('16:9')
        ->imageResizeTargetWidth('1920')
        ->imageResizeTargetHeight('1080')
],

Image editor for custom cropping or resizing

php
use QoreWorksBusiness\QoreAdminBase\Fields\MediaFileUpload;

return [
    MediaFileUpload::make('media')
        ->image()
        ->imageEditor(),
],
Media image editor

Get media url

When having the media model, it is easy to retrieve the url of the media.

php
$media->getUrl();

This will return the url for public or private depending on the disk the media is linked to. For example:

text
public: /media/public/887c7bc6-db7e-414a-ad11-1b7059b734c4/20140303_173219.jpg
private: /media/65af7d23-bb7b-4f8c-9dc0-0fa6cb5232b9/20111117_170742.jpg?expires=1701876835&signature=e3217e8e88e5209017ff4a48f47c635b392dcb0e51bc2a59d4f7b9cb14eafe04

This is also possible for the conversions:

php
$media->getUrl('thumb');

Display media inside blade

If your $media instance concerns an image, you can render it directly in a Blade view.

php
Here is the original image: {{ $media }}

This will output an img tag with a src attribute that contains an url to the media.

You can also render an img to a conversion.

php
Here is the converted image: {{ $media->img('thumb') }}

You can add extra attributes by calling attributes.

php
Here is the image with some attributes: {{ $media->img()->attributes(['class' => 'my-class']