Skip to content
Snippets Groups Projects
Commit 097dd4e4 authored by drobert's avatar drobert
Browse files

Issue #3437545 by DrDam, aurbain25: Rework derivativ folder organisation

parent 401b14e1
No related branches found
No related tags found
No related merge requests found
......@@ -19,3 +19,14 @@ function media_contextual_crop_update_10202() {
$file_system->deleteRecursive('public://media_contextual_crop');
$file_system->deleteRecursive('public://multi_crop_embed');
}
/**
* Flush contextual folders.
*/
function media_contextual_crop_update_10210() {
$file_system = \Drupal::service('file_system');
// Clean 2.0.x context folder.
$file_system->deleteRecursive('public://contextual');
}
......@@ -7,10 +7,8 @@
declare(strict_types=1);
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\crop\Entity\Crop;
use Drupal\image\Entity\ImageStyle;
// For all image_formater alteration & actions.
\Drupal::moduleHandler()->loadInclude('media_contextual_crop', 'alter_image_formater.inc');
......@@ -80,22 +78,7 @@ function media_contextual_crop_theme() {
* Deletes orphaned contexts when a Crop is deleted.
*/
function media_contextual_crop_crop_delete(Crop $crop) {
/** @var \Drupal\Core\File\FileSystem $file_system */
$file_system = \Drupal::service('file_system');
// Load all image styles used by the current crop type.
$image_style_ids = \Drupal::entityQuery('image_style')
->condition('effects.*.data.crop_type', $crop->bundle())
->accessCheck(TRUE)
->execute();
$image_styles = ImageStyle::loadMultiple($image_style_ids);
// For each image style, delete all possible derivatives location.
foreach ($image_styles as $style) {
$folder_uri = 'public://contextual/styles/' . $style->id() . '/' . $crop->id();
$file_system->deleteRecursive($folder_uri);
}
\Drupal::service('media_contextual_crop.service')->deleteDerivative($crop);
}
/**
......
......@@ -15,6 +15,7 @@ use Drupal\Core\File\FileUrlGenerator;
use Drupal\Core\Routing\RequestHelper;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\Core\Url;
use Drupal\crop\Entity\Crop;
use Drupal\image\Entity\ImageStyle;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\HttpFoundation\RequestStack;
......@@ -173,8 +174,15 @@ class MediaContextualCropService {
$target = $this->streamWrapperManager::getTarget($old_image_uri);
$source_scheme = $scheme = $this->streamWrapperManager::getScheme($old_image_uri);
// Calculate new extension.
$original_extension = pathinfo($target, PATHINFO_EXTENSION);
$new_extension = $style->getDerivativeExtension($original_extension);
// Slice old extension from target.
$target_as_folder = str_replace('.' . $original_extension, '', $target);
// Create new URI.
$path = $scheme . '://contextual/styles/' . $image_style . '/' . $crop_id . '/' . $source_scheme . '/' . $this->addExtension($target, $style);
$path = $scheme . '://contextual/styles/' . $image_style . '/' . $source_scheme . '/' . $target_as_folder . '/' . $crop_id . '.' . $new_extension;
$uri = $this->streamWrapperManager->normalizeUri($path);
// If derivative image exist, delete it.
......@@ -237,33 +245,6 @@ class MediaContextualCropService {
}
/**
* Adds an extension to a path.
*
* If this image style changes the extension of the derivative, this method
* adds the new extension to the given path. This way we avoid filename
* clashes while still allowing us to find the source image.
*
* @param string $path
* The path to add the extension to.
* @param \Drupal\image\Entity\ImageStyle $style
* The image style used.
*
* @return string
* The given path if this image style doesn't change its extension, or the
* path with the added extension if it does.
*
* @see: ImageStyle::addExtension()
*/
private function addExtension($path, ImageStyle $style) {
$original_extension = pathinfo($path, PATHINFO_EXTENSION);
$extension = $style->getDerivativeExtension($original_extension);
if ($original_extension !== $extension) {
$path .= '.' . $extension;
}
return $path;
}
/**
* Check if style use a crop manage by MCC.
*
......@@ -328,6 +309,35 @@ class MediaContextualCropService {
$this->fileSystem->deleteRecursive($folder_uri);
}
/**
* Flush all derivativ generate from one crop.
*
* @param \Drupal\crop\Entity\Crop $crop
* Crop deleted.
*/
public function deleteDerivative(Crop $crop) {
// Load all image styles used by the current crop type.
$image_style_ids = $this->entityTypeManager->getStorage('image_style')
->getQuery()
->condition('effects.*.data.crop_type', $crop->bundle())
->accessCheck(TRUE)
->execute();
// For each image style.
foreach ($image_style_ids as $style_id) {
// Generate attented derivative path for this crop.
$uri = $this->createContextualizedDerivativePath($crop->uri->getString(), $style_id, $crop->id(), TRUE);
// If derivative exists.
$real_path = $this->fileSystem->realpath($uri);
if (file_exists($real_path)) {
// Delete it.
unlink($real_path);
}
}
}
/**
* Recover crops from an entity.
*
......
......@@ -7,6 +7,7 @@ use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\crop\CropInterface;
use Drupal\image\PathProcessor\PathProcessorImageStyles as BaseFromImage;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Defines a path processor to rewrite contextualized image styles URLs.
......@@ -58,22 +59,44 @@ class PathProcessorImageStyles extends BaseFromImage {
$rest = preg_replace('|^' . preg_quote($path_prefix, '|') . '|', '', $path);
// Get the image style, scheme and path.
if (substr_count($rest, '/') >= 4) {
[$style_separator, $image_style, $context, $scheme, $file] = explode('/', $rest, 5);
if (substr_count($rest, '/') >= 5) {
// Set the file as query parameter.
// Needed for private files.
$request->query->set('file', $file);
return $path_prefix . $style_separator . '/' . $image_style . '/' . $context . '/' . $scheme;
}
// Set file query parameter if its still missing from the crop ID.
if (substr_count($rest, '/') == 3 && !$request->query->get('file')) {
[$style_separator, $image_style, $crop_id, $scheme] = explode('/', $rest, 4);
$exploded_path = explode('/', $rest);
/*
* $exploded_path[0] = "styles"
* $exploded_path[1] = style_name
* $exploded_path[2] = scheme (ex : "public")
* $exploded_path[3] -> [n-1] => file_path
* $exploded_path[n] = crop_id '.' extension
*/
$crop_extension = array_pop($exploded_path);
[$crop_id, $extension] = explode('.', $crop_extension);
unset($extension);
// Reconstruct orignal image path.
$original_image_path = implode('/', array_slice($exploded_path, 3));
$original_image_path = $exploded_path[2] . '://' . $original_image_path;
// Load crop.
$crop = $this->entityTypeManager->getStorage('crop')->load($crop_id);
if ($crop instanceof CropInterface) {
$request->query->set('file', $crop->uri->value);
$crop_uri = $crop->uri->value;
// Ensure Crop Target and Requested Image are the same.
$path_parts = pathinfo($crop_uri);
$crop_target_filename = $path_parts['dirname'] . '/' . $path_parts['filename'];
if ($original_image_path != $crop_target_filename) {
throw new NotFoundHttpException();
}
// Push Source image to request, in order validate private DL.
$request->query->set('file', $crop_uri);
}
// Set URL for controller.
$url = $path_prefix . 'styles/' . $exploded_path[1] . '/' . $crop_id . '/' . $exploded_path[2];
return $url;
}
return $path;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment