A few months ago, Plank decided it was time to redesign our own website. Rather than just reskin our old WordPress site, we wanted to rebuild from the ground up. The Laravel project was chosen for the project as the it has recently become a favorite among our developers. In reimagining our website, we didn't just want to recreate what we had before. We sought to embark on a project that would allow us to innovate and come up with new tools that we could provide our clients.
Today, Plank is happy to open source one little piece of innovation that emerged from this exercise: Laravel-Mediable. Feel free to check out the code on GitHub or read on to learn a little but about how this new tool came to be.
Building a Media Management Interface
While building the CMS for the new plankdesign.com, we realized that we would need to come up with a way of handling the many media files that would be used throughout the site. The various content types that make up the site make use of thumbnails, banners, galleries, inline images, and even downloadable attachments. hardcoding links to the files in the public/webroot directory is not a sustainable solution.
Fortunately, over the years, we have experimented with numerous ready-made file management plugins, such as CKFinder, ELFinder, Filemanager, WordPress's Media Library, etc. This has given us plenty of time to get a sense of which features make programming easier and what kind of interfaces lead to a smooth user experiece. We came up with the following list of requirements.
- Files should be presented in a grid or list similar to Mac OS Finder or Windows Explorer.
- Folders are a great way to keep content organized.
- Drag/drop uploads are a must, system uploader should be used as a fallback for older browsers.
- Files should present some kind of thumbnail.
- Models should attach to media files using a unique identifier, not by url, path or filename.
- Models should not require any change to their schema to attach new media
- Models must be able to attach multiple different media for different needs (e.g. thumbnail, featured image)
- Models should be able to have any number of media files attached for a single need (e.g. a gallery)
- Media should be reusable without needing to be re-uploaded
- Allow media to be stored in either public and private directories, as needed
- Must be easy to restrict uploads and attachments to particular file types, to avoid causing errors (e.g. thumbnail must always be an image, download should be an archive)
After a few weeks of work, we came up with a system which met all of our requirements. Here is a little peek at the user interface that lives on the backend of plankdesign.com
The code that we are open sourcing today represents the backend component that we built this media management on top of. It sadly doesn't include the interface shown above, but could serve as a foundation for others to build something similar – or something completely innovative.
A Quick Tour
The Laravel-Mediable package consists of three main classes:
Plank\Mediable\Media: an Eloquent subclass which keeps track of one file, including its location on disk and its type.
Plank\Mediable\MediaUploader: A utility class which uploads files to your server and generates
Mediarecords for them
Plank\Mediable\Mediable: a trait that can be added to any other Eloquent model and provides a number of methods for easily attaching and detaching
Upload a file to the server, and place it on the filesystem disk named "uploads". This will create a Media record that can be used to refer to the file
$media = MediaUploader::fromSource($request->file('thumb')) ->toDestination('uploads', 'post/thumbnails') ->upload();
Attach the Media to another eloquent model with one or more tags defining their relationship.
$post = Post::create($this->request->input()); $post->attachMedia($media, ['thumbnail']);
Retrieve the media from the model by its tag(s).
For more in-depth documentation and installation instructions, check out the readme page on github.
Comparing to Laravel-MediaLibrary
A popular Laravel package called Laravel-MediaLibrary released by the Belgian agency Spatie already attempts to do something very similar to our Laravel-Mediable package. We drew a lot of inspiration from this fantastic package, but found that it didn't quite meet all of our needs. Our package is a little bit more complex to use, but offers more flexibility. Here is a quick comparison to help you decide which package best suits your use case.
|Relationship||many-to-one polymorphic, each media record is owned by one related model||many-to-many polymorphic, each media record can connect to any number of related models, and vice versa.|
|Filesystem||Files are stored in directories named after the media id relative to the disk root||Files can be stored anywhere on the disk|
|Association Identifier||Each media record belongs to one "collection"||Media can be attached to a model with any number of "tags"|
|Aggregate Types||Support for images and pdfs||Configurable support for any number of custom types|
|Miscellaneous Features||Glide manipulations||Synchronization commands|