Skip to content

Commit

Permalink
Merge pull request #343 from plank/v6
Browse files Browse the repository at this point in the history
V6
  • Loading branch information
frasmage committed Apr 7, 2024
2 parents 198424e + e294deb commit c10eaf2
Show file tree
Hide file tree
Showing 80 changed files with 2,302 additions and 1,601 deletions.
18 changes: 13 additions & 5 deletions .github/workflows/automated-test.yml
Expand Up @@ -5,12 +5,17 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: ['7.4', '8.0', '8.1']
php-versions: ['8.1', '8.2', '8.3']
prefer-lowest: ['','--prefer-lowest']
name: PHP ${{ matrix.php-versions }} ${{ matrix.prefer-lowest }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: pngquant optipng
version: 1.0

- name: Setup PHP
uses: shivammathur/setup-php@v2
Expand All @@ -23,10 +28,10 @@ jobs:

- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: Cache dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php-version }}${{ matrix.prefer-lowest }}-composer-${{ hashFiles('**/composer.json') }}
Expand All @@ -38,13 +43,16 @@ jobs:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Run phpunit
run: vendor/bin/phpunit --coverage-clover build/logs/clover.xml -v
run: vendor/bin/phpunit --coverage-clover build/logs/clover.xml
env:
S3_KEY: ${{ secrets.S3_KEY }}
S3_SECRET: ${{ secrets.S3_SECRET }}
S3_REGION: ${{ secrets.S3_REGION }}
S3_BUCKET: ${{ secrets.S3_BUCKET }}

- name: Run PHPStan
run: vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=1G

- name: Upload coverage results to Coveralls
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,5 +4,6 @@ coverage/
.env
.idea/
.phpunit.result.cache
.phpunit.cache/
infection/
docs/build/
57 changes: 57 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,62 @@
# Changelog

## 6.0.0

### Compatibility
- Dropped support for PHP 7.4 and 8.0
- Dropped Support for Laravel 8 and 9
- Added Support for PHP 8.3
- Added Support for Laravel 11
- Added support for intervention/image 3.0
- Modernized the database migration files to use more recent Laravel conventions.

### Mediable

- Added `MediableInterface`

### MediaUploader

- Added support for recording alt attributes on Media (database migration required). MediaUploader now exposes a `withAltAttribute()` method to set the alt attribute on the generated media record.
- Added `MediaUploader::applyImageManipulation()` to make changes to the original uploaded image during the upload process.
- Added `MediaUploader::validateHash()` to ensure that the hash of the uploaded file matches a particular value during upload. Supports any hashing algorithm supported by PHP's `hash()` function.
- By default, the MediaUploader will always use the MIME type inferred from the file contents, regardless of the source. Added the `MediaUploader::preferClientMimeType()` to indicate that the MIME type provided by the source should be used instead, if provided. The default behaviour can be configured with the `'prefer_client_mime_type'` key in the `config/mediable.php` file.
- The `MediaUploader::useHashForFilename()` method now accepts an optional parameter to specify which hashing algorithm to use to generate the filename. Supports any hashing algorithm supported by PHP's `hash()` function.
- MediaUploader will now use the visibility defined on the filesystem disk config if the `makePublic()`/`makePrivate()` methods are not called, instead of assuming public visibility.
- MediaUploader now supports data URL strings as an input source, e.g. `data:image/jpeg;base64,...`.
- If a filename is not provided to the MediaUploader, and none can be inferred from the source, the uploader will throw an exception.
- If the file extension is not available from the source, the uploader will now consistently infer it from the MIME type. Previously this behaviour was inconsistent across different source adapters.

### SourceAdapters

All SourceAdapter classes have been significantly refactored.
- All sourceAdapters will now never load the entire file contents into memory (unless it is already in memory) to determine metadata about the file, in order to avoid memory exhaustion when dealing with large files. If reading the file is necessary, most adapters will attempt use a single streamed scan of the file to load all metadata at once, to speed up to the precess. Remote files will be cached to `temp://` to avoid repeated HTTP requests.
- Removed `getStreamResource()` method. The method has been replaced with the `getStream(): StreamInterface`, which returns a PSR-7 stream implementation instead.
- Added `hash(string $algo): string` method which is expected to return the hash of the file contents using the specified algorithm.
- The return type of the `filename()` and `extension()` method is now nullable. If the adapter cannot determine the value from the information available, it should return null.
- Removed the `getContents()` method. The `getStream()->getContents()` method may be used instead.
- Removed the `getSource()` method. No replacement.
- Removed the `path()` method. No replacement.
- Removed the `valid()` method. SourceAdapters should now throw an exception with a more helpful message from the constructor if the source is not valid.

### ImageManipulation

- Added support for optimizing manipulated images, using the [spatie/image-optimizer](https://github.com/spatie/image-optimizer/) package, which supports a variety of image optimization tools for different image formats (`jpegoptim`, `pngquant`, `optipng`, `gifsicle`, etc.)
- Default image optimization behaviour can configured in the `config/mediable.php` file to specify the optimization tools to use and their arguments.
- Added `ImageManipulation::noOptimization()` and `ImageManipulation::optimize(?array $optimizers = null)` methods to allow overriding the defaults set in the config file.
- The `ImageManipulation::useHashForFilename()` method now accepts an optional parameter to specify which hashing algorithm to use to generate the filename. Supports any hashing algorithm supported by PHP's `hash()` function.
- The `ImageManipulation::usingHashForFilename()` method has been renamed to `ImageManipulation::isUsingHashForFilename()` to avoid confusion with the `useHashForFilename()` method.

### Media
- Added `alt` attribute to the Media model.
- The Media class now exposes a dynamic `url` attribute which will generate a URL for the file (equivalent to the `getUrl()` method).

### Other
- Improved `MediableCollection` annotions to support generic types.
- Added missing type declarations to most property and method signatures.
- Removed the `\Plank\Mediable\Stream` class in favor of the `guzzlehttp/psr7` implementation. This removes the direct dependency on the `psr/http-message` library.
- `\Plank\Mediable\HandlesMediaUploadExceptions::transformMediaUploadException()` parameter and return type changed from `\Exception` to `\Throwable`.
- Added PHPStan static analysis to the test suite.

## 5.5.0 - 2022-05-09
- Filename and pathname sanitization will use the app locale when transliterating UTF-8 characters to ascii.
- Restored original behaviour of treating unrecognized mime types as `application/octet-stream` (changed in recent version of Flysystem)
Expand Down
30 changes: 30 additions & 0 deletions UPGRADING.md
@@ -1,5 +1,35 @@
# Upgrading

## 5.x to 6.x

* Minimum PHP version moved to 8.1
* Minimum Laravel version moved to 10
* New database migration file is included with the package. Run `php artisan migrate` to apply the changes.
* Add the `MediableInterface` to all models using the `Mediable` trait.
* To add support for data URLs to the MediaUploader, the following entry should be added to the `source_adapters.pattern` field in `config/mediable.php`
```php
'^data:/?/?[^,]*,' => Plank\Mediable\SourceAdapters\DataUrlAdapter::class,
```
* To specify default handling of inferred vs. client-provided MIME types, the following entry should be added to `config/mediable.php`. If `prefer_client_mime_type` is set to `true`, the MIME type provided by the client will be used when available. If set to `false`, the MIME type will always be inferred from the file contents. Defaults to `false`.
```php
'prefer_client_mime_type' => false,
```
* All properties now declare their types if able, and a handful of missing method return types have been added. If extending any class or implementing any interface from this package, property types may need to be updated.
* If you have implemented a custom SourceAdapter, you will need to apply the following changes from the `SourceAdapterInterface` interface:
* Implement the `getStream(): StreamInterface` method.
* Implement the `getHash(string $algo): string` method.
* he return type of the `filename()` and `extension()` method is now nullable. If the adapter cannot determine the value from the information available, it should return null.
* Remove the `getContents()` method. The `getStream()->getContents()` method may be used instead.
* Remove the `getSource()` method. No replacement.
* Remove the `path()` method. No replacement.
* Remove the `valid()` method. SourceAdapters should now throw an exception with a more helpful message from the constructor if the source is not valid.
* The `Plank\Mediable\Stream` class has been removed in favor of the `guzzlehttp/psr7` implementation. If you were using this class directly, you will need use another PSR-7 compatible stream wrapper instead (such as Guzzle's).
* To make use of the image optimization feature:
* Install the necessary binaries for the types of images that you are working with. See [spatie/image-optimizer documentation](https://github.com/spatie/image-optimizer/blob/main/README.md#optimization-tools) for installation instructions on various operating systems.
* add the `image_optimization.enabled` and `image_optimization.optimizers` configs to the `config/mediable.php` file. See the [sample configuration file](https://github.com/plank/laravel-mediable/blob/master/config/mediable.php) for a recommended baseline setup.
* The `ImageManipulation::usingHashForFilename()` method has been renamed to `ImageManipulation::isUsingHashForFilename()` to avoid confusion with the `useHashForFilename()` method.
* `\Plank\Mediable\HandlesMediaUploadExceptions::transformMediaUploadException()` parameter and return type changed from `\Exception` to `\Throwable`.

## 4.x to 5.x

* Database migration files are now served from within the package. In your migrations table, rename the `XXXX_XX_XX_XXXXXX_create_mediable_tables.php` entry to `2016_06_27_000000_create_mediable_tables.php` and delete your local copy of the migration file from the /database/migrations directory. If any customizations were made to the tables, those should be defined as one or more separate ALTER table migrations.
Expand Down
52 changes: 31 additions & 21 deletions composer.json
@@ -1,7 +1,13 @@
{
"name": "plank/laravel-mediable",
"description": "A package for easily uploading and attaching media files to models with Laravel",
"keywords": ["media", "image", "uploader", "eloquent", "laravel"],
"keywords": [
"media",
"image",
"uploader",
"eloquent",
"laravel"
],
"license": "MIT",
"authors": [
{
Expand All @@ -10,40 +16,44 @@
}
],
"require": {
"php": ">=7.4.0",
"php": ">=8.1.0",
"ext-fileinfo": "*",
"illuminate/support": "^8.83.3|^9.0|^10.0",
"illuminate/filesystem": "^8.83.3|^9.0|^10.0",
"illuminate/database": "^8.83.3|^9.0|^10.0",
"league/flysystem": "^1.1.9|^2.4.2|^3.0.4",
"psr/http-message": "^2.0",
"intervention/image": "^2.7.1",
"guzzlehttp/guzzle": "^6.5.5|^7.4.1",
"symfony/http-foundation": "^5.0.11|^6.0.3"

"guzzlehttp/guzzle": "^7.4.1",
"guzzlehttp/psr7": "^2.6",
"illuminate/database": "^10.0|^11.0",
"illuminate/filesystem": "^10.0|^11.0",
"illuminate/support": "^10.0|^11.0",
"intervention/image": "^2.7.1|^3.0",
"league/flysystem": "^3.0.4",
"symfony/http-foundation": "^6.0.3|^7.0",
"symfony/mime": "^6.0|^7.0",
"spatie/image-optimizer": "^1.7"
},
"require-dev": {
"orchestra/testbench": "^6.6|^7.0|^8.0",
"phpunit/phpunit": "^9.5.13",
"mockery/mockery": "^1.4.2",
"vlucas/phpdotenv": "^4.2.2|^5.4.1",
"guzzlehttp/promises": "^1.5.1",
"league/flysystem-aws-s3-v3" : "^1.0.29|^2.1.0|^3.0",
"aws/aws-sdk-php": "^3.166.2",
"php-coveralls/php-coveralls": "^2.5.2",
"doctrine/dbal": "^2.11|^3.0",
"guzzlehttp/promises": "^1.5.1",
"laravel/legacy-factories": "^1.3.0",
"doctrine/dbal": "^2.11|^3.0"
"league/flysystem-aws-s3-v3": "^3.0",
"mockery/mockery": "^1.4.2",
"orchestra/testbench": "^8.0|^9.0",
"php-coveralls/php-coveralls": "^2.5.2",
"phpunit/phpunit": "^10.0",
"vlucas/phpdotenv": "^5.4.1",
"phpstan/phpstan": "^1.10"
},
"autoload": {
"psr-4": {
"Plank\\Mediable\\": "src/"
}
},
"autoload-dev":{
"autoload-dev": {
"psr-4": {
"Plank\\Mediable\\Tests\\": "tests/"
},
"classmap": ["migrations/"]
"classmap": [
"migrations/"
]
},
"minimum-stability": "stable",
"prefer-stable": true,
Expand Down
60 changes: 59 additions & 1 deletion config/mediable.php
Expand Up @@ -61,6 +61,12 @@
*/
'allow_unrecognized_types' => false,

/**
* Prefer the client-provided MIME type over the one inferred from the file contents, if provided
* May be slightly faster to compute, but is not guaranteed to be accurate if the source is untrusted
*/
'prefer_client_mime_type' => false,

/*
* Only allow files with specific MIME type(s) to be uploaded
*/
Expand Down Expand Up @@ -213,7 +219,8 @@
'pattern' => [
'^https?://' => Plank\Mediable\SourceAdapters\RemoteUrlAdapter::class,
'^/' => Plank\Mediable\SourceAdapters\LocalPathAdapter::class,
'^[a-zA-Z]:\\\\' => Plank\Mediable\SourceAdapters\LocalPathAdapter::class
'^[a-zA-Z]:\\\\' => Plank\Mediable\SourceAdapters\LocalPathAdapter::class,
'^data:/?/?[^,]*,' => Plank\Mediable\SourceAdapters\DataUrlAdapter::class,
],
],

Expand Down Expand Up @@ -244,4 +251,55 @@
* Use this if you are renaming the published migrations and want to prevent them from being loaded twice.
*/
'ignore_migrations' => false,

/**
* Configuration for image optimization
*/
'image_optimization' => [
/**
* Whether to apply image optimization after performing image manipulations by default
*/
'enabled' => true,
/**
* array of optimizers to use, which should implement \Spatie\ImageOptimizer\Optimizer
* Each can be passed an array of command line arguments to be passed to the optimizer
*/
'optimizers' => [
\Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [
'--max=85',
'--strip-all',
'--all-progressive',
],
\Spatie\ImageOptimizer\Optimizers\Pngquant::class => [
'--quality=85',
'--force',
'--skip-if-larger',
],
\Spatie\ImageOptimizer\Optimizers\Optipng::class => [
'-i0',
'-o2',
'-quiet',
],
\Spatie\ImageOptimizer\Optimizers\Gifsicle::class => [
'-b',
'-O3',
],
\Spatie\ImageOptimizer\Optimizers\Cwebp::class => [
'-q 80',
'-m 6',
'-pass 10',
'-mt',
],
\Spatie\ImageOptimizer\Optimizers\Avifenc::class => [
'-a cq-level=23',
'-j all',
'--min 0',
'--max 63',
'--minalpha 0',
'--maxalpha 63',
'-a end-usage=q',
'-a tune=ssim',
],
],
]
];
48 changes: 48 additions & 0 deletions docs/source/installation.rst
Expand Up @@ -40,3 +40,51 @@ Run the migrations to add the required tables to your database.
::

$ php artisan migrate


Quickstart
-----------

Add the `Mediable` trait and `MediableInterface` interface to your eloquent models

::

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Plank\Mediable\Mediable;
use Plank\Mediable\MediableInterface;

class Post extends Model implements MediableInterface
{
use Mediable;

// ...
}

Upload files and convert them into `Media` records.

::

<?php
$media = MediaUploader::fromSource($request->file('thumbnail'))
->toDestination('s3', 'posts/thumbnails')
->upload();

Attach the records to your models.

::

<?php
$post = Post::find($postId);
$post->attachMedia($media, 'thumbnail');

Load and display your files

::

<?php
$post = Post::withMedia()->find($postId);
echo $post->getMedia('thumbnail')->first()->getUrl();
5 changes: 3 additions & 2 deletions docs/source/mediable.rst
Expand Up @@ -3,7 +3,7 @@ Handling Media

.. highlight:: php

Add the ``Mediable`` trait to any Eloquent models that you would like to be able to attach media to.
Add the ``Mediable`` trait and the `MediableInterface` interface to any Eloquent models that you would like to be able to attach media to.

::

Expand All @@ -13,8 +13,9 @@ Add the ``Mediable`` trait to any Eloquent models that you would like to be able

use Illuminate\Database\Eloquent\Model;
use Plank\Mediable\Mediable;
use Plank\Mediable\MediableInterface;

class Post extends Model
class Post extends Model implements MediableInterface
{
use Mediable;

Expand Down

0 comments on commit c10eaf2

Please sign in to comment.