Khóa học Newnet Framework

Bài 5: Quản lý Media - Module Media

Một website không thể nào không có nội dung, chính là module CMS. Nhưng để thêm phần sinh động, không thể thiếu hình ảnh được. Và hình ảnh cũng góp phần không nhỏ trong việc tăng thứ hạn SEO, giúp tiếp cận người dùng dễ dàng hơn. 

Nhưng để quản lý những tệp tin đã upload lên server thì không hề dễ dàng. Nhận biết được điều đó, module Media được ra đời.

Nó được tính hợp sẵn trong editor khi chúng ta xây dựng nội dung cho các bài viết hay các trang. Việc upload dữ liệu lên server cũng được quản lý chặt chẽ.

MEDIAS

Phần quản lý trên admin được quản lý bên trong phần hệ thống.

Vì phần editor được tích hợp sẵn khi upload và được tracking lại. Có thể theo dõi thêm file vendor/newnet-admin/js/scripts/tinymce.js

UPLOAD

Việc xử lý file dựa vào Storage mà laravel hỗ trợ. Chúng ta chỉ can thiệp vào việc tracking để quản lý file trên này thôi. Vậy lưu trữ file thông qua module này sẽ theo cấu hình FILESYSTEM_DISK trong .env

Để upload file ta sử dụng Newnet\Media\MediaUploader

Có thể kham khảo bên trong controller Newnet\Media\Http\Controllers\Admin\UploadController

<?php

namespace Newnet\Media\Http\Controllers\Admin;
...

class UploadController extends Controller
{
    /**
     * @var MediaUploader
     */
    private $mediaUploader;

    public function __construct(MediaUploader $mediaUploader)
    {
        $this->mediaUploader = $mediaUploader;
    }

    protected function handleUploadMedia(UploadedFile $item)
    {
        return $this->mediaUploader->setFile($item)->upload();
    }
}

CROP

Việc generate thumb chỉ cố định theo kích thước như cấu hình khá là bất tiện khi nhu cầu cần generate ra nhiều file. Nên chúng ta có thể sử dụng cách crop với kích thước tùy thích thay vì kích thước cố định.

Chúng ta có thể sử dụng phương thức crop($size) trong model Media với giá trị của $size: w200h300q100 tương ứng với chiều dài, chiều rộng và chất lượng. Tối thiểu giá trị của $size = w200. 

Hoặc có thể sử dụng facade Img::url($file, $width, $height, $quality) với $file là đường dẫn của file cần cắt.

Sau khi cắt thành công, file mới sẽ được sinh ra trong folder public tương ứng. Và trang chỉ nặng khi load lần đầu tiên, lúc này hệ thống phải xử lý cắt file. Nhưng những lần sau đó, khi file đã tồn tại thì không ảnh hưởng gì đến hiệu năng.

TRAITS

Bài toán đề ra:

Việc sử dụng media trong content thì việc tạo những hình ảnh cho bài viết, hình ảnh cho sản phẩm hay video cho hình ảnh là không thể thiếu.

Việc phải khai báo thuộc tính (column) trong từng model (table) để lưu trữ link của media hay đơn giản hơn là id để làm quan hệ.

Lỡ nhiều file thì như thế nào, có thể dùng array. Nhưng xử lý array trong mysql khá mất công và ta không thể sử dụng quan hệ (relationship) - tính năng mạnh mẽ của laravel.

Lỡ thêm cái nữa, trong model cần có nhiều loại media, video, hình ảnh, âm thanh, ... không lẽ tạo nhiều thuộc tính để lưu từng loại.

Lại lỡ như model nào cũng cần có hình ảnh, có phải rất mất công tạo migration, ròi khai báo tùm lum không. Rồi xử lý array nữa, hết cả thời gian.

Và cái lỡ cuối cùng, những hình ảnh, hay video được sử dụng cho nhiều record, hay sử dụng nhiều cho những model khác nhau thì sao. Theo như trên có nghĩa là phải upload 1 file nhiều lần ở nhiều record khác nhau và nhiều model khác nhau không.

Với quá nhiều cái lỡ bên trên, trait Newnet\Media\Traits\HasMediaTrait được ra đời để giải quyết các bài toán trên. Áp dụng kỹ thuật Many To Many (Polymorphic) giúp ta có thể tạo quan hệ giữa media và các model khác một cách dễ dàng.

Sử dụng

<?php

namespace Newnet\Cms\Models;
...
use Newnet\Media\Traits\HasMediaTrait;

class Post extends Model
{
    use HasMediaTrait;

    protected $table = 'cms__posts';

    protected $fillable = [
        'name',
        'gallery',
        'image',
    ];

    public function setImageAttribute($value)
    {
        $this->mediaAttributes['image'] = $value;
    }

    public function getImageAttribute()
    {
        return $this->getFirstMedia('image');
    }

    public function setGalleryAttribute($value)
    {
        $this->mediaAttributes['gallery'] = $value;
    }

    public function getGalleryAttribute()
    {
        return $this->getMedia('gallery');
    }
}

Ở đây là cách dùng của quan hệ 1 - 1 và 1 - n khi sử dụng media.

thuộc tính imagegallery là thuộc tính ảo không cần phải tạo migrate.

Để tạo file cho model này ta sử dụng blade alias có sẵn

@mediamanager(['name' => 'image', 'label' => 'image'])
hay 
@mediafile(['name' => 'image', 'label' => 'image'])
hay 
@gallery(['name' => 'gallery', 'label' => 'Bộ sưu tập'])

Cuối cùng là lấy ra sử dụng. Có thể trỏ đến thuộc tính ảo để truy cập đến model media. Với thuộc tính image, trả về media đầu tiên hay thuộc tính gallery trả về một mảng media. Lúc này có thể sử dụng thuộc tính url để lấy link của media hay lấy link crop như bên trên.