diff --git a/composer.json b/composer.json index 0429171b7dae162f0a2857176f2b36627e9b2cd7..d9f0627db06546b1ecc60b574b906fbc7fc8735f 100644 --- a/composer.json +++ b/composer.json @@ -246,7 +246,9 @@ }, "drupal/entity_browser": { "2914385 - Fix PHP error": - "https://www.drupal.org/files/issues/2023-10-10/2914385-25.patch" + "https://www.drupal.org/files/issues/2023-10-10/2914385-25.patch", + "2843247 - Drupal ajax error of undefined method getFileUri() while selecting newly uploaded image": + "https://www.drupal.org/files/issues/2025-02-13/entity-browser-2843247-16.patch" }, "drupal/fontawesome": { "3071758 - Fix multiple icons issue": diff --git a/modules/custom/wxt_ext/wxt_ext_media/src/Element/Upload.php b/modules/custom/wxt_ext/wxt_ext_media/src/Element/Upload.php index 3ef5789c749068e7f6956bd04995eb4c4a6bd60d..ac4a1da8679f93c7c68b49abdbd7aa0abd364415 100644 --- a/modules/custom/wxt_ext/wxt_ext_media/src/Element/Upload.php +++ b/modules/custom/wxt_ext/wxt_ext_media/src/Element/Upload.php @@ -42,19 +42,63 @@ public function getInfo() { * The current form state. */ public static function validate(array &$element, FormStateInterface $form_state) { - if ($element['#value']) { + if (isset($element['#value']) && $element['#value']) { $file = File::load($element['#value']); + if (!$file) { + \Drupal::logger('wxt_ext_media')->error( + 'File entity not found. Value: @value, Field: @field_name, Form: @form_id', + [ + '@value' => $element['#value'], + '@field_name' => $element['#name'] ?? 'unknown', + '@form_id' => $form_state->getFormObject()->getFormId() ?? 'unknown', + ] + ); + return; + } + $file_validator = \Drupal::service('file.validator'); - $errors = $file_validator->file_validate($file, $element['#upload_validators']); - if ($errors) { + $errors = $file_validator->validate($file, $element['#upload_validators']); + + if ($errors && count($errors)) { foreach ($errors as $error) { + \Drupal::logger('wxt_ext_media')->error( + 'File validation failed: @error for File ID: @fid', + ['@error' => $error, '@fid' => $file->id()] + ); $form_state->setError($element, $error); } static::delete($element); + return; + } + if (!count($errors) && $file && $file->isTemporary()) { + // Convert to a permanent file. + $file->setPermanent(); + $file->save(); } + + \Drupal::logger('wxt_ext_media')->notice( + 'File passed validation. File ID: @fid, URI: @uri', + ['@fid' => $file->id(), '@uri' => $file->getFileUri()] + ); } elseif ($element['#required']) { + \Drupal::logger('wxt_ext_media')->error( + 'Element required. FIELD NAME: @field_name, FORM_ID: @form_id.', + [ + '@field_name' => $element['#name'] ?? 'unknown', + '@form_id' => $form_state->getFormObject()->getFormId() ?? 'unknown', + ] + ); + $form_state->setError($element, t('You must upload a file.')); + } + else { + \Drupal::logger('wxt_ext_media')->error( + 'Element not found. FORM_ID: @form_id.', + [ + '@form_id' => $form_state->getFormObject()->getFormId() ?? 'unknown', + ] + ); $form_state->setError($element, t('You must upload a file.')); } } @@ -71,7 +115,11 @@ public static function delete(array $element) { $file->delete(); // Clean up the file system if needed. - $uri = $file->getFileUri(); + $uri = NULL; + if ($file instanceof File) { + $uri = $file->getFileUri(); + } + if (file_exists($uri)) { \Drupal::service('file_system')->unlink($uri); } diff --git a/modules/custom/wxt_ext/wxt_ext_media/src/MediaHelper.php b/modules/custom/wxt_ext/wxt_ext_media/src/MediaHelper.php index 313d8bb6e31e0ab5e19a6d8dc5fb6a61d7145c21..6d58c5d28496a31d4e0de6813820696f018481c5 100644 --- a/modules/custom/wxt_ext/wxt_ext_media/src/MediaHelper.php +++ b/modules/custom/wxt_ext/wxt_ext_media/src/MediaHelper.php @@ -189,7 +189,28 @@ public static function useFile(MediaInterface $entity, FileInterface $file, $rep /** @var \Drupal\file\FileInterface $file */ $file = File::load($file->id()); - if ($destination == $file->getFileUri()) { + if ($file instanceof File) { + \Drupal::logger('wxt_ext_media')->notice( + 'useFile debug: ID: @fid, URI: @uri, DESTINATION: @destination Status: @status', + [ + '@fid' => $file->id(), + '@uri' => $file->getFileUri(), + '@destination' => $destination, + '@status' => $file->isTemporary() ? 'Temporary' : 'Permanent', + ] + ); + } + else { + \Drupal::logger('wxt_ext_media')->notice( + 'useFile debug: ID: @fid, DESTINATION: @destination, Status: @status', + [ + '@fid' => $file->id(), + '@destination' => $destination, + '@status' => $file->isTemporary() ? 'Temporary' : 'Permanent', + ] + ); + } + if ($file instanceof File && $destination == $file->getFileUri()) { return $file; } else { diff --git a/modules/custom/wxt_ext/wxt_ext_media/src/Plugin/EntityBrowser/Widget/EntityFormProxy.php b/modules/custom/wxt_ext/wxt_ext_media/src/Plugin/EntityBrowser/Widget/EntityFormProxy.php index b514a216a41e5441066928d672bfcb55f901330e..2b03b273b1dc250ca303d7cc045fb5d09a53e3b4 100644 --- a/modules/custom/wxt_ext/wxt_ext_media/src/Plugin/EntityBrowser/Widget/EntityFormProxy.php +++ b/modules/custom/wxt_ext/wxt_ext_media/src/Plugin/EntityBrowser/Widget/EntityFormProxy.php @@ -97,7 +97,6 @@ public function getForm(array &$original_form, FormStateInterface $form_state, a protected function getCurrentEntity(FormStateInterface $form_state) { $value = $this->getCurrentValue($form_state); $types = $this->getCurrentTypes($form_state); - $type = $form_state->getValue('bundle'); if (empty($type) && count($types) === 1) { @@ -105,8 +104,37 @@ protected function getCurrentEntity(FormStateInterface $form_state) { } if ($value && $type) { - return $this->createMedia($value, $types[$type]); + // Check if media entity is already in form_state + if ($media = $form_state->get('media_entity')) { + // Use it; + $this->selectEntities([$media], $form_state); + $form_state->set('media_entity', $media); + return $media; + } + + // Create the media entity + $media = $this->createMedia($value, $types[$type]); + $media->save(); + \Drupal::logger('wxt_ext_media')->notice( + '✅ Media entity created: ID: @id, UUID: @uuid', + [ + '@id' => $media->id(), + '@uuid' => $media->uuid(), + ] + ); + + $this->selectEntities([$media], $form_state); + + // Store the media entity in form_state so it persists across AJAX calls + $form_state->set('media_entity', $media); + + return $media; } + + \Drupal::logger('wxt_ext_media')->error( + '🚨 getCurrentEntity() failed: No valid media entity found.' + ); + return NULL; } @@ -171,10 +199,19 @@ public static function update(array &$form, FormStateInterface $form_state) { * {@inheritdoc} */ public function submit(array &$element, array &$form, FormStateInterface $form_state) { - // IEF will take care of creating the entity upon submission. All we need to - // do is send it upstream to Entity Browser. - $entity = $form['widget']['entity']['#entity']; - $this->selectEntities([$entity], $form_state); + if (isset($form['widget']['entity']['#entity'])) { + $entity = $form['widget']['entity']['#entity']; + + \Drupal::logger('wxt_ext_media')->notice( + 'DEBUG: submit() called. Entity exists: ID: @id, UUID: @uuid', + [ + '@id' => $entity->id() ?? 'NULL', + '@uuid' => $entity->uuid() ?? 'NULL', + ] + ); + + $this->selectEntities([$entity], $form_state); + } } /** @@ -190,16 +227,13 @@ public function submit(array &$element, array &$form, FormStateInterface $form_s */ public static function ajax(array &$form, FormStateInterface $form_state) { if ($form_state::hasAnyErrors()) { + \Drupal::logger('wxt_ext_media')->error('🚨 Form state has errors.'); $form['widget']['bundle']['#access'] = FALSE; } return (new AjaxResponse()) - ->addCommand( - new ReplaceCommand('#entity-form', $form['widget']) - ) - ->addCommand( - new PrependCommand('#entity-form', ['#type' => 'status_messages']) - ); + ->addCommand(new ReplaceCommand('#entity-form', $form['widget'])) + ->addCommand(new PrependCommand('#entity-form', ['#type' => 'status_messages'])); } /** diff --git a/modules/custom/wxt_ext/wxt_ext_media/src/Plugin/EntityBrowser/Widget/FileUpload.php b/modules/custom/wxt_ext/wxt_ext_media/src/Plugin/EntityBrowser/Widget/FileUpload.php index 09099709e22dbfea54b533b5bd5f57458813387a..3816d710e5957d94c7ecaf397a699b150a4e1396 100644 --- a/modules/custom/wxt_ext/wxt_ext_media/src/Plugin/EntityBrowser/Widget/FileUpload.php +++ b/modules/custom/wxt_ext/wxt_ext_media/src/Plugin/EntityBrowser/Widget/FileUpload.php @@ -82,10 +82,10 @@ protected function getUploadValidators() { // If the widget context didn't specify any file extension validation, add // it as the first validator, allowing it to accept only file extensions // associated with existing media bundles. - if (empty($validators['file_validate_extensions'])) { + if (empty($validators['FileExtension'])) { return array_merge([ - 'file_validate_extensions' => [ - implode(' ', $this->getAllowedFileExtensions()), + 'FileExtension' => [ + 'extensions' => $this->getAllowedFileExtensions(), ], ], $validators); } @@ -115,15 +115,45 @@ protected function getAllowedFileExtensions() { * {@inheritdoc} */ public function validate(array &$form, FormStateInterface $form_state) { + if (empty($form_state->getValue('input'))) { + \Drupal::logger('wxt_ext_media')->warning( + 'Missing required input field in form: @form_id', + [ + '@form_id' => $form_id, + ] + ); + } $fid = $this->getCurrentValue($form_state); if ($fid) { parent::validate($form, $form_state); $media = $this->getCurrentEntity($form_state); if ($media) { + $has_error = FALSE; foreach ($this->validateFile($media) as $error) { + \Drupal::logger('wxt_ext_media')->error( + 'Form state has ERROR: @error.', + [ + '@error' => $error, + ] + ); + $has_error = TRUE; $form_state->setError($form['widget']['input'], $error); } + if ($has_error) { + return; + } + $source_field = $media->getSource()->getSourceFieldDefinition($media->bundle->entity)->getName(); + + if ($source_field && $media->hasField($source_field) && !$media->get($source_field)->isEmpty()) { + $file = $media->get($source_field)->entity; + if (!$file) { + \Drupal::logger('wxt_ext_media')->error('File is NULL after retrieval.'); + } + } + else { + \Drupal::logger('wxt_ext_media')->error('Source field does not exist or is empty.'); + } } } } @@ -135,7 +165,7 @@ public function validate(array &$form, FormStateInterface $form_state) { * The media item. * * @return array[] - * Any errors returned by file_validate(). + * Any errors returned by validate(). */ protected function validateFile(MediaInterface $media) { $field = $media->getSource() @@ -148,38 +178,40 @@ protected function validateFile(MediaInterface $media) { $validators = [ // It's maybe a bit overzealous to run this validator, but hey...better // safe than screwed over by script kiddies. - 'file_validate_name_length' => [], + 'FileNameLength' => [], ]; $validators = array_merge($validators, $item->getUploadValidators()); // This function is only called by the custom FileUpload widget, which runs - // file_validate_extensions before this function. So there's no need to + // FileExtension before this function. So there's no need to // validate the extensions again. - unset($validators['file_validate_extensions']); + unset($validators['FileExtension']); // If this is an image field, add image validation. Against all sanity, // this is normally done by ImageWidget, not ImageItem, which is why we // need to facilitate this a bit. if ($item instanceof ImageItem) { // Validate that this is, indeed, a supported image. - $validators['file_validate_is_image'] = []; + $validators['FileIsImage'] = []; $settings = $item->getFieldDefinition()->getSettings(); if ($settings['max_resolution'] || $settings['min_resolution']) { - $validators['file_validate_image_resolution'] = [ - $settings['max_resolution'], - $settings['min_resolution'], + $validators['FileImageDimensions'] = [ + 'maxDimensions' => [$settings['max_resolution']], + 'minDimensions' => [$settings['min_resolution']], ]; } } $file_validator = \Drupal::service('file.validator'); - return $file_validator->file_validate($item->entity, $validators); + + return $file_validator->validate($item->entity, $validators); } /** * {@inheritdoc} */ public function submit(array &$element, array &$form, FormStateInterface $form_state) { + \Drupal::logger('wxt_ext_media')->notice('FileUpload.php submit is called.'); /** @var \Drupal\media\MediaInterface $entity */ $entity = $element['entity']['#entity']; diff --git a/modules/custom/wxt_ext/wxt_ext_media/wxt_ext_media.module b/modules/custom/wxt_ext/wxt_ext_media/wxt_ext_media.module index 4cb87210f72a7bb93f5b77b25631bb2a07c3bcd7..3a8f725a2b9e99a64f7b27617037f98df1947c34 100644 --- a/modules/custom/wxt_ext/wxt_ext_media/wxt_ext_media.module +++ b/modules/custom/wxt_ext/wxt_ext_media/wxt_ext_media.module @@ -12,9 +12,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\StringTranslation\PluralTranslatableMarkup as Plural; use Drupal\ckeditor\Ajax\AddStyleSheetCommand; -use Drupal\file\FileInterface; use Drupal\image\Entity\ImageStyle; -use Drupal\image\Plugin\Field\FieldType\ImageItem; use Drupal\image\Plugin\Field\FieldWidget\ImageWidget; use Drupal\image\Plugin\ImageEffect\ResizeImageEffect; use Drupal\media\Entity\MediaType; @@ -23,7 +21,6 @@ use Drupal\views\ViewExecutable; use Drupal\wxt_core\BundleEntityStorage; use Drupal\wxt_core\OverrideHelper as Override; -use Drupal\wxt_ext_media\Exception\IndeterminateBundleException; use Drupal\wxt_ext_media\Form\MediaForm; use Drupal\wxt_ext_media\ImageWidgetHelper; use Drupal\wxt_ext_media\MediaHelper; @@ -149,60 +146,6 @@ function wxt_ext_media_inline_entity_form_entity_form_alter(array &$entity_form) } } -/** - * Validates a file using media entity source field criteria. - * - * @param \Drupal\file\FileInterface $file - * The file to validate. - * @param string[] $bundles - * (optional) A set of media bundle IDs which might match the input. If - * omitted, all bundles to which the user has create access will be checked. - * - * @return string[] - * An array of errors. If empty, the file passed validation. - */ -function wxt_ext_media_validate_upload(FileInterface $file, array $bundles = []) { - try { - $entity = \Drupal::service('wxt.media_helper')->createFromInput($file, $bundles); - } - catch (IndeterminateBundleException $e) { - return []; - } - - /** @var \Drupal\file\Plugin\Field\FieldType\FileItem $item */ - $item = MediaHelper::getSourceField($entity)->first(); - - $validators = [ - // It's maybe a bit overzealous to run this validator, but hey...better - // safe than screwed over by script kiddies. - 'file_validate_name_length' => [], - ]; - $validators = array_merge($validators, $item->getUploadValidators()); - // This function is only called by the custom FileUpload widget, which runs - // file_validate_extensions before this function. So there's no need to - // validate the extensions again. - unset($validators['file_validate_extensions']); - - // If this is an image field, add image validation. Against all sanity, - // this is normally done by ImageWidget, not ImageItem, which is why we - // need to facilitate this a bit. - if ($item instanceof ImageItem) { - // Validate that this is, indeed, a supported image. - $validators['file_validate_is_image'] = []; - - $settings = $item->getFieldDefinition()->getSettings(); - if ($settings['max_resolution'] || $settings['min_resolution']) { - $validators['file_validate_image_resolution'] = [ - $settings['max_resolution'], - $settings['min_resolution'], - ]; - } - } - - $file_validator = \Drupal::service('file.validator'); - return $file_validator->file_validate($file, $validators); -} - /** * Post-build callback for entity browser elements. * @@ -219,9 +162,14 @@ function wxt_ext_media_validate_upload(FileInterface $file, array $bundles = []) * The processed element. */ function wxt_ext_media_inject_entity_browser_count(array $element) { + if (empty($element['#attached']['drupalSettings']['entity_browser'])) { + return $element; + } + $settings = &$element['#attached']['drupalSettings']['entity_browser']; $uuid = key($settings); - $settings[$uuid]['count'] = count($element['#default_value']); + $cardinality = $element['#cardinality'] ?? 1; + $settings[$uuid]['count'] = min(count($element['#default_value'] ?? []), $cardinality); return $element; }