18e19853bed7956e9c41078a3803f3ef7e2aa59d
[yaffs-website] / web / modules / contrib / crop / crop.module
1 <?php
2
3 /**
4  * @file
5  * The Crop API Drupal module.
6  *
7  * Provides storage and API for image crops.
8  */
9 use Drupal\Component\Utility\UrlHelper;
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\MediaType;
15 use Drupal\media\MediaTypeInterface;
16 use Drupal\media_entity\MediaBundleInterface;
17 use Drupal\file\FileInterface;
18
19 /**
20  * Implements hook_theme().
21  */
22 function crop_theme() {
23   return [
24     'crop_crop_summary' => [
25       'variables' => ['data' => [], 'effect' => []],
26     ],
27   ];
28 }
29
30 /**
31  * Prepares variables for crop_crop summary template.
32  *
33  * Default template: crop-crop-summary.twig.html.
34  */
35 function template_preprocess_crop_crop_summary(&$variables) {
36   if (!empty($variables['data']['crop_type'])) {
37     $type = \Drupal::entityTypeManager()->getStorage('crop_type')->load($variables['data']['crop_type']);
38     $variables['data']['crop_type'] = $type->label();
39   }
40 }
41
42 /**
43  * Implements hook_form_FORM_ID_alter().
44  *
45  * Adds crop configuration fields to media type form.
46  */
47 function crop_form_media_type_edit_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
48   _crop_media_provider_form($form, $form_state);
49 }
50
51 /**
52  * Implements hook_form_FORM_ID_alter().
53  *
54  * Adds crop configuration fields to media bundle form.
55  */
56 function crop_form_media_bundle_edit_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
57   _crop_media_provider_form($form, $form_state);
58 }
59
60 /**
61  * Helper function to avoid uneeded code duplication.
62  *
63  * @todo Delete this and media entity fallback when media is stable.
64  */
65 function _crop_media_provider_form(array &$form, FormStateInterface $form_state) {
66   /** @var \Drupal\Core\Config\Entity\ConfigEntityBundleBase $entity_type */
67   $entity_type = $form_state->getFormObject()->getEntity();
68   $options = [];
69   $allowed_field_types = ['file', 'image'];
70
71   /** @var \Drupal\Core\Field\FieldDefinitionInterface[] $fields */
72   $fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('media', $entity_type->id());
73   foreach ($fields as $field_name => $field) {
74     if (in_array($field->getType(), $allowed_field_types) && !$field->getFieldStorageDefinition()->isBaseField()) {
75       $options[$field_name] = $field->getLabel();
76     }
77   }
78
79   // Maintain compatibility with Media Entity.
80   if ($entity_type instanceof MediaType) {
81     $form['#entity_builders'][] = 'crop_media_type_form_builder';
82   }
83   else {
84     $form['#entity_builders'][] = 'crop_media_bundle_form_builder';
85   }
86
87   $form['crop'] = [
88     '#type' => 'fieldset',
89     '#title' => t('Crop configuration'),
90     '#group' => 'source_dependent',
91   ];
92
93   if (empty($options)) {
94     $form['crop']['image_field'] = [
95       '#type' => 'value',
96       '#value' => NULL,
97     ];
98
99     $form['crop']['message'] = [
100       '#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.'),
101     ];
102
103     return;
104   }
105
106   $form['crop']['image_field'] = [
107     '#type' => 'select',
108     '#title' => t('Image field'),
109     '#default_value' => $entity_type->getThirdPartySetting('crop', 'image_field'),
110     '#options' => $options,
111     '#empty_option' => t('- Skip field -'),
112     '#empty_value' => '_none',
113     '#description' => t('Select field that stores image which needs to be cropped.'),
114   ];
115
116   return $form;
117 }
118
119 /**
120  * Entity builder for Media bundle.
121  *
122  * Adds third party settings to Media bundle config entity.
123  *
124  * @see crop_form_media_bundle_form_alter()
125  */
126 function crop_media_bundle_form_builder($entity_type, MediaBundleInterface $bundle, &$form, FormStateInterface $form_state) {
127   $bundle->setThirdPartySetting('crop', 'image_field', $form_state->getValue('image_field'));
128 }
129
130 /**
131  * Entity builder for Media type.
132  *
133  * Adds third party settings to Media type config entity.
134  *
135  * @see crop_form_media_type_edit_form_alter()
136  */
137 function crop_media_type_form_builder($entity_type, MediaTypeInterface $bundle, array &$form, FormStateInterface $form_state) {
138   $bundle->setThirdPartySetting('crop', 'image_field', $form_state->getValue('image_field'));
139 }
140
141 /**
142  * Implements hook_ENTITY_TYPE_delete().
143  *
144  * Deletes orphaned crops when a file is deleted.
145  */
146 function crop_file_delete(FileInterface $file) {
147   // Get all crops for the file being deleted.
148   $crops = \Drupal::entityTypeManager()
149     ->getStorage('crop')
150     ->loadByProperties(['uri' => $file->getFileUri()]);
151
152   foreach ($crops as $crop) {
153     $crop->delete();
154   }
155 }
156
157 /**
158  * Implements hook_file_url_alter().
159  */
160 function crop_file_url_alter(&$uri) {
161   // Process only files that are stored in "styles" directory.
162   if (strpos($uri, '/styles/') !== FALSE && preg_match('/\/styles\/(.*?)\/(.*?)\/(.+)/', $uri, $match)) {
163     // Match image style, schema, file subdirectory and file name.
164     // Get the image style ID.
165     $image_style = $match[1];
166     // Get the file path without query parameter.
167     $parsed_uri = UrlHelper::parse($match[3]);
168     // Get the file URI using parsed schema and file path.
169     $file_uri = $match[2] . '://' . $parsed_uri['path'];
170
171     // Prevent double hashing, if there is a hash argument already, do not add
172     // it again.
173     if (!empty($parsed_uri['query']['h'])) {
174       return;
175     }
176
177     /** @var \Drupal\image\Entity\ImageStyle $image_style */
178     if (!$image_style = ImageStyle::load($image_style)) {
179       return;
180     }
181
182     if ($crop = Crop::getCropFromImageStyle($file_uri, $image_style)) {
183       // Found a crop for this image, append a hash of it to the URL,
184       // so that browsers reload the image and CDNs and proxies can be bypassed.
185       $shortened_hash = substr(md5(implode($crop->position()) . implode($crop->anchor())), 0, 8);
186
187       // If the URI has a schema and that is not http, https or data, convert
188       // the URI to the external URL. Otherwise the appended query argument
189       // will be encoded.
190       // @see file_create_url()
191       $scheme = \Drupal::service('file_system')->uriScheme($uri);
192       if ($scheme && !in_array($scheme, ['http', 'https', 'data'])) {
193         if ($wrapper = \Drupal::service('stream_wrapper_manager')->getViaUri($uri)) {
194           $uri = $wrapper->getExternalUrl();
195         }
196       }
197
198       // Append either with a ? or a & if there are existing query arguments.
199       if (strpos($uri, '?') === FALSE) {
200         $uri .= '?h=' . $shortened_hash;
201       }
202       else {
203         $uri .= '&h=' . $shortened_hash;
204       }
205     }
206   }
207 }