diff --git a/.github/workflows/build-2.x.yml b/.github/workflows/build-2.x.yml
index c5d9d66b0..8677ddf4e 100644
--- a/.github/workflows/build-2.x.yml
+++ b/.github/workflows/build-2.x.yml
@@ -1,38 +1,30 @@
-# This is a basic workflow to help you get started with Actions
-
name: CI
-# Controls when the action will run.
on:
- # Triggers the workflow on push or pull request events but only for the 2.x branch
push:
branches: [ 2.x ]
pull_request:
branches: [ 2.x ]
-
- # Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
-# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
- # This workflow contains a single job called "build"
build:
- # The type of runner that the job will run on
+ env:
+ DRUPAL_VERSION: ${{ matrix.drupal-version }}
+ SCRIPT_DIR: ${{ github.workspace }}/islandora_ci
+ DRUPAL_DIR: /opt/drupal
+ PHPUNIT_FILE: ${{ github.workspace }}/build_dir/phpunit.xml
+
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.allowed_failure }}
strategy:
fail-fast: false
matrix:
php-versions: ["8.1", "8.2", "8.3"]
- # test-suite functional-javascript will appear to pass but will skip tests; missing chromedriver.
test-suite: ["kernel", "functional", "functional-javascript"]
- drupal-version: ["10.1.x", "10.2.x", "10.3.x-dev"]
+ drupal-version: ["10.2.x", "10.3.x", "10.4.x-dev"]
mysql: ["8.0"]
allowed_failure: [false]
- exclude:
- - php-versions: "8.3"
- drupal-version: "10.1.x"
-
name: PHP ${{ matrix.php-versions }} | drupal ${{ matrix.drupal-version }} | mysql ${{ matrix.mysql }} | test-suite ${{ matrix.test-suite }}
@@ -51,17 +43,15 @@ jobs:
- 61616:61616
- 61613:61613
- # Steps represent a sequence of tasks that will be executed as part of the job
steps:
- # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: build_dir
- name: Checkout islandora_ci
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
repository: islandora/islandora_ci
ref: github-actions
@@ -79,13 +69,6 @@ jobs:
sudo apt-get remove -y mysql-client mysql-common
sudo apt-get install -y mysql-client
- - name: Set environment variables
- run: |
- echo "DRUPAL_VERSION=${{ matrix.drupal-version }}" >> $GITHUB_ENV
- echo "SCRIPT_DIR=$GITHUB_WORKSPACE/islandora_ci" >> $GITHUB_ENV
- echo "DRUPAL_DIR=/opt/drupal" >> $GITHUB_ENV
- echo "PHPUNIT_FILE=$GITHUB_WORKSPACE/build_dir/phpunit.xml" >> $GITHUB_ENV
-
- name: Cache Composer dependencies
uses: actions/cache@v3
with:
@@ -118,8 +101,21 @@ jobs:
- name: Test scripts
run: $SCRIPT_DIR/travis_scripts.sh
+
+ - name: Start chromedriver
+ if: matrix.test-suite == 'functional-javascript'
+ run: |-
+ /usr/local/share/chromedriver-linux64/chromedriver \
+ --log-path=/tmp/chromedriver.log \
+ --verbose \
+ --allowed-ips= \
+ --allowed-origins=* &
- name: PHPUNIT tests
run: |
cd $DRUPAL_DIR/web/core
$DRUPAL_DIR/vendor/bin/phpunit --verbose --testsuite "${{ matrix.test-suite }}"
+
+ - name: Print chromedriver logs
+ if: matrix.test-suite == 'functional-javascript'
+ run: cat /tmp/chromedriver.log
diff --git a/composer.json b/composer.json
index cb95bbc6e..9a3c693e8 100644
--- a/composer.json
+++ b/composer.json
@@ -18,8 +18,9 @@
"drupal/ctools": "^3.8 || ^4",
"drupal/eva" : "^3.0",
"drupal/file_replace": "^1.1",
- "drupal/filehash": "^2",
+ "drupal/filehash": "^2 || ^3",
"drupal/flysystem" : "^2.0@alpha",
+ "drupal/jsonld": "^2 || ^3",
"drupal/jwt": "^1.1 || ^2",
"drupal/migrate_plus" : "^5.1 || ^6",
"drupal/migrate_source_csv" : "^3.4",
@@ -28,7 +29,6 @@
"drupal/token" : "^1.3",
"islandora/chullo": "^2.0",
"islandora/fedora-entity-mapper": "^1.0",
- "islandora/jsonld": "^2 || ^3",
"stomp-php/stomp-php": "4.* || ^5"
},
"require-dev": {
diff --git a/config/schema/islandora.schema.yml b/config/schema/islandora.schema.yml
index 49de998b3..282f7b3c5 100644
--- a/config/schema/islandora.schema.yml
+++ b/config/schema/islandora.schema.yml
@@ -173,6 +173,10 @@ condition.plugin.node_had_namespace:
field.formatter.settings.islandora_image:
type: field.formatter.settings.image
label: 'Islandora image field display format settings'
+ mapping:
+ image_alt_text:
+ type: string
+ label: "Alt text source"
condition.plugin.islandora_entity_bundle:
type: condition.plugin
diff --git a/islandora.info.yml b/islandora.info.yml
index 6dd0597f2..a43196a42 100644
--- a/islandora.info.yml
+++ b/islandora.info.yml
@@ -4,7 +4,7 @@ name: 'islandora'
description: "Islandora Core"
type: module
package: Islandora
-core_version_requirement: ^9 || ^10
+core_version_requirement: ^10.2
dependencies:
- context:context_ui
- ctools:ctools
diff --git a/islandora.module b/islandora.module
index d715db52d..153eb1679 100644
--- a/islandora.module
+++ b/islandora.module
@@ -16,19 +16,18 @@
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
+use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\Url;
+use Drupal\file\FileInterface;
use Drupal\islandora\Form\IslandoraSettingsForm;
-use Drupal\node\NodeInterface;
use Drupal\media\MediaInterface;
-use Drupal\file\FileInterface;
-use Drupal\taxonomy\TermInterface;
-use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\node\NodeInterface;
use Drupal\serialization\Normalizer\CacheableNormalizerInterface;
-use Drupal\Core\Entity\EntityForm;
-use Drupal\file\Entity\File;
+use Drupal\taxonomy\TermInterface;
/**
* Implements hook_help().
@@ -408,132 +407,25 @@ function islandora_media_custom_form_submit(&$form, FormStateInterface $form_sta
* Implements a submit handler for the delete form.
*/
function islandora_object_delete_form_submit($form, FormStateInterface $form_state) {
-
$result = $form_state->getValues('delete_associated_content');
- $utils = \Drupal::service('islandora.utils');
-
if ($result['delete_associated_content'] == 1) {
-
+ $utils = \Drupal::service('islandora.utils');
$node = $form_state->getFormObject()->getEntity();
$medias = $utils->getMedia($node);
- $media_list = [];
-
- $entity_field_manager = \Drupal::service('entity_field.manager');
- $current_user = \Drupal::currentUser();
+ $results = $utils->deleteMediaAndFiles($medias);
$logger = \Drupal::logger('logger.channel.islandora');
$messenger = \Drupal::messenger();
-
- $delete_media = [];
- $media_translations = [];
- $media_files = [];
- $entity_protected_medias = [];
- $inaccessible_entities = [];
-
- foreach ($medias as $id => $media) {
- $lang = $media->language()->getId();
- $selected_langcodes[$lang] = $lang;
-
- if (!$media->access('delete', $current_user)) {
- $inaccessible_entities[] = $media;
- continue;
- }
- // Check for files.
- $fields = $entity_field_manager->getFieldDefinitions('media', $media->bundle());
- foreach ($fields as $field) {
- $type = $field->getType();
- if ($type == 'file' || $type == 'image') {
- $target_id = $media->get($field->getName())->target_id;
- $file = File::load($target_id);
- if ($file) {
- if (!$file->access('delete', $current_user)) {
- $inaccessible_entities[] = $file;
- continue;
- }
- $media_files[$id][$file->id()] = $file;
- }
- }
- }
-
- foreach ($selected_langcodes as $langcode) {
- // We're only working with media, which are translatable.
- $entity = $media->getTranslation($langcode);
- if ($entity->isDefaultTranslation()) {
- $delete_media[$id] = $entity;
- unset($media_translations[$id]);
- }
- elseif (!isset($delete_media[$id])) {
- $media_translations[$id][] = $entity;
- }
- }
- }
-
- if ($delete_media) {
- foreach ($delete_media as $id => $media) {
- try {
- $media->delete();
- $media_list[] = $id;
- $logger->notice('The media %label has been deleted.', [
- '%label' => $media->label(),
- ]);
- }
- catch (Exception $e) {
- $entity_protected_medias[] = $id;
- }
- }
- }
-
- $delete_files = array_filter($media_files, function ($media) use ($entity_protected_medias) {
- return !in_array($media, $entity_protected_medias);
- }, ARRAY_FILTER_USE_KEY);
-
- if ($delete_files) {
- foreach ($delete_files as $files_array) {
- foreach ($files_array as $file) {
- $file->delete();
- $logger->notice('The file %label has been deleted.', [
- '%label' => $file->label(),
- ]);
- }
- }
+ if (isset($results['inaccessible'])) {
+ $messenger->addWarning($results['inaccessible']);
}
-
- $delete_media_translations = array_filter($media_translations, function ($media) use ($entity_protected_medias) {
- return !in_array($media, $entity_protected_medias);
- }, ARRAY_FILTER_USE_KEY);
-
- if ($delete_media_translations) {
- foreach ($delete_media_translations as $id => $translations) {
- $media = $medias[$id];
- foreach ($translations as $translation) {
- $media->removeTranslation($translation->language()->getId());
- }
- $media->save();
- foreach ($translations as $translation) {
- $logger->notice('The media %label @language translation has been deleted', [
- '%label' => $media->label(),
- '@language' => $translation->language()->getName(),
- ]);
- }
- }
- }
-
- if ($inaccessible_entities) {
- $messenger->addWarning("@count items have not been deleted because you do not have the necessary permissions.", [
- '@count' => count($inaccessible_entities),
- ]);
- }
-
+ $logger->notice($results['deleted']);
$build = [
'heading' => [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => t("The repository item @node and @media", [
'@node' => $node->getTitle(),
- '@media' => \Drupal::translation()->formatPlural(
- count($media_list), 'the media with the id @media has been deleted.',
- 'the medias with the ids @media have been deleted.',
- ['@media' => implode(", ", $media_list)],
- ),
+ '@media' => $results['deleted'],
]),
],
];
@@ -653,12 +545,11 @@ function islandora_entity_view(array &$build, EntityInterface $entity, EntityVie
$route_match_item = \Drupal::routeMatch()->getParameters()->get($entity->getEntityTypeId());
// Ensure the entity matches the route.
if ($entity === $route_match_item) {
- if ($display->getComponent('field_gemini_uri')) {
- $mapper = \Drupal::service('islandora.entity_mapper');
- $flysystem_config = Settings::get('flysystem');
- $fedora_root = $flysystem_config['fedora']['config']['root'];
+ $flysystem_config = Settings::get('flysystem');
+ $fedora_root = $flysystem_config['fedora']['config']['root'] ?? NULL;
+ if ($display->getComponent('field_gemini_uri') && $fedora_root) {
$fedora_root = rtrim($fedora_root, '/');
-
+ $mapper = \Drupal::service('islandora.entity_mapper');
if ($entity->getEntityTypeId() == 'media') {
// Check if the source file is in Fedora or not.
$media_source_service = \Drupal::service('islandora.media_source_service');
diff --git a/islandora.services.yml b/islandora.services.yml
index 74725d803..36ef7dac3 100644
--- a/islandora.services.yml
+++ b/islandora.services.yml
@@ -54,7 +54,7 @@ services:
arguments: ['@entity_type.manager', '@current_user', '@language_manager', '@file_system', '@islandora.utils']
islandora.utils:
class: Drupal\islandora\IslandoraUtils
- arguments: ['@entity_type.manager', '@entity_field.manager', '@context.manager', '@flysystem_factory', '@language_manager']
+ arguments: ['@entity_type.manager', '@entity_field.manager', '@context.manager', '@flysystem_factory', '@language_manager', '@current_user']
islandora.entity_mapper:
class: Islandora\EntityMapper\EntityMapper
islandora.stomp.auth_header_listener:
diff --git a/islandora.tokens.inc b/islandora.tokens.inc
index f528dee3d..d2c424c53 100644
--- a/islandora.tokens.inc
+++ b/islandora.tokens.inc
@@ -80,6 +80,9 @@ function islandora_tokens($type, $tokens, array $data, array $options, Bubbleabl
return;
}
$islandoraUtils = \Drupal::service('islandora.utils');
+ if (!$islandoraUtils->isIslandoraType('node', $data['node']->bundle())) {
+ return;
+ }
foreach ($tokens as $name => $original) {
switch ($name) {
case 'media-original-file:basename':
diff --git a/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php b/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php
index f0aca47da..42984eba8 100644
--- a/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php
+++ b/modules/islandora_iiif/src/Plugin/views/style/IIIFManifest.php
@@ -494,17 +494,20 @@ protected function defineOptions() {
*/
protected function addSearchEndpoint(array &$json, array $url_components) {
$url_base = $this->getRequest()->getSchemeAndHttpHost();
- $hocr_search_path = $this->options['search_endpoint'];
- $hocr_search_url = $url_base . '/' . ltrim($hocr_search_path, '/');
+ $hocr_search_path = $this->options['search_endpoint'] ?? null;
- $hocr_search_url = str_replace('%node', $url_components[1], $hocr_search_url);
+ if ($hocr_search_path) {
+ $hocr_search_url = $url_base . '/' . ltrim($hocr_search_path, '/');
- $json['service'][] = [
- "@context" => "http://iiif.io/api/search/0/context.json",
- "@id" => $hocr_search_url,
- "profile" => "http://iiif.io/api/search/0/search",
- "label" => t("Search inside this work"),
- ];
+ $hocr_search_url = str_replace('%node', $url_components[1], $hocr_search_url);
+
+ $json['service'][] = [
+ "@context" => "http://iiif.io/api/search/0/context.json",
+ "@id" => $hocr_search_url,
+ "profile" => "http://iiif.io/api/search/0/search",
+ "label" => t("Search inside this work"),
+ ];
+ }
}
/**
diff --git a/modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php b/modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php
index 272e9f01b..e60931a85 100644
--- a/modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php
+++ b/modules/islandora_text_extraction/src/Plugin/Action/GenerateOCRDerivative.php
@@ -48,8 +48,9 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::validateConfigurationForm($form, $form_state);
- $exploded_mime = explode('/', $form_state->getValue('mimetype'));
- if ($exploded_mime[0] != 'text') {
+ $mime = $form_state->getValue('mimetype');
+ $exploded_mime = explode('/', $mime);
+ if ($exploded_mime[0] != 'text' && $mime != 'application/xml') {
$form_state->setErrorByName(
'mimetype',
$this->t('Please enter file mimetype (e.g. text/plain.)')
diff --git a/phpunit.xml b/phpunit.xml
index 46e82e78d..bc0609fba 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -47,7 +47,7 @@
-
+
diff --git a/src/Form/AddChildrenWizard/AbstractFileSelectionForm.php b/src/Form/AddChildrenWizard/AbstractFileSelectionForm.php
index 6aeed8795..445c251e9 100644
--- a/src/Form/AddChildrenWizard/AbstractFileSelectionForm.php
+++ b/src/Form/AddChildrenWizard/AbstractFileSelectionForm.php
@@ -142,16 +142,46 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
$builder = (new BatchBuilder())
->setTitle($this->t('Bulk creating...'))
->setInitMessage($this->t('Initializing...'))
- ->setFinishCallback([$this->batchProcessor, 'batchProcessFinished']);
+ ->setFinishCallback([$this, 'batchProcessFinished']);
$values = $form_state->getValue($this->getField($cached_values)->getName());
$massaged_values = $widget->massageFormValues($values, $form, $form_state);
foreach ($massaged_values as $delta => $info) {
$builder->addOperation(
- [$this->batchProcessor, 'batchOperation'],
+ [$this, 'batchOperation'],
[$delta, $info, $cached_values]
);
}
batch_set($builder->toArray());
}
+ /**
+ * Wrap batch processor operation call to side-step serialization issues.
+ *
+ * Previously, we referred to the method on the processors directly; however,
+ * this can lead to issues regarding the (un)serialization of the services as
+ * which the processors are implemented. For example, if decorating one of the
+ * processors to extend it, it loses the reference back to be able to load the
+ * "inner"/decorated processor.
+ *
+ * @see \Drupal\islandora\Form\AddChildrenWizard\AbstractBatchProcessor::batchOperation()
+ */
+ public function batchOperation($delta, $info, $cached_values, &$context) : void {
+ $this->batchProcessor->batchOperation($delta, $info, $cached_values, $context);
+ }
+
+ /**
+ * Wrap batch processor finished call to side-step serialization issues.
+ *
+ * Previously, we referred to the method on the processors directly; however,
+ * this can lead to issues regarding the (un)serialization of the services as
+ * which the processors are implemented. For example, if decorating one of the
+ * processors to extend it, it loses the reference back to be able to load the
+ * "inner"/decorated processor.
+ *
+ * @see \Drupal\islandora\Form\AddChildrenWizard\AbstractBatchProcessor::batchProcessFinished()
+ */
+ public function batchProcessFinished($success, $results, $operations) : void {
+ $this->batchProcessor->batchProcessFinished($success, $results, $operations);
+ }
+
}
diff --git a/src/Form/ConfirmDeleteMediaAndFile.php b/src/Form/ConfirmDeleteMediaAndFile.php
index a9613871f..90e61878a 100644
--- a/src/Form/ConfirmDeleteMediaAndFile.php
+++ b/src/Form/ConfirmDeleteMediaAndFile.php
@@ -2,7 +2,6 @@
namespace Drupal\islandora\Form;
-use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Form\DeleteMultipleForm;
use Drupal\Core\Form\FormStateInterface;
@@ -10,8 +9,7 @@
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\Url;
-use Drupal\file\Entity\File;
-use Drupal\islandora\MediaSource\MediaSourceService;
+use Drupal\islandora\IslandoraUtils;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -21,11 +19,11 @@
class ConfirmDeleteMediaAndFile extends DeleteMultipleForm {
/**
- * Media source service.
+ * The current user.
*
- * @var \Drupal\islandora\MediaSource\MediaSourceService
+ * @var \Drupal\Core\Session\AccountInterface
*/
- protected $mediaSourceService;
+ protected $currentUser;
/**
* Logger.
@@ -42,23 +40,22 @@ class ConfirmDeleteMediaAndFile extends DeleteMultipleForm {
protected $selection = [];
/**
- * Entity field manager.
+ * The Islandora Utils service.
*
- * @var \Drupal\Core\Entity\EntityFieldManagerInterface
+ * @var \Drupal\islandora\IslandoraUtils
*/
- protected $entityFieldManager;
+ protected IslandoraUtils $utils;
/**
* {@inheritdoc}
*/
- public function __construct(AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, PrivateTempStoreFactory $temp_store_factory, MessengerInterface $messenger, MediaSourceService $media_source_service, LoggerInterface $logger) {
+ public function __construct(AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, PrivateTempStoreFactory $temp_store_factory, MessengerInterface $messenger, LoggerInterface $logger, IslandoraUtils $utils) {
$this->currentUser = $current_user;
$this->entityTypeManager = $entity_type_manager;
- $this->entityFieldManager = $entity_field_manager;
$this->tempStore = $temp_store_factory->get('media_and_file_delete_confirm');
$this->messenger = $messenger;
- $this->mediaSourceService = $media_source_service;
$this->logger = $logger;
+ $this->utils = $utils;
}
/**
@@ -68,11 +65,11 @@ public static function create(ContainerInterface $container) {
return new static(
$container->get('current_user'),
$container->get('entity_type.manager'),
- $container->get('entity_field.manager'),
$container->get('tempstore.private'),
$container->get('messenger'),
- $container->get('islandora.media_source_service'),
- $container->get('logger.channel.islandora'));
+ $container->get('logger.channel.islandora'),
+ $container->get('islandora.utils')
+ );
}
/**
@@ -111,94 +108,13 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t
public function submitForm(array &$form, FormStateInterface $form_state) {
// Similar to parent::submitForm(), but let's blend in the related files and
// optimize based on the fact that we know we're working with media.
- $total_count = 0;
- $delete_media = [];
- $delete_media_translations = [];
- $delete_files = [];
- $inaccessible_entities = [];
$media_storage = $this->entityTypeManager->getStorage('media');
- $file_storage = $this->entityTypeManager->getStorage('file');
$media = $media_storage->loadMultiple(array_keys($this->selection));
- foreach ($this->selection as $id => $selected_langcodes) {
- $entity = $media[$id];
- if (!$entity->access('delete', $this->currentUser)) {
- $inaccessible_entities[] = $entity;
- continue;
- }
- // Check for files.
- $fields = $this->entityFieldManager->getFieldDefinitions('media', $entity->bundle());
- foreach ($fields as $field) {
- if ($field->getName() == 'thumbnail') {
- continue;
- }
- $type = $field->getType();
- if ($type == 'file' || $type == 'image') {
- $target_id = $entity->get($field->getName())->target_id;
- $file = File::load($target_id);
- if ($file) {
- if (!$file->access('delete', $this->currentUser)) {
- $inaccessible_entities[] = $file;
- continue;
- }
- if (!array_key_exists($file->id(), $delete_files)) {
- $delete_files[$file->id()] = $file;
- $total_count++;
- }
-
- }
- }
- }
-
- foreach ($selected_langcodes as $langcode) {
- // We're only working with media, which are translatable.
- $entity = $entity->getTranslation($langcode);
- if ($entity->isDefaultTranslation()) {
- $delete_media[$id] = $entity;
- unset($delete_media_translations[$id]);
- $total_count += count($entity->getTranslationLanguages());
- }
- elseif (!isset($delete_media[$id])) {
- $delete_media_translations[$id][] = $entity;
- }
- }
- }
- if ($delete_media) {
- $media_storage->delete($delete_media);
- foreach ($delete_media as $entity) {
- $this->logger->notice('The media %label has been deleted.', [
- '%label' => $entity->label(),
- ]);
- }
- }
- if ($delete_files) {
- $file_storage->delete($delete_files);
- foreach ($delete_files as $entity) {
- $this->logger->notice('The file %label has been deleted.', [
- '%label' => $entity->label(),
- ]);
- }
- }
- if ($delete_media_translations) {
- foreach ($delete_media_translations as $id => $translations) {
- $entity = $media[$id];
- foreach ($translations as $translation) {
- $entity->removeTranslation($translation->language()->getId());
- }
- $entity->save();
- foreach ($translations as $translation) {
- $this->logger->notice('The media %label @language translation has been deleted', [
- '%label' => $entity->label(),
- '@language' => $translation->language()->getName(),
- ]);
- }
- $total_count += count($translations);
- }
- }
- if ($total_count) {
- $this->messenger->addStatus($this->getDeletedMessage($total_count));
- }
- if ($inaccessible_entities) {
- $this->messenger->addWarning($this->getInaccessibleMessage(count($inaccessible_entities)));
+ $results = $this->utils->deleteMediaAndFiles($media);
+ $this->logger->notice($results['deleted']);
+ $this->messenger->addStatus($results['deleted']);
+ if (isset($results['inaccessible'])) {
+ $this->messenger->addWarning($results['inaccessible']);
}
$this->tempStore->delete($this->currentUser->id());
$form_state->setRedirectUrl($this->getCancelUrl());
diff --git a/src/IslandoraContextManager.php b/src/IslandoraContextManager.php
index 9fd93fbc2..ed6f74af9 100644
--- a/src/IslandoraContextManager.php
+++ b/src/IslandoraContextManager.php
@@ -37,7 +37,7 @@ public function evaluateContexts(array $provided = []) {
}
/** @var \Drupal\context\ContextInterface $context */
foreach ($this->getContexts() as $context) {
- if ($this->evaluateContextConditions($context, $provided) && !$context->disabled()) {
+ if (!$context->disabled() && $this->evaluateContextConditions($context, $provided)) {
$this->activeContexts[$context->id()] = $context;
}
}
diff --git a/src/IslandoraUtils.php b/src/IslandoraUtils.php
index a2df75896..5d667fc42 100644
--- a/src/IslandoraUtils.php
+++ b/src/IslandoraUtils.php
@@ -10,7 +10,9 @@
use Drupal\Core\Entity\Query\QueryException;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Site\Settings;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\file\FileInterface;
use Drupal\flysystem\FlysystemFactory;
@@ -26,13 +28,15 @@
* Utility functions for figuring out when to fire derivative reactions.
*/
class IslandoraUtils {
-
+ use StringTranslationTrait;
const EXTERNAL_URI_FIELD = 'field_external_uri';
const MEDIA_OF_FIELD = 'field_media_of';
const MEDIA_USAGE_FIELD = 'field_media_use';
+
const MEMBER_OF_FIELD = 'field_member_of';
+
const MODEL_FIELD = 'field_model';
/**
@@ -68,7 +72,14 @@ class IslandoraUtils {
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
- protected $languageManager;
+ protected LanguageManagerInterface $languageManager;
+
+ /**
+ * The current user.
+ *
+ * @var \Drupal\Core\Session\AccountInterface
+ */
+ protected AccountInterface $currentUser;
/**
* Constructor.
@@ -83,19 +94,23 @@ class IslandoraUtils {
* Flysystem factory.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* Language manager.
+ * @param \Drupal\Core\Session\AccountInterface $current_user
+ * The current user.
*/
public function __construct(
EntityTypeManagerInterface $entity_type_manager,
EntityFieldManagerInterface $entity_field_manager,
ContextManager $context_manager,
FlysystemFactory $flysystem_factory,
- LanguageManagerInterface $language_manager
+ LanguageManagerInterface $language_manager,
+ AccountInterface $current_user
) {
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
$this->contextManager = $context_manager;
$this->flysystemFactory = $flysystem_factory;
$this->languageManager = $language_manager;
+ $this->currentUser = $current_user;
}
/**
@@ -423,7 +438,6 @@ public function executeDerivativeReactions($reaction_type, NodeInterface $node,
* TRUE if the fields have changed.
*/
public function haveFieldsChanged(ContentEntityInterface $entity, ContentEntityInterface $original) {
-
$field_definitions = $this->entityFieldManager->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle());
$ignore_list = ['vid' => 1, 'changed' => 1, 'path' => 1];
@@ -528,7 +542,8 @@ public function getMediaReferencingNodeAndTerm(NodeInterface $node, TermInterfac
* Array of fields.
*/
public function getReferencingFields($entity_type, $target_type) {
- $fields = $this->entityTypeManager->getStorage('field_storage_config')->getQuery()
+ $fields = $this->entityTypeManager->getStorage('field_storage_config')
+ ->getQuery()
->condition('entity_type', $entity_type)
->condition('settings.target_type', $target_type)
->execute();
@@ -657,8 +672,6 @@ public function isIslandoraType($entity_type, $bundle) {
public function canCreateIslandoraEntity($entity_type, $bundle_type) {
$bundles = $this->entityTypeManager->getStorage($bundle_type)->loadMultiple();
$access_control_handler = $this->entityTypeManager->getAccessControlHandler($entity_type);
-
- $allowed = [];
foreach (array_keys($bundles) as $bundle) {
// Skip bundles that aren't 'Islandora' types.
if (!$this->isIslandoraType($entity_type, $bundle)) {
@@ -755,4 +768,71 @@ protected function getParentsByEntityReference(ContentEntityInterface $entity, a
return $parents;
}
+ /**
+ * Deletes Media and all associated files.
+ *
+ * @param \Drupal\media\MediaInterface[] $media
+ * Array of media objects to be deleted along with their files.
+ *
+ * @return array
+ * Associative array keyed 'deleted' and 'inaccessible'.
+ *
+ * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
+ * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
+ * @throws \Drupal\Core\Entity\EntityStorageException
+ */
+ public function deleteMediaAndFiles(array $media) {
+ $results = [];
+ $delete_media = [];
+ $delete_files = [];
+ $inaccessible_entities = [];
+ $media_storage = $this->entityTypeManager->getStorage('media');
+ $file_storage = $this->entityTypeManager->getStorage('file');
+ foreach ($media as $entity) {
+ if (!$entity->access('delete', $this->currentUser)) {
+ $inaccessible_entities[] = $entity;
+ continue;
+ }
+ else {
+ $delete_media[$entity->id()] = $entity;
+ }
+ // Check for source and additional files.
+ $fields = $this->entityFieldManager->getFieldDefinitions('media', $entity->bundle());
+ foreach ($fields as $field) {
+ if ($field->getName() == 'thumbnail') {
+ continue;
+ }
+ $type = $field->getType();
+ if ($type == 'file' || $type == 'image') {
+ $target_id = $entity->get($field->getName())->target_id;
+ $file = $file_storage->load($target_id);
+ if ($file) {
+ if (!$file->access('delete', $this->currentUser)) {
+ $inaccessible_entities[] = $file;
+ continue;
+ }
+ if (!array_key_exists($file->id(), $delete_files)) {
+ $delete_files[$file->id()] = $file;
+ }
+ }
+ }
+ }
+ }
+ if ($delete_media) {
+ $media_storage->delete($delete_media);
+ }
+ if ($delete_files) {
+ $file_storage->delete($delete_files);
+ }
+ $results['deleted'] = $this->formatPlural(
+ count($delete_media), 'The media with the id @media has been deleted.',
+ 'The medias with the ids @media have been deleted.',
+ ['@media' => implode(", ", array_keys($delete_media))],
+ );
+ if ($inaccessible_entities) {
+ $results['inaccessible'] = $this->formatPlural($inaccessible_entities, "@count item has not been deleted because you do not have the necessary permissions.", "@count items have not been deleted because you do not have the necessary permissions.");
+ }
+ return $results;
+ }
+
}
diff --git a/src/Plugin/Condition/NodeHasParent.php b/src/Plugin/Condition/NodeHasParent.php
index f9ef0cbf5..813fd00b1 100644
--- a/src/Plugin/Condition/NodeHasParent.php
+++ b/src/Plugin/Condition/NodeHasParent.php
@@ -137,9 +137,11 @@ public function evaluate() {
* TRUE if entity references the specified parent.
*/
protected function evaluateEntity(EntityInterface $entity) {
+ $parent_reference_field = $this->configuration['parent_reference_field'];
foreach ($entity->referencedEntities() as $referenced_entity) {
- if ($entity->getEntityTypeID() == 'node' && $referenced_entity->getEntityTypeId() == 'node') {
- $parent_reference_field = $this->configuration['parent_reference_field'];
+ // Check whether the entity and the referenced entity are nodes.
+ // Also make sure that the field exists.
+ if ($entity->getEntityTypeID() == 'node' && $entity->hasField($parent_reference_field) && $referenced_entity->getEntityTypeId() == 'node') {
$field = $entity->get($parent_reference_field);
if (!$field->isEmpty()) {
$nids = $field->getValue();
diff --git a/src/Plugin/Field/FieldFormatter/IslandoraImageFormatter.php b/src/Plugin/Field/FieldFormatter/IslandoraImageFormatter.php
index deb6c7690..ffe6d47a2 100644
--- a/src/Plugin/Field/FieldFormatter/IslandoraImageFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/IslandoraImageFormatter.php
@@ -6,9 +6,11 @@
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\File\FileUrlGeneratorInterface;
+use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatter;
use Drupal\islandora\IslandoraUtils;
+use Drupal\islandora\MediaSource\MediaSourceService;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -34,6 +36,13 @@ class IslandoraImageFormatter extends ImageFormatter {
*/
protected $utils;
+ /**
+ * Islandora media source service.
+ *
+ * @var \Drupal\islandora\MediaSource\MediaSourceService
+ */
+ protected $mediaSourceService;
+
/**
* Constructs an IslandoraImageFormatter object.
*
@@ -59,6 +68,8 @@ class IslandoraImageFormatter extends ImageFormatter {
* Islandora utils.
* @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator
* The File URL Generator.
+ * @param \Drupal\islandora\MediaSource\MediaSourceService $media_source_service
+ * Utils to get the source file from media.
*/
public function __construct(
$plugin_id,
@@ -71,7 +82,8 @@ public function __construct(
AccountInterface $current_user,
EntityStorageInterface $image_style_storage,
IslandoraUtils $utils,
- FileUrlGeneratorInterface $file_url_generator
+ FileUrlGeneratorInterface $file_url_generator,
+ MediaSourceService $media_source_service
) {
parent::__construct(
$plugin_id,
@@ -86,6 +98,7 @@ public function __construct(
$file_url_generator
);
$this->utils = $utils;
+ $this->mediaSourceService = $media_source_service;
}
/**
@@ -103,10 +116,40 @@ public static function create(ContainerInterface $container, array $configuratio
$container->get('current_user'),
$container->get('entity_type.manager')->getStorage('image_style'),
$container->get('islandora.utils'),
- $container->get('file_url_generator')
+ $container->get('file_url_generator'),
+ $container->get('islandora.media_source_service')
);
}
+ /**
+ * {@inheritdoc}
+ */
+ public static function defaultSettings() {
+ return [
+ 'image_alt_text' => 'local',
+ ] + parent::defaultSettings();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function settingsForm(array $form, FormStateInterface $form_state) {
+ $element = parent::settingsForm($form, $form_state);
+ $alt_text_options = [
+ 'local' => $this->t('Local'),
+ 'original_file_fallback' => $this->t('Local, with fallback to Original File'),
+ 'original_file' => $this->t('Original File'),
+ ];
+ $element['image_alt_text'] = [
+ '#title' => $this->t('Alt text source'),
+ '#type' => 'select',
+ '#default_value' => $this->getSetting('image_alt_text'),
+ '#empty_option' => $this->t('None'),
+ '#options' => $alt_text_options,
+ ];
+ return $element;
+ }
+
/**
* {@inheritdoc}
*/
@@ -114,28 +157,68 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = parent::viewElements($items, $langcode);
$image_link_setting = $this->getSetting('image_link');
- // Check if the formatter involves a link.
- if ($image_link_setting != 'content') {
+ $alt_text_setting = $this->getsetting('image_alt_text');
+
+ // Check if we can leave the image as-is:
+ if ($image_link_setting !== 'content' && $alt_text_setting === 'local') {
return $elements;
}
-
$entity = $items->getEntity();
- if ($entity->isNew() || $entity->getEntityTypeId() != 'media') {
+ if ($entity->isNew() || $entity->getEntityTypeId() !== 'media') {
return $elements;
}
- $node = $this->utils->getParentNode($entity);
-
- if ($node === NULL) {
- return $elements;
+ if ($alt_text_setting === 'none') {
+ foreach ($elements as $element) {
+ $element['#item']->set('alt', '');
+ }
}
- $url = $node->toUrl();
+ if ($image_link_setting === 'content' || $alt_text_setting === 'original_file' || $alt_text_setting === 'original_file_fallback') {
+ $node = $this->utils->getParentNode($entity);
+ if ($node === NULL) {
+ return $elements;
+ }
- foreach ($elements as &$element) {
- $element['#url'] = $url;
- }
+ if ($image_link_setting === 'content') {
+ // Set image link.
+ $url = $node->toUrl();
+ foreach ($elements as &$element) {
+ $element['#url'] = $url;
+ }
+ unset($element);
+ }
+
+ if ($alt_text_setting === 'original_file' || $alt_text_setting === 'original_file_fallback') {
+ $original_file_term = $this->utils->getTermForUri("http://pcdm.org/use#OriginalFile");
+ if ($original_file_term !== NULL) {
+ $original_file_media = $this->utils->getMediaWithTerm($node, $original_file_term);
+
+ if ($original_file_media !== NULL) {
+ $source_field_name = $this->mediaSourceService->getSourceFieldName($original_file_media->bundle());
+ if ($original_file_media->hasField($source_field_name)) {
+ $original_file_files = $original_file_media->get($source_field_name);
+ // XXX: Support the multifile media use case where there could
+ // be multiple files in the source field.
+ $i = 0;
+ foreach ($original_file_files as $file) {
+ if (isset($file->alt)) {
+ $alt_text = $file->get('alt')->getValue();
+ if (isset($elements[$i])) {
+ $element = $elements[$i];
+ if ($alt_text_setting === 'original_file' || $element['#item']->get('alt')->getValue() === '') {
+ $elements[$i]['#item']->set('alt', $alt_text);
+ }
+ $i++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
return $elements;
}
diff --git a/src/Plugin/views/filter/NodeHasMediaUse.php b/src/Plugin/views/filter/NodeHasMediaUse.php
index 3c69bddd5..1686c4217 100644
--- a/src/Plugin/views/filter/NodeHasMediaUse.php
+++ b/src/Plugin/views/filter/NodeHasMediaUse.php
@@ -2,8 +2,13 @@
namespace Drupal\islandora\Plugin\views\filter;
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
+use Drupal\islandora\IslandoraUtils;
use Drupal\views\Plugin\views\filter\FilterPluginBase;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Views Filter on Having Media of a Type.
@@ -14,6 +19,48 @@
*/
class NodeHasMediaUse extends FilterPluginBase {
+ /**
+ * Islandora's utility service.
+ *
+ * @var \Drupal\islandora\IslandoraUtils
+ */
+ protected IslandoraUtils $utils;
+
+ /**
+ * Drupal's entity type manager service.
+ *
+ * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+ */
+ protected EntityTypeManagerInterface $entityTypeManager;
+
+ /**
+ * Drupal's database connection service.
+ *
+ * @var \Drupal\Core\Database\Connection
+ */
+ protected Connection $connection;
+
+ /**
+ * Logger service.
+ *
+ * @var \Psr\Log\LoggerInterface
+ */
+ protected LoggerInterface $logger;
+
+ /**
+ * {@inheritDoc}
+ */
+ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+ $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
+
+ $instance->utils = $container->get('islandora.utils');
+ $instance->entityTypeManager = $container->get('entity_type.manager');
+ $instance->connection = $container->get('database');
+ $instance->logger = $container->get('logger.factory')->get('islanodra');
+
+ return $instance;
+ }
+
/**
* {@inheritdoc}
*/
@@ -29,7 +76,7 @@ protected function defineOptions() {
*/
public function validateOptionsForm(&$form, FormStateInterface $form_state) {
$uri = $form_state->getValues()['options']['use_uri'];
- $term = \Drupal::service('islandora.utils')->getTermForUri($uri);
+ $term = $this->utils->getTermForUri($uri);
if (empty($term)) {
$form_state->setError($form['use_uri'], $this->t('Could not find term with URI: "%uri"', ['%uri' => $uri]));
}
@@ -39,7 +86,7 @@ public function validateOptionsForm(&$form, FormStateInterface $form_state) {
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
- $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['vid' => 'islandora_media_use']);
+ $terms = $this->entityTypeManager->getStorage('taxonomy_term')->loadByProperties(['vid' => 'islandora_media_use']);
$uris = [];
foreach ($terms as $term) {
foreach ($term->get('field_external_uri')->getValue() as $uri) {
@@ -67,7 +114,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
*/
public function adminSummary() {
$operator = ($this->options['negated']) ? "does not have" : "has";
- $term = \Drupal::service('islandora.utils')->getTermForUri($this->options['use_uri']);
+ $term = $this->utils->getTermForUri($this->options['use_uri']);
$label = (empty($term)) ? 'BROKEN TERM URI' : $term->label();
return "Node {$operator} a '{$label}' media";
}
@@ -77,18 +124,21 @@ public function adminSummary() {
*/
public function query() {
$condition = ($this->options['negated']) ? 'NOT IN' : 'IN';
- $utils = \Drupal::service('islandora.utils');
- $term = $utils->getTermForUri($this->options['use_uri']);
+ $term = $this->utils->getTermForUri($this->options['use_uri']);
if (empty($term)) {
- \Drupal::logger('islandora')->warning('Node Has Media Filter could not find term with URI: "%uri"', ['%uri' => $this->options['use_uri']]);
+ $this->logger->warning('Node Has Media Filter could not find term with URI: "%uri"', ['%uri' => $this->options['use_uri']]);
return;
}
- $sub_query = \Drupal::database()->select('media', 'm');
- $sub_query->join('media__field_media_use', 'use', 'm.mid = use.entity_id');
- $sub_query->join('media__field_media_of', 'of', 'm.mid = of.entity_id');
- $sub_query->fields('of', ['field_media_of_target_id'])
- ->condition('use.field_media_use_target_id', $term->id());
- $this->query->addWhere(0, 'nid', $sub_query, $condition);
+ $sub_query = $this->connection->select('media', 'm');
+ $use_alias = $sub_query->join('media__field_media_use', 'use', 'm.mid = %alias.entity_id');
+ $of_alias = $sub_query->join('media__field_media_of', 'of', 'm.mid = %alias.entity_id');
+ $sub_query->fields($of_alias, ['field_media_of_target_id'])
+ ->condition("{$use_alias}.field_media_use_target_id", $term->id());
+
+ /** @var \Drupal\views\Plugin\views\query\Sql $query */
+ $query = $this->query;
+ $alias = $query->ensureTable('node_field_data', $this->relationship);
+ $query->addWhere(0, "{$alias}.nid", $sub_query, $condition);
}
}
diff --git a/src/PresetReaction/PresetReaction.php b/src/PresetReaction/PresetReaction.php
index 98aa69462..4ebd68235 100644
--- a/src/PresetReaction/PresetReaction.php
+++ b/src/PresetReaction/PresetReaction.php
@@ -7,6 +7,7 @@
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -21,12 +22,20 @@ class PresetReaction extends ContextReactionPluginBase implements ContainerFacto
*/
protected $actionStorage;
+ /**
+ * The logger.
+ *
+ * @var \Psr\Log\LoggerInterface
+ */
+ protected $logger;
+
/**
* {@inheritdoc}
*/
- public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $action_storage) {
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $action_storage, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->actionStorage = $action_storage;
+ $this->logger = $logger;
}
/**
@@ -37,7 +46,8 @@ public static function create(ContainerInterface $container, array $configuratio
$configuration,
$plugin_id,
$plugin_definition,
- $container->get('entity_type.manager')->getStorage('action')
+ $container->get('entity_type.manager')->getStorage('action'),
+ $container->get('logger.factory')->get('islandora')
);
}
@@ -56,7 +66,20 @@ public function execute(EntityInterface $entity = NULL) {
$action_ids = $config['actions'];
foreach ($action_ids as $action_id) {
$action = $this->actionStorage->load($action_id);
- $action->execute([$entity]);
+ if (empty($action)) {
+ $this->logger->warning('Action "@action" not found.', ['@action' => $action_id]);
+ continue;
+ }
+ try {
+ $action->execute([$entity]);
+ }
+ catch (\Exception $e) {
+ $this->logger->error('Error executing action "@action" on entity "@entity": @message', [
+ '@action' => $action->label(),
+ '@entity' => $entity->label(),
+ '@message' => $e->getMessage(),
+ ]);
+ }
}
}
diff --git a/tests/modules/integer_weight_test_views/test_views/views.view.test_integer_weight.yml b/tests/modules/integer_weight_test_views/test_views/views.view.test_integer_weight.yml
index 08dc4912a..9ccb76a81 100644
--- a/tests/modules/integer_weight_test_views/test_views/views.view.test_integer_weight.yml
+++ b/tests/modules/integer_weight_test_views/test_views/views.view.test_integer_weight.yml
@@ -4,6 +4,7 @@ dependencies:
config:
- node.type.repo_item
module:
+ - islandora
- node
- user
id: test_integer_weight
@@ -13,87 +14,36 @@ description: ''
tag: ''
base_table: node_field_data
base_field: nid
-core: 8.x
display:
default:
- display_plugin: default
id: default
display_title: Master
+ display_plugin: default
position: 0
display_options:
- access:
- type: perm
- options:
- perm: 'access content'
- cache:
- type: tag
- options: { }
- query:
- type: views_query
- options:
- disable_sql_rewrite: false
- distinct: false
- replica: false
- query_comment: ''
- query_tags: { }
- exposed_form:
- type: basic
- options:
- submit_button: Apply
- reset_button: false
- reset_button_label: Reset
- exposed_sorts_label: 'Sort by'
- expose_sort_order: true
- sort_asc_label: Asc
- sort_desc_label: Desc
- pager:
- type: mini
- options:
- items_per_page: 10
- offset: 0
- id: 0
- total_pages: null
- expose:
- items_per_page: false
- items_per_page_label: 'Items per page'
- items_per_page_options: '5, 10, 25, 50'
- items_per_page_options_all: false
- items_per_page_options_all_label: '- All -'
- offset: false
- offset_label: Offset
- tags:
- previous: ‹‹
- next: ››
- style:
- type: table
- row:
- type: fields
+ title: 'test weight'
fields:
title:
id: title
table: node_field_data
field: title
+ relationship: none
+ group_type: group
+ admin_label: ''
entity_type: node
entity_field: title
+ plugin_id: field
+ label: Title
+ exclude: false
alter:
alter_text: false
make_link: false
absolute: false
- trim: false
word_boundary: false
ellipsis: false
strip_tags: false
+ trim: false
html: false
- hide_empty: false
- empty_zero: false
- settings:
- link_to_entity: true
- plugin_id: field
- relationship: none
- group_type: group
- admin_label: ''
- label: Title
- exclude: false
element_type: ''
element_class: ''
element_label_type: ''
@@ -103,9 +53,13 @@ display:
element_wrapper_class: ''
element_default_classes: true
empty: ''
+ hide_empty: false
+ empty_zero: false
hide_alter_empty: true
click_sort_column: value
type: string
+ settings:
+ link_to_entity: true
group_column: value
group_columns: { }
group_rows: true
@@ -123,7 +77,8 @@ display:
relationship: none
group_type: group
admin_label: ''
- label: 'Integer weight selector (field_integer_weight)'
+ plugin_id: integer_weight_selector
+ label: 'Integer Weight Selector (field_integer_weight)'
exclude: false
alter:
alter_text: false
@@ -164,44 +119,57 @@ display:
hide_empty: false
empty_zero: false
hide_alter_empty: true
- range: '20'
- plugin_id: integer_weight_selector
- filters:
- status:
- value: '1'
- table: node_field_data
- field: status
- plugin_id: boolean
- entity_type: node
- entity_field: status
- id: status
+ pager:
+ type: mini
+ options:
+ offset: 0
+ items_per_page: 10
+ total_pages: null
+ id: 0
+ tags:
+ next: ››
+ previous: ‹‹
expose:
- operator: ''
- group: 1
- type:
- id: type
- table: node_field_data
- field: type
- value:
- repo_item:repo_item
- entity_type: node
- entity_field: type
- plugin_id: bundle
+ items_per_page: false
+ items_per_page_label: 'Items per page'
+ items_per_page_options: '5, 10, 25, 50'
+ items_per_page_options_all: false
+ items_per_page_options_all_label: '- All -'
+ offset: false
+ offset_label: Offset
+ exposed_form:
+ type: basic
+ options:
+ submit_button: Apply
+ reset_button: false
+ reset_button_label: Reset
+ exposed_sorts_label: 'Sort by'
+ expose_sort_order: true
+ sort_asc_label: Asc
+ sort_desc_label: Desc
+ access:
+ type: perm
+ options:
+ perm: 'access content'
+ cache:
+ type: tag
+ options: { }
+ empty: { }
sorts:
created:
id: created
table: node_field_data
field: created
- order: DESC
- entity_type: node
- entity_field: created
- plugin_id: date
relationship: none
group_type: group
admin_label: ''
- exposed: false
+ entity_type: node
+ entity_field: created
+ plugin_id: date
+ order: DESC
expose:
label: ''
+ exposed: false
granularity: second
field_integer_weight_value:
id: field_integer_weight_value
@@ -210,17 +178,82 @@ display:
relationship: none
group_type: group
admin_label: ''
+ plugin_id: standard
order: ASC
+ expose:
+ label: ''
+ field_identifier: ''
+ exposed: false
+ arguments: { }
+ filters:
+ status:
+ id: status
+ table: node_field_data
+ field: status
+ entity_type: node
+ entity_field: status
+ plugin_id: boolean
+ value: '1'
+ group: 1
+ expose:
+ operator: ''
+ type:
+ id: type
+ table: node_field_data
+ field: type
+ relationship: none
+ group_type: group
+ admin_label: ''
+ entity_type: node
+ entity_field: type
+ plugin_id: bundle
+ operator: in
+ value:
+ repo_item: repo_item
+ group: 1
exposed: false
expose:
+ operator_id: ''
label: ''
- plugin_id: standard
- title: 'test weight'
+ description: ''
+ use_operator: false
+ operator: ''
+ operator_limit_selection: false
+ operator_list: { }
+ identifier: ''
+ required: false
+ remember: false
+ multiple: false
+ remember_roles:
+ authenticated: authenticated
+ reduce: false
+ is_grouped: false
+ group_info:
+ label: ''
+ description: ''
+ identifier: ''
+ optional: true
+ widget: select
+ multiple: false
+ remember: false
+ default_group: All
+ default_group_multiple: { }
+ group_items: { }
+ style:
+ type: table
+ row:
+ type: fields
+ query:
+ type: views_query
+ options:
+ query_comment: ''
+ disable_sql_rewrite: false
+ distinct: false
+ replica: false
+ query_tags: { }
+ relationships: { }
header: { }
footer: { }
- empty: { }
- relationships: { }
- arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
@@ -232,9 +265,9 @@ display:
- user.permissions
tags: { }
page_1:
- display_plugin: page
id: page_1
display_title: Page
+ display_plugin: page
position: 1
display_options:
display_extenders: { }
diff --git a/tests/src/Functional/DeleteMediaTest.php b/tests/src/Functional/DeleteMediaTest.php
index c52eca31f..76298501a 100644
--- a/tests/src/Functional/DeleteMediaTest.php
+++ b/tests/src/Functional/DeleteMediaTest.php
@@ -50,12 +50,7 @@ class DeleteMediaTest extends IslandoraFunctionalTestBase {
public function setUp(): void {
parent::setUp();
- if (version_compare(\Drupal::VERSION, '10.1', '>=')) {
- $permissions = ['create media', 'delete any media', 'delete any file'];
- }
- else {
- $permissions = ['create media', 'delete any media'];
- }
+ $permissions = ['create media', 'delete any media', 'delete any file'];
// Create a test user.
$this->account = $this->createUser($permissions);
@@ -93,7 +88,7 @@ public function testDeleteMediaAndFile() {
$this->assertSession()->pageTextContains('Are you sure you want to delete this media and associated files?');
$page->pressButton('Delete');
// Should assert that a media and file were deleted.
- $this->assertSession()->pageTextContains('Deleted 2 items.');
+ $this->assertSession()->pageTextContains("The media with the id $mid has been deleted");
// Attempt to reload the entities.
// Both media and file should be gone.
diff --git a/tests/src/Functional/JsonldTypeAlterReactionTest.php b/tests/src/Functional/JsonldTypeAlterReactionTest.php
index 6ac70d7da..7e2005842 100644
--- a/tests/src/Functional/JsonldTypeAlterReactionTest.php
+++ b/tests/src/Functional/JsonldTypeAlterReactionTest.php
@@ -26,15 +26,7 @@ public function testMappingReaction() {
// Add the typed predicate we will select in the reaction config.
// Taken from FieldUiTestTrait->fieldUIAddNewField.
- if (version_compare(\Drupal::VERSION, '10.2.x-dev', 'lt')) {
- $this->submitForm([
- 'new_storage_type' => 'string',
- 'label' => 'Typed Predicate',
- 'field_name' => 'type_predicate',
- ], 'Save and continue');
- $this->submitForm([], 'Save field settings');
- }
- elseif (version_compare(\Drupal::VERSION, '10.3.x-dev', 'lt')) {
+ if (version_compare(\Drupal::VERSION, '10.3.x-dev', 'lt')) {
$this->getSession()->getPage()->selectFieldOption('new_storage_type', 'plain_text');
// For Drupal 10.2, we first need to submit the form with the elements
// displayed on initial page load. The form is using AJAX to send a
diff --git a/tests/src/FunctionalJavascript/IntegerWeightTest.php b/tests/src/FunctionalJavascript/IntegerWeightTest.php
index 2572c191e..5e10133c4 100644
--- a/tests/src/FunctionalJavascript/IntegerWeightTest.php
+++ b/tests/src/FunctionalJavascript/IntegerWeightTest.php
@@ -8,6 +8,7 @@
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\Node;
+use Drupal\views\Tests\ViewTestData;
/**
* Test integer weight selector.
@@ -30,6 +31,7 @@ class IntegerWeightTest extends WebDriverTestBase {
'views',
'field_ui',
'integer_weight_test_views',
+ 'islandora',
];
/**
@@ -82,27 +84,16 @@ class IntegerWeightTest extends WebDriverTestBase {
*/
public function setUp(): void {
parent::setUp();
+ $this->drupalCreateContentType([
+ 'type' => 'repo_item',
+ 'name' => 'Repository Item',
+ ]);
- $this->adminUser = $this->drupalCreateUser(
- [
- 'administer content types',
- 'administer node fields',
- 'administer node display',
- ]
- );
-
- // Create dummy repo_item type to sort (since we don't have
- // repository_object without islandora_defaults).
- $type = $this->container->get('entity_type.manager')->getStorage('node_type')
- ->create([
- 'type' => 'repo_item',
- 'name' => 'Repository Item',
- ]);
- $type->save();
- $this->container->get('router.builder')->rebuild();
+ $account = $this->createUser(['edit any repo_item content'], 'test', TRUE);
+ $this->drupalLogin($account);
$fieldStorage = FieldStorageConfig::create([
- 'fieldName' => static::$fieldName,
+ 'field_name' => static::$fieldName,
'entity_type' => 'node',
'type' => static::$fieldType,
]);
@@ -124,16 +115,18 @@ public function setUp(): void {
$this->nodes[] = $node;
}
- ViewsTestData::createTestViews(get_class($this), ['integer_weight_test_views']);
+ ViewTestData::createTestViews(get_class($this), ['integer_weight_test_views']);
}
/**
* Test integer weight selector.
*/
public function testIntegerWeightSelector() {
- $this->drupalGet('test-integer-weight');
- $page = $this->getSession()->getPage();
+ $web_assert = $this->assertSession();
+ $this->drupalGet('/test-integer-weight');
+ $web_assert->pageTextContains('Item 1');
+ $page = $this->getSession()->getPage();
$weight_select1 = $page->findField("field_integer_weight[0][weight]");
$weight_select2 = $page->findField("field_integer_weight[1][weight]");
$weight_select3 = $page->findField("field_integer_weight[2][weight]");
@@ -153,8 +146,8 @@ public function testIntegerWeightSelector() {
$this->assertSession()->pageTextNotContains('You have unsaved changes.');
// Drag and drop 'Item 1' over 'Item 2'.
- $dragged = $this->xpath("//tr[@class='draggable'][1]//a[@class='tabledrag-handle']")[0];
- $target = $this->xpath("//tr[@class='draggable'][2]//a[@class='tabledrag-handle']")[0];
+ $dragged = $this->xpath("//tr[contains(@class, 'draggable')][1]//a[contains(@class, 'tabledrag-handle')]")[0];
+ $target = $this->xpath("//tr[contains(@class, 'draggable')][2]//a[contains(@class, 'tabledrag-handle')]")[0];
$dragged->dragTo($target);
// Pause for javascript to do it's thing.