Skip to content
This repository was archived by the owner on Jan 19, 2023. It is now read-only.

Collection support #12

Draft
wants to merge 6 commits into
base: next
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "ziffdavis/laravel-eloquent-imagery",
"description": "Image handling per column/attribute for Laravel Eloquent",
"type": "library",
"authors": [
{
@@ -11,7 +12,7 @@
"php": "^7.1"
},
"require-dev": {
"laravel/laravel": "^5.6.0",
"orchestra/testbench": "^3.8",
"intervention/image": "^2.4",
"phpunit/phpunit": "^7.1"
},
1 change: 1 addition & 0 deletions src/Controller/EloquentImageryController.php
Original file line number Diff line number Diff line change
@@ -98,6 +98,7 @@ public function render($path)

// step 3: no placeholder, no primary FS image, look for fallback image on alternative filesystem if enabled
if (!$imageBytes && config('eloquent-imagery.render.fallback.enable')) {
/** @var Filesystem $fallbackFilesystem */
$fallbackFilesystem = app(FilesystemManager::class)->disk(config('eloquent-imagery.render.fallback.filesystem'));
try {
$imageBytes = $fallbackFilesystem->get($storagePath);
85 changes: 52 additions & 33 deletions src/Eloquent/EloquentImageryObserver.php
Original file line number Diff line number Diff line change
@@ -5,109 +5,125 @@
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use ReflectionProperty;
use RuntimeException;

class EloquentImageryObserver
{
protected $attributeReflector = null;
/** @var ReflectionProperty */
protected $eloquentImageryImagesReflector;

public function __construct()
/** @var ReflectionProperty */
protected $attributesReflector;

/**
* EloquentImageryObserver constructor.
* @param $modelClassToObserve
* @throws \ReflectionException
*/
public function __construct($modelClassToObserve)
{
$this->attributeReflector = new ReflectionProperty(Model::class, 'attributes');
$this->attributeReflector->setAccessible(true);
$this->eloquentImageryImagesReflector = new ReflectionProperty($modelClassToObserve, 'eloquentImageryImages');
$this->eloquentImageryImagesReflector->setAccessible(true);

$this->attributesReflector = new ReflectionProperty($modelClassToObserve, 'attributes');
$this->attributesReflector->setAccessible(true);
}

/**
* @param \Illuminate\Database\Eloquent\Model|\ZiffDavis\Laravel\EloquentImagery\Eloquent\HasEloquentImagery $model
*/
public function retrieved(Model $model)
{
$attributeImages = $model->getEloquentImageryImages();
/** @var Image[]|ImageCollection[] $eloquentImageryImages */
$eloquentImageryImages = $this->eloquentImageryImagesReflector->getValue($model);

$modelAttributes = $this->attributeReflector->getValue($model);
$modelAttributes = $this->attributesReflector->getValue($model);

foreach ($attributeImages as $attribute => $image) {
foreach ($eloquentImageryImages as $attribute => $image) {
// in the case a model was retrieved and the image column was not returned
if (!array_key_exists($attribute, $modelAttributes)) {
continue;
}

$properties = $modelAttributes[$attribute];
$attributeData = $modelAttributes[$attribute];
$modelAttributes[$attribute] = $image;

if ($properties == '') {
if ($attributeData == '') {
continue;
}

if (is_string($properties)) {
$properties = json_decode($properties, true);
if (is_string($attributeData)) {
$attributeData = json_decode($attributeData, true);
}

$image->setStateProperties($properties);
$image->setStateFromAttributeData($attributeData);
}

$this->attributeReflector->setValue($model, $modelAttributes);
$this->attributesReflector->setValue($model, $modelAttributes);
}

/**
* @param \Illuminate\Database\Eloquent\Model|\ZiffDavis\Laravel\EloquentImagery\Eloquent\HasEloquentImagery $model
*/
public function saving(Model $model)
{
$attributeImages = $model->getEloquentImageryImages();
/** @var Image[]|ImageCollection[] $eloquentImageryImages */
$eloquentImageryImages = $this->eloquentImageryImagesReflector->getValue($model);

$casts = $model->getCasts();

$modelAttributes = $this->attributeReflector->getValue($model);
$modelAttributes = $this->attributesReflector->getValue($model);

foreach ($attributeImages as $attribute => $image) {
foreach ($eloquentImageryImages as $attribute => $image) {
if ($image->pathHasReplacements()) {
$image->updatePath($model);
$image->updatePath([], $model);
}

if ($image instanceof ImageCollection) {
$image->purgeRemovedImages();
}

if (!$image->exists()) {
} elseif ($image instanceof Image && !$image->exists()) {
$modelAttributes[$attribute] = null;
continue;
}

$imageState = $image->getStateProperties();
$attributeData = $image->getStateAsAttributeData();

$value = (isset($casts[$attribute]) && $casts[$attribute] === 'json')
? $imageState
: json_encode($imageState);
? $attributeData
: json_encode($attributeData);

$modelAttributes[$attribute] = $value;
}

$this->attributeReflector->setValue($model, $modelAttributes);
$this->attributesReflector->setValue($model, $modelAttributes);
}

/**
* @param \Illuminate\Database\Eloquent\Model|\ZiffDavis\Laravel\EloquentImagery\Eloquent\HasEloquentImagery $model
*/
public function saved(Model $model)
{
$attributeImages = $model->getEloquentImageryImages();
/** @var Image[]|ImageCollection[] $eloquentImageryImages */
$eloquentImageryImages = $this->eloquentImageryImagesReflector->getValue($model);

$casts = $model->getCasts();

$errors = [];

$modelAttributes = $this->attributeReflector->getValue($model);
$modelAttributes = $this->attributesReflector->getValue($model);

foreach ($attributeImages as $attribute => $image) {
foreach ($eloquentImageryImages as $attribute => $image) {
if ($image->pathHasReplacements()) {

$image->updatePath($model);
$image->updatePath([], $model);

if ($image->pathHasReplacements()) {
$errors[] = "After saving row, image for attribute {$attribute}'s path still contains unresolvable path replacements";
}

$imageState = $image->getStateProperties();
$imageState = $image->getStateAsAttributeData();

$value = (isset($this->casts[$attribute]) && $this->casts[$attribute] === 'json')
$value = (isset($casts[$attribute]) && $casts[$attribute] === 'json')
? $imageState
: json_encode($imageState);

@@ -121,10 +137,10 @@ public function saved(Model $model)
$modelAttributes[$attribute] = $image;
}

$this->attributeReflector->setValue($model, $modelAttributes);
$this->attributesReflector->setValue($model, $modelAttributes);

if ($errors) {
throw new \RuntimeException(implode('; ', $errors));
throw new RuntimeException(implode('; ', $errors));
}
}

@@ -137,7 +153,10 @@ public function deleted(Model $model)
return;
}

foreach ($model->getEloquentImageryImages() as $image) {
/** @var Image[]|ImageCollection[] $eloquentImageryImages */
$eloquentImageryImages = $this->eloquentImageryImagesReflector->getValue($model);

foreach ($eloquentImageryImages as $image) {
if ($image->exists()) {
$image->remove();
$image->flush();
61 changes: 23 additions & 38 deletions src/Eloquent/HasEloquentImagery.php
Original file line number Diff line number Diff line change
@@ -2,78 +2,63 @@

namespace ZiffDavis\Laravel\EloquentImagery\Eloquent;

use Illuminate\Support\Str;
use Illuminate\Filesystem\FilesystemManager;
use RuntimeException;

/**
* @mixin \Illuminate\Database\Eloquent\Model
*/
trait HasEloquentImagery
{
/** @var Image[] */
/** @var Image[]|ImageCollection[] */
protected static $eloquentImageryPrototypes = [];

/** @var Image[]|ImageCollection[] */
protected $eloquentImageryImages = [];

public static function bootHasEloquentImagery()
{
static::observe(new EloquentImageryObserver());
$observer = new EloquentImageryObserver(get_called_class());

// register directly so that the instance is preserved (not preserved via static::observe())
static::registerModelEvent('retrieved', [$observer, 'retrieved']);
static::registerModelEvent('saving', [$observer, 'saving']);
static::registerModelEvent('saved', [$observer, 'saved']);
static::registerModelEvent('deleted', [$observer, 'deleted']);
}

public function initializeHasEloquentImagery()
{
if (!empty($this->eloquentImageryImages)) {
throw new \RuntimeException('$eloquentImageryImages should be empty, are you sure you have your configuration in the right place?');
throw new RuntimeException('$eloquentImageryImages should be empty, are you sure you have your configuration in the right place?');
}

if (empty($this->eloquentImagery) || !property_exists($this, 'eloquentImagery')) {
throw new \RuntimeException('You are using ' . __TRAIT__ . ' but have not yet configured it through $eloquentImagery, please see the docs');
throw new RuntimeException('You are using ' . __TRAIT__ . ' but have not yet configured it through $eloquentImagery, please see the docs');
}

foreach ($this->eloquentImagery as $attribute => $config) {
if (is_string($config)) {
$config = ['path' => $config];
}

if (isset($config['collection']) && $config['collection'] === true) {
$this->eloquentImageryCollection($attribute, $config['path']);
} else {
$this->eloquentImagery($attribute, $config['path']);
if (!is_array($config)) {
throw new RuntimeException('configuration must be a string or array');
}
}
}

public function eloquentImagery($attribute, $path = null)
{
$this->eloquentImageryInitializeImage(Image::class, $attribute, $path);
}
if (!isset(static::$eloquentImageryPrototypes[$attribute])) {
$prototype = new Image($config['path']);

public function eloquentImageryCollection($attribute, $path = null)
{
$this->eloquentImageryInitializeImage(ImageCollection::class, $attribute, $path);
}
if (isset($config['collection']) && $config['collection'] === true) {
$prototype = new ImageCollection($prototype);
}

protected function eloquentImageryInitializeImage($class, $attribute, $path)
{
if (!isset(static::$eloquentImageryPrototypes[$attribute])) {
if (!$path) {
$path = ($class === ImageCollection::class)
? Str::singular($this->getTable()) . '/{' . $this->getKeyName() . "}/{$attribute}-{index}.{extension}"
: Str::singular($this->getTable()) . '/{' . $this->getKeyName() . "}/{$attribute}.{extension}";
static::$eloquentImageryPrototypes[$attribute] = $prototype;
} else {
$prototype = static::$eloquentImageryPrototypes[$attribute];
}

static::$eloquentImageryPrototypes[$attribute] = new $class($attribute, $path);
$this->attributes[$attribute] = $this->eloquentImageryImages[$attribute] = clone $prototype;
}

// set the image as the attribute so that it can be accessed on new instances via attribute accessor
$this->eloquentImageryImages[$attribute] = $this->attributes[$attribute] = clone static::$eloquentImageryPrototypes[$attribute];
}

/**
* @return Image[]|ImageCollection[]
*/
public function getEloquentImageryImages()
{
return $this->eloquentImageryImages;
}
}
Loading