5 * The Crop API Drupal module.
7 * Provides storage and API for image crops.
10 use \Drupal\Core\Form\FormStateInterface;
11 use Drupal\Core\StreamWrapper\PublicStream;
12 use Drupal\crop\Entity\Crop;
13 use Drupal\image\Entity\ImageStyle;
14 use \Drupal\media_entity\MediaBundleInterface;
15 use \Drupal\file\FileInterface;
18 * Implements hook_theme().
20 function crop_theme() {
22 'crop_crop_summary' => [
23 'variables' => ['data' => [], 'effect' => []],
29 * Prepares variables for crop_crop summary template.
31 * Default template: crop-crop-summary.twig.html.
33 function template_preprocess_crop_crop_summary(&$variables) {
34 if (!empty($variables['data']['crop_type'])) {
35 $type = \Drupal::entityTypeManager()->getStorage('crop_type')->load($variables['data']['crop_type']);
36 $variables['data']['crop_type'] = $type->label();
41 * Implements hook_form_BASE_ID_alter().
43 * Adds crop configuraiton fields to media bundle form.
45 function crop_form_media_bundle_form_alter(&$form, FormStateInterface $form_state, $form_id) {
46 /** @var \Drupal\media_entity\MediaBundleInterface $bundle */
47 $bundle = $form['#entity'];
49 $allowed_field_types = ['file', 'image'];
50 foreach (\Drupal::service('entity_field.manager')->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) {
51 if (in_array($field->getType(), $allowed_field_types) && !$field->getFieldStorageDefinition()->isBaseField()) {
52 $options[$field_name] = $field->getLabel();
56 $form['#entity_builders'][] = 'crop_media_bundle_form_builder';
58 '#type' => 'fieldset',
59 '#title' => t('Crop configuration'),
62 if (empty($options)) {
63 $form['crop']['image_field'] = [
68 $form['crop']['message'] = [
69 '#markup' => t('There are no file or image fields on this bundle at the moment. In order to configure crop add at least one such field and come back.'),
75 $form['crop']['image_field'] = [
77 '#title' => t('Image field'),
78 '#default_value' => $bundle->getThirdPartySetting('crop', 'image_field'),
79 '#options' => $options,
80 '#description' => t('Select field that stores image which needs to be cropped.'),
86 * Entity builder for Media bundle.
88 * Adds third party settings to Media bundle config entity.
90 * @see crop_form_media_bundle_form_alter()
92 function crop_media_bundle_form_builder($entity_type, MediaBundleInterface $bundle, &$form, FormStateInterface $form_state) {
93 $bundle->setThirdPartySetting('crop', 'image_field', $form_state->getValue('image_field'));
97 * Implements hook_ENTITY_TYPE_delete().
99 * Deletes orphaned crops when a file is deleted.
101 function crop_file_delete(FileInterface $file) {
102 // Get all crops for the file being deleted.
103 $crops = \Drupal::entityTypeManager()
105 ->loadByProperties(['uri' => $file->getFileUri()]);
107 foreach ($crops as $crop) {
113 * Implements hook_file_url_alter().
115 function crop_file_url_alter(&$uri) {
116 // Process only files that are stored in "styles" directory.
117 if (strpos($uri, PublicStream::basePath() . '/styles/') !== FALSE) {
118 // Handle the case of multiple "/styles/" in URI.
119 $uri_parts = explode('/styles/', $uri);
120 $image_style_part = end($uri_parts);
121 // Match image style, schema, file subdirectory and file name.
122 preg_match("/(.*?)\/(.*?)\/(.*+)/", $image_style_part, $match);
123 // Get the image style ID.
124 $image_style = $match[1];
125 // Get the file path without query parameter.
126 $parsed_uri = parse_url($match[3]);
127 // Get the file URI using parsed schema and file path.
128 $file_uri = $match[2] . '://' . $parsed_uri['path'];
130 /** @var \Drupal\image\Entity\ImageStyle $image_style */
131 if (!$image_style = ImageStyle::load($image_style)) {
136 // Find whether matched image style uses "crop_type" effect.
137 /* @var \Drupal\image\ImageEffectInterface $effect */
138 foreach ($image_style->getEffects() as $uuid => $effect) {
139 $data_effect = $image_style->getEffect($uuid)->getConfiguration()['data'];
140 if (isset($data_effect['crop_type'])) {
141 $crop_type = $data_effect['crop_type'];
146 // In case the image style uses "crop_type" effect, load the crop entity.
147 if ($crop_type && $crop = Crop::findCrop($file_uri, $crop_type)) {
148 // Found a crop for this image, append a hash of it to the URL,
149 // so that browsers reload the image and CDNs and proxies can be bypassed.
150 $shortened_hash = substr(md5(implode($crop->position()) . implode($crop->anchor())), 0, 8);
151 $uri .= '&h=' . $shortened_hash;