Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\image\Controller;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Core\Cache\CacheableJsonResponse;
|
Chris@0
|
6 use Drupal\Core\Controller\ControllerBase;
|
Chris@0
|
7 use Drupal\Core\Entity\ContentEntityInterface;
|
Chris@18
|
8 use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
|
Chris@0
|
9 use Drupal\Core\Entity\EntityInterface;
|
Chris@18
|
10 use Drupal\Core\File\FileSystemInterface;
|
Chris@0
|
11 use Drupal\Core\Image\ImageFactory;
|
Chris@0
|
12 use Drupal\Core\Render\Element\StatusMessages;
|
Chris@0
|
13 use Drupal\Core\Render\RendererInterface;
|
Chris@0
|
14 use Drupal\image\Plugin\Field\FieldType\ImageItem;
|
Chris@14
|
15 use Drupal\Core\TempStore\PrivateTempStoreFactory;
|
Chris@0
|
16 use Symfony\Component\DependencyInjection\ContainerInterface;
|
Chris@0
|
17 use Symfony\Component\HttpFoundation\JsonResponse;
|
Chris@0
|
18 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
Chris@0
|
19
|
Chris@0
|
20 /**
|
Chris@0
|
21 * Returns responses for our image routes.
|
Chris@0
|
22 */
|
Chris@0
|
23 class QuickEditImageController extends ControllerBase {
|
Chris@0
|
24
|
Chris@0
|
25 /**
|
Chris@0
|
26 * Stores The Quick Edit tempstore.
|
Chris@0
|
27 *
|
Chris@14
|
28 * @var \Drupal\Core\TempStore\PrivateTempStore
|
Chris@0
|
29 */
|
Chris@0
|
30 protected $tempStore;
|
Chris@0
|
31
|
Chris@0
|
32 /**
|
Chris@0
|
33 * The renderer.
|
Chris@0
|
34 *
|
Chris@0
|
35 * @var \Drupal\Core\Render\RendererInterface
|
Chris@0
|
36 */
|
Chris@0
|
37 protected $renderer;
|
Chris@0
|
38
|
Chris@0
|
39 /**
|
Chris@0
|
40 * The image factory.
|
Chris@0
|
41 *
|
Chris@0
|
42 * @var \Drupal\Core\Image\ImageFactory
|
Chris@0
|
43 */
|
Chris@0
|
44 protected $imageFactory;
|
Chris@0
|
45
|
Chris@0
|
46 /**
|
Chris@18
|
47 * The entity display repository service.
|
Chris@18
|
48 *
|
Chris@18
|
49 * @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
|
Chris@18
|
50 */
|
Chris@18
|
51 protected $entityDisplayRepository;
|
Chris@18
|
52
|
Chris@18
|
53 /**
|
Chris@18
|
54 * The file system.
|
Chris@18
|
55 *
|
Chris@18
|
56 * @var \Drupal\Core\File\FileSystemInterface
|
Chris@18
|
57 */
|
Chris@18
|
58 protected $fileSystem;
|
Chris@18
|
59
|
Chris@18
|
60 /**
|
Chris@0
|
61 * Constructs a new QuickEditImageController.
|
Chris@0
|
62 *
|
Chris@0
|
63 * @param \Drupal\Core\Render\RendererInterface $renderer
|
Chris@0
|
64 * The renderer.
|
Chris@0
|
65 * @param \Drupal\Core\Image\ImageFactory $image_factory
|
Chris@0
|
66 * The image factory.
|
Chris@14
|
67 * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
|
Chris@0
|
68 * The tempstore factory.
|
Chris@18
|
69 * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
|
Chris@18
|
70 * The entity display repository service.
|
Chris@18
|
71 * @param \Drupal\Core\File\FileSystemInterface $file_system
|
Chris@18
|
72 * The file system.
|
Chris@0
|
73 */
|
Chris@18
|
74 public function __construct(RendererInterface $renderer, ImageFactory $image_factory, PrivateTempStoreFactory $temp_store_factory, EntityDisplayRepositoryInterface $entity_display_repository = NULL, FileSystemInterface $file_system = NULL) {
|
Chris@0
|
75 $this->renderer = $renderer;
|
Chris@0
|
76 $this->imageFactory = $image_factory;
|
Chris@0
|
77 $this->tempStore = $temp_store_factory->get('quickedit');
|
Chris@18
|
78 if (!$entity_display_repository) {
|
Chris@18
|
79 @trigger_error('The entity_display.repository service must be passed to QuickEditImageController::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
|
Chris@18
|
80 $entity_display_repository = \Drupal::service('entity_display.repository');
|
Chris@18
|
81 }
|
Chris@18
|
82 $this->entityDisplayRepository = $entity_display_repository;
|
Chris@18
|
83 if (!$file_system) {
|
Chris@18
|
84 @trigger_error('The file_system service must be passed to QuickEditImageController::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
|
Chris@18
|
85 $file_system = \Drupal::service('file_system');
|
Chris@18
|
86 }
|
Chris@18
|
87 $this->fileSystem = $file_system;
|
Chris@0
|
88 }
|
Chris@0
|
89
|
Chris@0
|
90 /**
|
Chris@0
|
91 * {@inheritdoc}
|
Chris@0
|
92 */
|
Chris@0
|
93 public static function create(ContainerInterface $container) {
|
Chris@0
|
94 return new static(
|
Chris@0
|
95 $container->get('renderer'),
|
Chris@0
|
96 $container->get('image.factory'),
|
Chris@18
|
97 $container->get('tempstore.private'),
|
Chris@18
|
98 $container->get('entity_display.repository'),
|
Chris@18
|
99 $container->get('file_system')
|
Chris@0
|
100 );
|
Chris@0
|
101 }
|
Chris@0
|
102
|
Chris@0
|
103 /**
|
Chris@0
|
104 * Returns JSON representing the new file upload, or validation errors.
|
Chris@0
|
105 *
|
Chris@0
|
106 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
107 * The entity of which an image field is being rendered.
|
Chris@0
|
108 * @param string $field_name
|
Chris@0
|
109 * The name of the (image) field that is being rendered
|
Chris@0
|
110 * @param string $langcode
|
Chris@0
|
111 * The language code of the field that is being rendered.
|
Chris@0
|
112 * @param string $view_mode_id
|
Chris@0
|
113 * The view mode of the field that is being rendered.
|
Chris@0
|
114 *
|
Chris@0
|
115 * @return \Symfony\Component\HttpFoundation\JsonResponse
|
Chris@0
|
116 * The JSON response.
|
Chris@0
|
117 */
|
Chris@0
|
118 public function upload(EntityInterface $entity, $field_name, $langcode, $view_mode_id) {
|
Chris@0
|
119 $field = $this->getField($entity, $field_name, $langcode);
|
Chris@0
|
120 $field_validators = $field->getUploadValidators();
|
Chris@0
|
121 $field_settings = $field->getFieldDefinition()->getSettings();
|
Chris@0
|
122 $destination = $field->getUploadLocation();
|
Chris@0
|
123
|
Chris@0
|
124 // Add upload resolution validation.
|
Chris@0
|
125 if ($field_settings['max_resolution'] || $field_settings['min_resolution']) {
|
Chris@0
|
126 $field_validators['file_validate_image_resolution'] = [$field_settings['max_resolution'], $field_settings['min_resolution']];
|
Chris@0
|
127 }
|
Chris@0
|
128
|
Chris@0
|
129 // Create the destination directory if it does not already exist.
|
Chris@18
|
130 if (isset($destination) && !$this->fileSystem->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY)) {
|
Chris@0
|
131 return new JsonResponse(['main_error' => $this->t('The destination directory could not be created.'), 'errors' => '']);
|
Chris@0
|
132 }
|
Chris@0
|
133
|
Chris@0
|
134 // Attempt to save the image given the field's constraints.
|
Chris@0
|
135 $result = file_save_upload('image', $field_validators, $destination);
|
Chris@0
|
136 if (is_array($result) && $result[0]) {
|
Chris@0
|
137 /** @var \Drupal\file\Entity\File $file */
|
Chris@0
|
138 $file = $result[0];
|
Chris@0
|
139 $image = $this->imageFactory->get($file->getFileUri());
|
Chris@0
|
140
|
Chris@0
|
141 // Set the value in the Entity to the new file.
|
Chris@0
|
142 /** @var \Drupal\file\Plugin\Field\FieldType\FileFieldItemList $field_list */
|
Chris@0
|
143 $value = $entity->$field_name->getValue();
|
Chris@0
|
144 $value[0]['target_id'] = $file->id();
|
Chris@0
|
145 $value[0]['width'] = $image->getWidth();
|
Chris@0
|
146 $value[0]['height'] = $image->getHeight();
|
Chris@0
|
147 $entity->$field_name->setValue($value);
|
Chris@0
|
148
|
Chris@0
|
149 // Render the new image using the correct formatter settings.
|
Chris@18
|
150 $entity_view_mode_ids = array_keys($this->entityDisplayRepository->getViewModes($entity->getEntityTypeId()));
|
Chris@0
|
151 if (in_array($view_mode_id, $entity_view_mode_ids, TRUE)) {
|
Chris@0
|
152 $output = $entity->$field_name->view($view_mode_id);
|
Chris@0
|
153 }
|
Chris@0
|
154 else {
|
Chris@0
|
155 // Each part of a custom (non-Entity Display) view mode ID is separated
|
Chris@0
|
156 // by a dash; the first part must be the module name.
|
Chris@0
|
157 $mode_id_parts = explode('-', $view_mode_id, 2);
|
Chris@0
|
158 $module = reset($mode_id_parts);
|
Chris@0
|
159 $args = [$entity, $field_name, $view_mode_id, $langcode];
|
Chris@0
|
160 $output = $this->moduleHandler()->invoke($module, 'quickedit_render_field', $args);
|
Chris@0
|
161 }
|
Chris@0
|
162
|
Chris@0
|
163 // Save the Entity to tempstore.
|
Chris@0
|
164 $this->tempStore->set($entity->uuid(), $entity);
|
Chris@0
|
165
|
Chris@0
|
166 $data = [
|
Chris@0
|
167 'fid' => $file->id(),
|
Chris@0
|
168 'html' => $this->renderer->renderRoot($output),
|
Chris@0
|
169 ];
|
Chris@0
|
170 return new JsonResponse($data);
|
Chris@0
|
171 }
|
Chris@0
|
172 else {
|
Chris@0
|
173 // Return a JSON object containing the errors from Drupal and our
|
Chris@0
|
174 // "main_error", which is displayed inside the dropzone area.
|
Chris@0
|
175 $messages = StatusMessages::renderMessages('error');
|
Chris@0
|
176 return new JsonResponse(['errors' => $this->renderer->render($messages), 'main_error' => $this->t('The image failed validation.')]);
|
Chris@0
|
177 }
|
Chris@0
|
178 }
|
Chris@0
|
179
|
Chris@0
|
180 /**
|
Chris@0
|
181 * Returns JSON representing an image field's metadata.
|
Chris@0
|
182 *
|
Chris@0
|
183 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
184 * The entity of which an image field is being rendered.
|
Chris@0
|
185 * @param string $field_name
|
Chris@0
|
186 * The name of the (image) field that is being rendered
|
Chris@0
|
187 * @param string $langcode
|
Chris@0
|
188 * The language code of the field that is being rendered.
|
Chris@0
|
189 * @param string $view_mode_id
|
Chris@0
|
190 * The view mode of the field that is being rendered.
|
Chris@0
|
191 *
|
Chris@0
|
192 * @return \Drupal\Core\Cache\CacheableJsonResponse
|
Chris@0
|
193 * The JSON response.
|
Chris@0
|
194 */
|
Chris@0
|
195 public function getInfo(EntityInterface $entity, $field_name, $langcode, $view_mode_id) {
|
Chris@0
|
196 $field = $this->getField($entity, $field_name, $langcode);
|
Chris@0
|
197 $settings = $field->getFieldDefinition()->getSettings();
|
Chris@0
|
198 $info = [
|
Chris@0
|
199 'alt' => $field->alt,
|
Chris@0
|
200 'title' => $field->title,
|
Chris@0
|
201 'alt_field' => $settings['alt_field'],
|
Chris@0
|
202 'title_field' => $settings['title_field'],
|
Chris@0
|
203 'alt_field_required' => $settings['alt_field_required'],
|
Chris@0
|
204 'title_field_required' => $settings['title_field_required'],
|
Chris@0
|
205 ];
|
Chris@0
|
206 $response = new CacheableJsonResponse($info);
|
Chris@0
|
207 $response->addCacheableDependency($entity);
|
Chris@0
|
208 return $response;
|
Chris@0
|
209 }
|
Chris@0
|
210
|
Chris@0
|
211 /**
|
Chris@0
|
212 * Returns JSON representing the current state of the field.
|
Chris@0
|
213 *
|
Chris@0
|
214 * @param \Drupal\Core\Entity\EntityInterface $entity
|
Chris@0
|
215 * The entity of which an image field is being rendered.
|
Chris@0
|
216 * @param string $field_name
|
Chris@0
|
217 * The name of the (image) field that is being rendered
|
Chris@0
|
218 * @param string $langcode
|
Chris@0
|
219 * The language code of the field that is being rendered.
|
Chris@0
|
220 *
|
Chris@0
|
221 * @return \Drupal\image\Plugin\Field\FieldType\ImageItem
|
Chris@0
|
222 * The field for this request.
|
Chris@0
|
223 *
|
Chris@0
|
224 * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
|
Chris@0
|
225 * Throws an exception if the request is invalid.
|
Chris@0
|
226 */
|
Chris@0
|
227 protected function getField(EntityInterface $entity, $field_name, $langcode) {
|
Chris@0
|
228 // Ensure that this is a valid Entity.
|
Chris@0
|
229 if (!($entity instanceof ContentEntityInterface)) {
|
Chris@0
|
230 throw new BadRequestHttpException('Requested Entity is not a Content Entity.');
|
Chris@0
|
231 }
|
Chris@0
|
232
|
Chris@0
|
233 // Check that this field exists.
|
Chris@0
|
234 /** @var \Drupal\Core\Field\FieldItemListInterface $field_list */
|
Chris@0
|
235 $field_list = $entity->getTranslation($langcode)->get($field_name);
|
Chris@0
|
236 if (!$field_list) {
|
Chris@0
|
237 throw new BadRequestHttpException('Requested Field does not exist.');
|
Chris@0
|
238 }
|
Chris@0
|
239
|
Chris@0
|
240 // If the list is empty, append an empty item to use.
|
Chris@0
|
241 if ($field_list->isEmpty()) {
|
Chris@0
|
242 $field = $field_list->appendItem();
|
Chris@0
|
243 }
|
Chris@0
|
244 // Otherwise, use the first item.
|
Chris@0
|
245 else {
|
Chris@0
|
246 $field = $entity->getTranslation($langcode)->get($field_name)->first();
|
Chris@0
|
247 }
|
Chris@0
|
248
|
Chris@0
|
249 // Ensure that the field is the type we expect.
|
Chris@0
|
250 if (!($field instanceof ImageItem)) {
|
Chris@0
|
251 throw new BadRequestHttpException('Requested Field is not of type "image".');
|
Chris@0
|
252 }
|
Chris@0
|
253
|
Chris@0
|
254 return $field;
|
Chris@0
|
255 }
|
Chris@0
|
256
|
Chris@0
|
257 }
|