Browse Source

Demo implementation

pull/756/head
DiegoPino 9 years ago
parent
commit
07e3c2f6c5
  1. 24
      config/schema/fedora_resource_type.schema.yml
  2. 62
      fedora_resource.page.inc
  3. 14
      islandoraclaw.info.yml
  4. 11
      islandoraclaw.links.action.yml
  5. 16
      islandoraclaw.links.menu.yml
  6. 17
      islandoraclaw.links.task.yml
  7. 58
      islandoraclaw.module
  8. 19
      islandoraclaw.permissions.yml
  9. 97
      src/Controller/FedoraResourceAddController.php
  10. 391
      src/Entity/FedoraResource.php
  11. 58
      src/Entity/FedoraResourceType.php
  12. 28
      src/Entity/FedoraResourceViewsData.php
  13. 22
      src/FedoraResource.php
  14. 47
      src/FedoraResourceAccessControlHandler.php
  15. 149
      src/FedoraResourceHtmlRouteProvider.php
  16. 85
      src/FedoraResourceInterface.php
  17. 45
      src/FedoraResourceListBuilder.php
  18. 96
      src/FedoraResourceTypeHtmlRouteProvider.php
  19. 13
      src/FedoraResourceTypeInterface.php
  20. 32
      src/FedoraResourceTypeListBuilder.php
  21. 15
      src/Form/FedoraResourceDeleteForm.php
  22. 48
      src/Form/FedoraResourceForm.php
  23. 55
      src/Form/FedoraResourceSettingsForm.php
  24. 53
      src/Form/FedoraResourceTypeDeleteForm.php
  25. 67
      src/Form/FedoraResourceTypeForm.php
  26. 842
      src/Plugin/Search/FedoraEntitySearch.php
  27. 23
      templates/fedora-resource-content-add-list.html.twig
  28. 22
      templates/fedora_resource.html.twig

24
config/schema/fedora_resource_type.schema.yml

@ -0,0 +1,24 @@
islandoraclaw.fedora_resource_type.*:
type: config_entity
label: 'Fedora resource type config'
mapping:
id:
type: string
label: 'ID'
label:
type: label
label: 'Label'
uuid:
type: string
# Plugin \Drupal\islandoraclaw\Plugin\Search\FedoraResourceSearch
search.plugin.node_search:
type: mapping
label: 'Fedora Resource search'
mapping:
rankings:
type: sequence
label: 'Content ranking'
sequence:
type: integer
label: 'Influence'

62
fedora_resource.page.inc

@ -0,0 +1,62 @@
<?php
/**
* @file
* Contains fedora_resource.page.inc.
*
* Page callback for Fedora resource entities.
*/
use Drupal\Core\Render\Element;
use Drupal\Core\Link;
use Drupal\Core\Url;
/**
* Prepares variables for Fedora resource templates.
*
* Default template: fedora_resource.html.twig.
*
* @param array $variables
* An associative array containing:
* - elements: An associative array containing the user information and any
* - attributes: HTML attributes for the containing element.
*/
function template_preprocess_fedora_resource(array &$variables) {
// Fetch FedoraResource Entity Object.
$fedora_resource = $variables['elements']['#fedora_resource'];
// Helpful $content variable for templates.
foreach (Element::children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
}
}
/**
* Prepares variables for a custom entity type creation list templates.
*
* Default template: fedora_resource-content-add-list.html.twig.
*
* @param array $variables
* An associative array containing:
* - content: An array of fedora_resource-types.
*
* @see block_content_add_page()
*/
function template_preprocess_fedora_resource_content_add_list(&$variables) {
$variables['types'] = array();
$query = \Drupal::request()->query->all();
foreach ($variables['content'] as $type) {
$variables['types'][$type->id()] = array(
'link' => Link::fromTextAndUrl($type->label(), new Url('entity.fedora_resource.add_form', array(
'fedora_resource_type' => $type->id()
), array('query' => $query))),
'description' => array(
'#markup' => $type->label(),
),
'title' => $type->label(),
'localized_options' => array(
'query' => $query,
),
);
}
}

14
islandoraclaw.info.yml

@ -0,0 +1,14 @@
# This .info.yml files provides the basic information about our module to Drupal
# More: https://www.drupal.org/node/2000204
name: Islandora CLAW
description: 'Learning Drupal 8 with Islandora Claw'
type: module
package: Islandora
core: 8.x
dependencies:
- block
- node
- path
- text
- options
version: '8.x-2.x-dev'

11
islandoraclaw.links.action.yml

@ -0,0 +1,11 @@
entity.fedora_resource.add_form:
route_name: 'fedora_resource.add_page'
title: 'Add Fedora resource'
appears_on:
- entity.fedora_resource.collection
entity.fedora_resource_type.add_form:
route_name: 'entity.fedora_resource_type.add_form'
title: 'Add Fedora resource type'
appears_on:
- entity.fedora_resource_type.collection

16
islandoraclaw.links.menu.yml

@ -0,0 +1,16 @@
# Fedora resource menu items definition
entity.fedora_resource.collection:
title: 'Fedora resource list'
route_name: entity.fedora_resource.collection
description: 'List Fedora resource entities'
parent: system.admin_structure
weight: 100
# Fedora resource type menu items definition
entity.fedora_resource_type.collection:
title: 'Fedora resource type'
route_name: entity.fedora_resource_type.collection
description: 'List Fedora resource type (bundles)'
parent: system.admin_structure
weight: 99

17
islandoraclaw.links.task.yml

@ -0,0 +1,17 @@
# Fedora resource routing definition
entity.fedora_resource.canonical:
route_name: entity.fedora_resource.canonical
base_route: entity.fedora_resource.canonical
title: 'View'
entity.fedora_resource.edit_form:
route_name: entity.fedora_resource.edit_form
base_route: entity.fedora_resource.canonical
title: Edit
entity.fedora_resource.delete_form:
route_name: entity.fedora_resource.delete_form
base_route: entity.fedora_resource.canonical
title: Delete
weight: 10

58
islandoraclaw.module

@ -0,0 +1,58 @@
<?php
/**
* @file
* Contains islandoraclaw.module..
*/
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function islandoraclaw_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the islandoraclaw module.
case 'help.page.islandoraclaw':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('') . '</p>';
return $output;
default:
}
}
/**
* Implements hook_theme().
*/
function islandoraclaw_theme() {
$theme = [];
$theme['fedora_resource'] = [
'render element' => 'elements',
'file' => 'fedora_resource.page.inc',
'template' => 'fedora_resource',
];
$theme['fedora_resource_content_add_list'] = [
'render element' => 'content',
'variables' => ['content' => NULL],
'file' => 'fedora_resource.page.inc',
];
return $theme;
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function islandoraclaw_theme_suggestions_fedora_resource(array $variables) {
$suggestions = array();
$entity = $variables['elements']['#fedora_resource'];
$sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
$suggestions[] = 'fedora_resource__' . $sanitized_view_mode;
$suggestions[] = 'fedora_resource__' . $entity->bundle();
$suggestions[] = 'fedora_resource__' . $entity->bundle() . '__' . $sanitized_view_mode;
$suggestions[] = 'fedora_resource__' . $entity->id();
$suggestions[] = 'fedora_resource__' . $entity->id() . '__' . $sanitized_view_mode;
return $suggestions;
}

19
islandoraclaw.permissions.yml

@ -0,0 +1,19 @@
add fedora resource entities:
title: 'Create new Fedora resource entities'
administer fedora resource entities:
title: 'Administer Fedora resource entities'
description: 'Allow to access the administration form to configure Fedora resource entities.'
restrict access: true
delete fedora resource entities:
title: 'Delete Fedora resource entities'
edit fedora resource entities:
title: 'Edit Fedora resource entities'
view published fedora resource entities:
title: 'View published Fedora resource entities'
view unpublished fedora resource entities:
title: 'View unpublished Fedora resource entities'

97
src/Controller/FedoraResourceAddController.php

@ -0,0 +1,97 @@
<?php
namespace Drupal\islandoraclaw\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class FedoraResourceAddController.
*
* @package Drupal\islandoraclaw\Controller
*/
class FedoraResourceAddController extends ControllerBase {
public function __construct(EntityStorageInterface $storage, EntityStorageInterface $type_storage) {
$this->storage = $storage;
$this->typeStorage = $type_storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
/** @var EntityTypeManagerInterface $entity_type_manager */
$entity_type_manager = $container->get('entity_type.manager');
return new static(
$entity_type_manager->getStorage('fedora_resource'),
$entity_type_manager->getStorage('fedora_resource_type')
);
}
/**
* Displays add links for available bundles/types for entity fedora_resource .
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request object.
*
* @return array
* A render array for a list of the fedora_resource bundles/types that can be added or
* if there is only one type/bunlde defined for the site, the function returns the add page for that bundle/type.
*/
public function add(Request $request) {
$types = $this->typeStorage->loadMultiple();
if ($types && count($types) == 1) {
$type = reset($types);
return $this->addForm($type, $request);
}
if (count($types) === 0) {
return array(
'#markup' => $this->t('You have not created any %bundle types yet. @link to add a new type.', [
'%bundle' => 'Fedora resource',
'@link' => $this->l($this->t('Go to the type creation page'), Url::fromRoute('entity.fedora_resource_type.add_form')),
]),
);
}
return array('#theme' => 'fedora_resource_content_add_list', '#content' => $types);
}
/**
* Presents the creation form for fedora_resource entities of given bundle/type.
*
* @param EntityInterface $fedora_resource_type
* The custom bundle to add.
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request object.
*
* @return array
* A form array as expected by drupal_render().
*/
public function addForm(EntityInterface $fedora_resource_type, Request $request) {
$entity = $this->storage->create(array(
'type' => $fedora_resource_type->id()
));
return $this->entityFormBuilder()->getForm($entity);
}
/**
* Provides the page title for this controller.
*
* @param EntityInterface $fedora_resource_type
* The custom bundle/type being added.
*
* @return string
* The page title.
*/
public function getAddFormTitle(EntityInterface $fedora_resource_type) {
return t('Create of bundle @label',
array('@label' => $fedora_resource_type->label())
);
}
}

391
src/Entity/FedoraResource.php

@ -0,0 +1,391 @@
<?php
namespace Drupal\islandoraclaw\Entity;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\islandoraclaw\FedoraResourceInterface;
use Drupal\user\UserInterface;
/**
* Defines the Fedora resource entity.
*
* @ingroup islandoraclaw
*
* @ContentEntityType(
* id = "fedora_resource",
* label = @Translation("Fedora resource"),
* bundle_label = @Translation("Fedora resource type"),
* handlers = {
* "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
* "list_builder" = "Drupal\islandoraclaw\FedoraResourceListBuilder",
* "views_data" = "Drupal\islandoraclaw\Entity\FedoraResourceViewsData",
*
* "form" = {
* "default" = "Drupal\islandoraclaw\Form\FedoraResourceForm",
* "add" = "Drupal\islandoraclaw\Form\FedoraResourceForm",
* "edit" = "Drupal\islandoraclaw\Form\FedoraResourceForm",
* "delete" = "Drupal\islandoraclaw\Form\FedoraResourceDeleteForm",
* },
* "access" = "Drupal\islandoraclaw\FedoraResourceAccessControlHandler",
* "route_provider" = {
* "html" = "Drupal\islandoraclaw\FedoraResourceHtmlRouteProvider",
* },
* },
* base_table = "fedora_resource",
* data_table = "fedora_resource_field_data",
* revision_table = "fedora_resource_revision",
* revision_data_table = "fedora_resource_field_data_revision",
* admin_permission = "administer fedora resource entities",
* entity_keys = {
* "id" = "id",
* "bundle" = "type",
* "label" = "name",
* "uuid" = "uuid",
* "uid" = "user_id",
* "langcode" = "langcode",
* "status" = "status",
* },
* common_reference_target = TRUE,
* permission_granularity = "bundle",
* links = {
* "canonical" = "/admin/structure/fedora_resource/{fedora_resource}",
* "add-form" = "/admin/structure/fedora_resource/add/{fedora_resource_type}",
* "edit-form" = "/admin/structure/fedora_resource/{fedora_resource}/edit",
* "delete-form" = "/admin/structure/fedora_resource/{fedora_resource}/delete",
* "collection" = "/admin/structure/fedora_resource",
* "version-history" = "/admin/structure/{fedora_resource}/revisions",
* "revision" = "/admin/structure/{fedora_resource}/revisions/{node_revision}/view",
* },
* bundle_entity_type = "fedora_resource_type",
* field_ui_base_route = "entity.fedora_resource_type.edit_form"
* )
*/
class FedoraResource extends ContentEntityBase implements FedoraResourceInterface {
use EntityChangedTrait;
/**
* {@inheritdoc}
*/
public static function preCreate(EntityStorageInterface $storage_controller, array &$values) {
parent::preCreate($storage_controller, $values);
$values += array(
'user_id' => \Drupal::currentUser()->id(),
);
}
/**
* {@inheritdoc}
*/
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update);
// Reindex the entity when it is updated. The entity is automatically
// indexed when it is added, simply by being added to the {fedora_resource} table.
// Only required if using the core search index.
if ($update) {
if (\Drupal::moduleHandler()->moduleExists('search')) {
search_mark_for_reindex('fedora_resource_search', $this->id());
}
}
}
/**
* {@inheritdoc}
*/
public function getType() {
return $this->bundle();
}
/**
* {@inheritdoc}
*/
public function getName() {
return $this->get('name')->value;
}
/**
* {@inheritdoc}
*/
public function setName($name) {
$this->set('name', $name);
return $this;
}
/**
* {@inheritdoc}
*/
public function getCreatedTime() {
return $this->get('created')->value;
}
/**
* {@inheritdoc}
*/
public function setCreatedTime($timestamp) {
$this->set('created', $timestamp);
return $this;
}
/**
* {@inheritdoc}
*/
public function getOwner() {
return $this->get('user_id')->entity;
}
/**
* {@inheritdoc}
*/
public function getOwnerId() {
return $this->get('user_id')->target_id;
}
/**
* {@inheritdoc}
*/
public function setOwnerId($uid) {
$this->set('user_id', $uid);
return $this;
}
/**
* {@inheritdoc}
*/
public function setOwner(UserInterface $account) {
$this->set('user_id', $account->id());
return $this;
}
/**
* {@inheritdoc}
*/
public function isPublished() {
return (bool) $this->getEntityKey('status');
}
/**
* {@inheritdoc}
*/
public function setPublished($published) {
$this->set('status', $published ? NODE_PUBLISHED : NODE_NOT_PUBLISHED);
return $this;
}
/**
* Default value callback for 'fedora_has_parent' base field definition.
*
* @see ::baseFieldDefinitions()
*
* @return array
* An array of default values.
*/
public static function getFedoraRoot() {
return array('root');
}
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields['id'] = BaseFieldDefinition::create('integer')
->setLabel(t('ID'))
->setDescription(t('The ID of the Fedora resource entity.'))
->setReadOnly(TRUE);
$fields['type'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Type'))
->setDescription(t('The Fedora resource type/bundle.'))
->setSetting('target_type', 'fedora_resource_type')
->setRequired(TRUE);
$fields['uuid'] = BaseFieldDefinition::create('uuid')
->setLabel(t('UUID'))
->setDescription(t('The UUID of the Fedora resource entity.'))
->setReadOnly(TRUE);
$fields['user_id'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Authored by'))
->setDescription(t('The user ID of author of the Fedora resource entity.'))
->setRevisionable(TRUE)
->setSetting('target_type', 'user')
->setSetting('handler', 'default')
->setDefaultValueCallback('Drupal\node\Entity\Node::getCurrentUserId')
->setTranslatable(TRUE)
->setDisplayOptions('view', array(
'label' => 'hidden',
'type' => 'author',
'weight' => 0,
))
->setDisplayOptions('form', array(
'type' => 'entity_reference_autocomplete',
'weight' => 5,
'settings' => array(
'match_operator' => 'CONTAINS',
'size' => '60',
'autocomplete_type' => 'tags',
'placeholder' => '',
),
))
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['fedora_has_parent'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Fedora has Parent'))
->setDescription(t('Parent Fedora Resource.'))
->setRevisionable(TRUE)
->setSetting('target_type', 'fedora_resource')
->setSetting('handler', 'default')
->setDefaultValueCallback('Drupal\islandoraClaw\Entity\FedoraResource::getFedoraRoot')
->setTranslatable(TRUE)
->setDisplayOptions('view', array(
'label' => 'hidden',
'type' => 'author',
'weight' => 0,
))
->setDisplayOptions('form', array(
'type' => 'entity_reference_autocomplete',
'weight' => 5,
'settings' => array(
'match_operator' => 'CONTAINS',
'size' => '60',
'autocomplete_type' => 'tags',
'placeholder' => '',
),
))
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['ldp_containes'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('LDP Contains'))
->setDescription(t('Contains Fedora Resource.'))
->setRevisionable(TRUE)
->setSetting('target_type', 'fedora_resource_type')
->setSetting('handler', 'default')
->setTranslatable(TRUE)
->setDisplayOptions('view', array(
'label' => 'hidden',
'type' => 'author',
'weight' => 0,
))
->setDisplayOptions('form', array(
'type' => 'entity_reference_autocomplete',
'weight' => 5,
'settings' => array(
'match_operator' => 'CONTAINS',
'size' => '60',
'autocomplete_type' => 'tags',
'placeholder' => '',
),
))
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['name'] = BaseFieldDefinition::create('string')
->setLabel(t('Name'))
->setDescription(t('The name of the Fedora resource entity.'))
->setSettings(array(
'max_length' => 50,
'text_processing' => 0,
))
->setDefaultValue('')
->setDisplayOptions('view', array(
'label' => 'above',
'type' => 'string',
'weight' => -4,
))
->setDisplayOptions('form', array(
'type' => 'string_textfield',
'weight' => -4,
))
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['status'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Publishing status'))
->setDescription(t('A boolean indicating whether the Fedora resource is published.'))
->setDefaultValue(TRUE);
$fields['langcode'] = BaseFieldDefinition::create('language')
->setLabel(t('Language code'))
->setDescription(t('The language code for the Fedora resource entity.'))
->setDisplayOptions('form', array(
'type' => 'language_select',
'weight' => 10,
))
->setDisplayConfigurable('form', TRUE);
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Created'))
->setDescription(t('The time that the entity was created.'));
$fields['changed'] = BaseFieldDefinition::create('changed')
->setLabel(t('Changed'))
->setDescription(t('The time that the entity was last edited.'));
$fields['promote'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Promoted to front page'))
->setRevisionable(TRUE)
->setTranslatable(TRUE)
->setDefaultValue(TRUE)
->setDisplayOptions('form', array(
'type' => 'boolean_checkbox',
'settings' => array(
'display_label' => TRUE,
),
'weight' => 15,
))
->setDisplayConfigurable('form', TRUE);
$fields['sticky'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Sticky at top of lists'))
->setRevisionable(TRUE)
->setTranslatable(TRUE)
->setDefaultValue(FALSE)
->setDisplayOptions('form', array(
'type' => 'boolean_checkbox',
'settings' => array(
'display_label' => TRUE,
),
'weight' => 16,
))
->setDisplayConfigurable('form', TRUE);
$fields['revision_timestamp'] = BaseFieldDefinition::create('created')
->setLabel(t('Revision timestamp'))
->setDescription(t('The time that the current revision was created.'))
->setQueryable(FALSE)
->setRevisionable(TRUE);
$fields['revision_uid'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Revision user ID'))
->setDescription(t('The user ID of the author of the current revision.'))
->setSetting('target_type', 'user')
->setQueryable(FALSE)
->setRevisionable(TRUE);
$fields['revision_log'] = BaseFieldDefinition::create('string_long')
->setLabel(t('Revision log message'))
->setDescription(t('Briefly describe the changes you have made.'))
->setRevisionable(TRUE)
->setDefaultValue('')
->setDisplayOptions('form', array(
'type' => 'string_textarea',
'weight' => 25,
'settings' => array(
'rows' => 4,
),
));
$fields['revision_translation_affected'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Revision translation affected'))
->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
->setReadOnly(TRUE)
->setRevisionable(TRUE)
->setTranslatable(TRUE);
return $fields;
}
}

58
src/Entity/FedoraResourceType.php

@ -0,0 +1,58 @@
<?php
namespace Drupal\islandoraclaw\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
use Drupal\islandoraclaw\FedoraResourceTypeInterface;
/**
* Defines the Fedora resource type entity.
*
* @ConfigEntityType(
* id = "fedora_resource_type",
* label = @Translation("Fedora resource type"),
* handlers = {
* "list_builder" = "Drupal\islandoraclaw\FedoraResourceTypeListBuilder",
* "form" = {
* "add" = "Drupal\islandoraclaw\Form\FedoraResourceTypeForm",
* "edit" = "Drupal\islandoraclaw\Form\FedoraResourceTypeForm",
* "delete" = "Drupal\islandoraclaw\Form\FedoraResourceTypeDeleteForm"
* },
* "route_provider" = {
* "html" = "Drupal\islandoraclaw\FedoraResourceTypeHtmlRouteProvider",
* },
* },
* config_prefix = "fedora_resource_type",
* admin_permission = "administer site configuration",
* bundle_of = "fedora_resource",
* entity_keys = {
* "id" = "id",
* "label" = "label",
* "uuid" = "uuid"
* },
* links = {
* "canonical" = "/admin/structure/fedora_resource_type/{fedora_resource_type}",
* "add-form" = "/admin/structure/fedora_resource_type/add",
* "edit-form" = "/admin/structure/fedora_resource_type/{fedora_resource_type}/edit",
* "delete-form" = "/admin/structure/fedora_resource_type/{fedora_resource_type}/delete",
* "collection" = "/admin/structure/fedora_resource_type"
* }
* )
*/
class FedoraResourceType extends ConfigEntityBundleBase implements FedoraResourceTypeInterface {
/**
* The Fedora resource type ID.
*
* @var string
*/
protected $id;
/**
* The Fedora resource type label.
*
* @var string
*/
protected $label;
}

28
src/Entity/FedoraResourceViewsData.php

@ -0,0 +1,28 @@
<?php
namespace Drupal\islandoraclaw\Entity;
use Drupal\views\EntityViewsData;
use Drupal\views\EntityViewsDataInterface;
/**
* Provides Views data for Fedora resource entities.
*/
class FedoraResourceViewsData extends EntityViewsData implements EntityViewsDataInterface {
/**
* {@inheritdoc}
*/
public function getViewsData() {
$data = parent::getViewsData();
$data['fedora_resource']['table']['base'] = array(
'field' => 'id',
'title' => $this->t('Fedora resource'),
'help' => $this->t('The Fedora resource ID.'),
);
return $data;
}
}

22
src/FedoraResource.php

@ -0,0 +1,22 @@
<?php
/**
* @file
* Contains \Drupal\islandoraclaw\FedoraResourceInterface.
*/
namespace Drupal\islandoraclaw;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\user\EntityOwnerInterface;
use Drupal\Core\Entity\EntityChangedInterface;
/**
* Provides an interface for defining a Fedora 4 Resource entity.
*
* This interface extends multiple ones so we can use all the extended ones at once.
*
* @ingroup islandoraclaw
*/
interface FedoraResourceInterface extends ContentEntityInterface, EntityOwnerInterface, EntityChangedInterface {
}

47
src/FedoraResourceAccessControlHandler.php

@ -0,0 +1,47 @@
<?php
namespace Drupal\islandoraclaw;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessResult;
/**
* Access controller for the Fedora resource entity.
*
* @see \Drupal\islandoraclaw\Entity\FedoraResource.
*/
class FedoraResourceAccessControlHandler extends EntityAccessControlHandler {
/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
/** @var \Drupal\islandoraclaw\FedoraResourceInterface $entity */
switch ($operation) {
case 'view':
if (!$entity->isPublished()) {
return AccessResult::allowedIfHasPermission($account, 'view unpublished fedora resource entities');
}
return AccessResult::allowedIfHasPermission($account, 'view published fedora resource entities');
case 'update':
return AccessResult::allowedIfHasPermission($account, 'edit fedora resource entities');
case 'delete':
return AccessResult::allowedIfHasPermission($account, 'delete fedora resource entities');
}
// Unknown operation, no opinion.
return AccessResult::neutral();
}
/**
* {@inheritdoc}
*/
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
return AccessResult::allowedIfHasPermission($account, 'add fedora resource entities');
}
}

149
src/FedoraResourceHtmlRouteProvider.php

@ -0,0 +1,149 @@
<?php
namespace Drupal\islandoraclaw;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
use Symfony\Component\Routing\Route;
/**
* Provides routes for Fedora resource entities.
*
* @see Drupal\Core\Entity\Routing\AdminHtmlRouteProvider
* @see Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider
*/
class FedoraResourceHtmlRouteProvider extends AdminHtmlRouteProvider {
/**
* {@inheritdoc}
*/
public function getRoutes(EntityTypeInterface $entity_type) {
$collection = parent::getRoutes($entity_type);
$entity_type_id = $entity_type->id();
if ($collection_route = $this->getCollectionRoute($entity_type)) {
$collection->add("entity.{$entity_type_id}.collection", $collection_route);
}
if ($add_form_route = $this->getAddFormRoute($entity_type)) {
$collection->add("entity.{$entity_type_id}.add_form", $add_form_route);
}
$add_page_route = $this->getAddPageRoute($entity_type);
$collection->add("$entity_type_id.add_page", $add_page_route);
if ($settings_form_route = $this->getSettingsFormRoute($entity_type)) {
$collection->add("$entity_type_id.settings", $settings_form_route);
}
return $collection;
}
/**
* Gets the collection route.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return \Symfony\Component\Routing\Route|null
* The generated route, if available.
*/
protected function getCollectionRoute(EntityTypeInterface $entity_type) {
if ($entity_type->hasLinkTemplate('collection') && $entity_type->hasListBuilderClass()) {
$entity_type_id = $entity_type->id();
$route = new Route($entity_type->getLinkTemplate('collection'));
$route
->setDefaults([
'_entity_list' => $entity_type_id,
'_title' => "{$entity_type->getLabel()} list",
])
->setRequirement('_permission', 'view fedora resource entities')
->setOption('_admin_route', TRUE);
return $route;
}
}
/**
* Gets the add-form route.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return \Symfony\Component\Routing\Route|null
* The generated route, if available.
*/
protected function getAddFormRoute(EntityTypeInterface $entity_type) {
if ($entity_type->hasLinkTemplate('add-form')) {
$entity_type_id = $entity_type->id();
$parameters = [
$entity_type_id => ['type' => 'entity:' . $entity_type_id],
];
$route = new Route($entity_type->getLinkTemplate('add-form'));
$bundle_entity_type_id = $entity_type->getBundleEntityType();
// Content entities with bundles are added via a dedicated controller.
$route
->setDefaults([
'_controller' => 'Drupal\islandoraclaw\Controller\FedoraResourceAddController::addForm',
'_title_callback' => 'Drupal\islandoraclaw\Controller\FedoraResourceAddController::getAddFormTitle',
])
->setRequirement('_entity_create_access', $entity_type_id . ':{' . $bundle_entity_type_id . '}');
$parameters[$bundle_entity_type_id] = ['type' => 'entity:' . $bundle_entity_type_id];
$route
->setOption('parameters', $parameters)
->setOption('_admin_route', TRUE);
return $route;
}
}
/**
* Gets the add page route.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return \Symfony\Component\Routing\Route|null
* The generated route, if available.
*/
protected function getAddPageRoute(EntityTypeInterface $entity_type) {
$route = new Route("/admin/structure/{$entity_type->id()}/add");
$route
->setDefaults([
'_controller' => 'Drupal\islandoraclaw\Controller\FedoraResourceAddController::add',
'_title' => "Add {$entity_type->getLabel()}",
])
->setRequirement('_entity_create_access', $entity_type->id())
->setOption('_admin_route', TRUE);
return $route;
}
/**
* Gets the settings form route.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return \Symfony\Component\Routing\Route|null
* The generated route, if available.
*/
protected function getSettingsFormRoute(EntityTypeInterface $entity_type) {
if (!$entity_type->getBundleEntityType()) {
$route = new Route("/admin/structure/{$entity_type->id()}/settings");
$route
->setDefaults([
'_form' => 'Drupal\islandoraclaw\Form\FedoraResourceSettingsForm',
'_title' => "{$entity_type->getLabel()} settings",
])
->setRequirement('_permission', $entity_type->getAdminPermission())
->setOption('_admin_route', TRUE);
return $route;
}
}
}

85
src/FedoraResourceInterface.php

@ -0,0 +1,85 @@
<?php
namespace Drupal\islandoraclaw;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityChangedInterface;
use Drupal\user\EntityOwnerInterface;
/**
* Provides an interface for defining Fedora resource entities.
*
* @ingroup islandoraclaw
*/
interface FedoraResourceInterface extends ContentEntityInterface, EntityChangedInterface, EntityOwnerInterface {
// Add get/set methods for your configuration properties here.
/**
* Gets the Fedora resource type.
*
* @return string
* The Fedora resource type.
*/
public function getType();
/**
* Gets the Fedora resource name.
*
* @return string
* Name of the Fedora resource.
*/
public function getName();
/**
* Sets the Fedora resource name.
*
* @param string $name
* The Fedora resource name.
*
* @return \Drupal\islandoraclaw\FedoraResourceInterface
* The called Fedora resource entity.
*/
public function setName($name);
/**
* Gets the Fedora resource creation timestamp.
*
* @return int
* Creation timestamp of the Fedora resource.
*/
public function getCreatedTime();
/**
* Sets the Fedora resource creation timestamp.
*
* @param int $timestamp
* The Fedora resource creation timestamp.
*
* @return \Drupal\islandoraclaw\FedoraResourceInterface
* The called Fedora resource entity.
*/
public function setCreatedTime($timestamp);
/**
* Returns the Fedora resource published status indicator.
*
* Unpublished Fedora resource are only visible to restricted users.
*
* @return bool
* TRUE if the Fedora resource is published.
*/
public function isPublished();
/**
* Sets the published status of a Fedora resource.
*
* @param bool $published
* TRUE to set this Fedora resource to published, FALSE to set it to unpublished.
*
* @return \Drupal\islandoraclaw\FedoraResourceInterface
* The called Fedora resource entity.
*/
public function setPublished($published);
}

45
src/FedoraResourceListBuilder.php

@ -0,0 +1,45 @@
<?php
namespace Drupal\islandoraclaw;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityListBuilder;
use Drupal\Core\Routing\LinkGeneratorTrait;
use Drupal\Core\Url;
/**
* Defines a class to build a listing of Fedora resource entities.
*
* @ingroup islandoraclaw
*/
class FedoraResourceListBuilder extends EntityListBuilder {
use LinkGeneratorTrait;
/**
* {@inheritdoc}
*/
public function buildHeader() {
$header['id'] = $this->t('Fedora resource ID');
$header['name'] = $this->t('Name');
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity) {
/* @var $entity \Drupal\islandoraclaw\Entity\FedoraResource */
$row['id'] = $entity->id();
$row['name'] = $this->l(
$entity->label(),
new Url(
'entity.fedora_resource.edit_form', array(
'fedora_resource' => $entity->id(),
)
)
);
return $row + parent::buildRow($entity);
}
}

96
src/FedoraResourceTypeHtmlRouteProvider.php

@ -0,0 +1,96 @@
<?php
namespace Drupal\islandoraclaw;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
use Symfony\Component\Routing\Route;
/**
* Provides routes for Fedora resource type entities.
*
* @see Drupal\Core\Entity\Routing\AdminHtmlRouteProvider
* @see Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider
*/
class FedoraResourceTypeHtmlRouteProvider extends AdminHtmlRouteProvider {
/**
* {@inheritdoc}
*/
public function getRoutes(EntityTypeInterface $entity_type) {
$collection = parent::getRoutes($entity_type);
$entity_type_id = $entity_type->id();
if ($collection_route = $this->getCollectionRoute($entity_type)) {
$collection->add("entity.{$entity_type_id}.collection", $collection_route);
}
if ($add_form_route = $this->getAddFormRoute($entity_type)) {
$collection->add("entity.{$entity_type_id}.add_form", $add_form_route);
}
return $collection;
}
/**
* Gets the collection route.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return \Symfony\Component\Routing\Route|null
* The generated route, if available.
*/
protected function getCollectionRoute(EntityTypeInterface $entity_type) {
if ($entity_type->hasLinkTemplate('collection') && $entity_type->hasListBuilderClass()) {
$entity_type_id = $entity_type->id();
$route = new Route($entity_type->getLinkTemplate('collection'));
$route
->setDefaults([
'_entity_list' => $entity_type_id,
// Make sure this is not a TranslatableMarkup object as the
// TitleResolver translates this string again.
'_title' => (string) $entity_type->getLabel(),
])
->setRequirement('_permission', $entity_type->getAdminPermission())
->setOption('_admin_route', TRUE);
return $route;
}
}
/**
* Gets the add-form route.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return \Symfony\Component\Routing\Route|null
* The generated route, if available.
*/
protected function getAddFormRoute(EntityTypeInterface $entity_type) {
if ($entity_type->hasLinkTemplate('add-form')) {
$entity_type_id = $entity_type->id();
$route = new Route($entity_type->getLinkTemplate('add-form'));
// Use the add form handler, if available, otherwise default.
$operation = 'default';
if ($entity_type->getFormClass('add')) {
$operation = 'add';
}
$route
->setDefaults([
'_entity_form' => "{$entity_type_id}.{$operation}",
'_title' => "Add {$entity_type->getLabel()}",
])
->setRequirement('_entity_create_access', $entity_type_id)
->setOption('parameters', [
$entity_type_id => ['type' => 'entity:' . $entity_type_id],
])
->setOption('_admin_route', TRUE);
return $route;
}
}
}

13
src/FedoraResourceTypeInterface.php

@ -0,0 +1,13 @@
<?php
namespace Drupal\islandoraclaw;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
/**
* Provides an interface for defining Fedora resource type entities.
*/
interface FedoraResourceTypeInterface extends ConfigEntityInterface {
// Add get/set methods for your configuration properties here.
}

32
src/FedoraResourceTypeListBuilder.php

@ -0,0 +1,32 @@
<?php
namespace Drupal\islandoraclaw;
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a listing of Fedora resource type entities.
*/
class FedoraResourceTypeListBuilder extends ConfigEntityListBuilder {
/**
* {@inheritdoc}
*/
public function buildHeader() {
$header['label'] = $this->t('Fedora resource type');
$header['id'] = $this->t('Machine name');
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity) {
$row['label'] = $entity->label();
$row['id'] = $entity->id();
// You probably want a few more properties here...
return $row + parent::buildRow($entity);
}
}

15
src/Form/FedoraResourceDeleteForm.php

@ -0,0 +1,15 @@
<?php
namespace Drupal\islandoraclaw\Form;
use Drupal\Core\Entity\ContentEntityDeleteForm;
/**
* Provides a form for deleting Fedora resource entities.
*
* @ingroup islandoraclaw
*/
class FedoraResourceDeleteForm extends ContentEntityDeleteForm {
}

48
src/Form/FedoraResourceForm.php

@ -0,0 +1,48 @@
<?php
namespace Drupal\islandoraclaw\Form;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Form\FormStateInterface;
/**
* Form controller for Fedora resource edit forms.
*
* @ingroup islandoraclaw
*/
class FedoraResourceForm extends ContentEntityForm {
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
/* @var $entity \Drupal\islandoraclaw\Entity\FedoraResource */
$form = parent::buildForm($form, $form_state);
$entity = $this->entity;
return $form;
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$entity = $this->entity;
$status = parent::save($form, $form_state);
switch ($status) {
case SAVED_NEW:
drupal_set_message($this->t('Created the %label Fedora resource.', [
'%label' => $entity->label(),
]));
break;
default:
drupal_set_message($this->t('Saved the %label Fedora resource.', [
'%label' => $entity->label(),
]));
}
$form_state->setRedirect('entity.fedora_resource.canonical', ['fedora_resource' => $entity->id()]);
}
}

55
src/Form/FedoraResourceSettingsForm.php

@ -0,0 +1,55 @@
<?php
namespace Drupal\islandoraclaw\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Class FedoraResourceSettingsForm.
*
* @package Drupal\islandoraclaw\Form
*
* @ingroup islandoraclaw
*/
class FedoraResourceSettingsForm extends FormBase {
/**
* Returns a unique string identifying the form.
*
* @return string
* The unique string identifying the form.
*/
public function getFormId() {
return 'FedoraResource_settings';
}
/**
* Form submission handler.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Empty implementation of the abstract submit class.
}
/**
* Defines the settings form for Fedora resource entities.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @return array
* Form definition array.
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['FedoraResource_settings']['#markup'] = 'Settings form for Fedora resource entities. Manage field settings here.';
return $form;
}
}

53
src/Form/FedoraResourceTypeDeleteForm.php

@ -0,0 +1,53 @@
<?php
namespace Drupal\islandoraclaw\Form;
use Drupal\Core\Entity\EntityConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
/**
* Builds the form to delete Fedora resource type entities.
*/
class FedoraResourceTypeDeleteForm extends EntityConfirmFormBase {
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Are you sure you want to delete %name?', array('%name' => $this->entity->label()));
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('entity.fedora_resource_type.collection');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Delete');
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->entity->delete();
drupal_set_message(
$this->t('content @type: deleted @label.',
[
'@type' => $this->entity->bundle(),
'@label' => $this->entity->label(),
]
)
);
$form_state->setRedirectUrl($this->getCancelUrl());
}
}

67
src/Form/FedoraResourceTypeForm.php

@ -0,0 +1,67 @@
<?php
namespace Drupal\islandoraclaw\Form;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Form\FormStateInterface;
/**
* Class FedoraResourceTypeForm.
*
* @package Drupal\islandoraclaw\Form
*/
class FedoraResourceTypeForm extends EntityForm {
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$fedora_resource_type = $this->entity;
$form['label'] = array(
'#type' => 'textfield',
'#title' => $this->t('Label'),
'#maxlength' => 255,
'#default_value' => $fedora_resource_type->label(),
'#description' => $this->t("Label for the Fedora resource type."),
'#required' => TRUE,
);
$form['id'] = array(
'#type' => 'machine_name',
'#default_value' => $fedora_resource_type->id(),
'#machine_name' => array(
'exists' => '\Drupal\islandoraclaw\Entity\FedoraResourceType::load',
),
'#disabled' => !$fedora_resource_type->isNew(),
);
/* You will need additional form elements for your custom properties. */
return $form;
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$fedora_resource_type = $this->entity;
$status = $fedora_resource_type->save();
switch ($status) {
case SAVED_NEW:
drupal_set_message($this->t('Created the %label Fedora resource type.', [
'%label' => $fedora_resource_type->label(),
]));
break;
default:
drupal_set_message($this->t('Saved the %label Fedora resource type.', [
'%label' => $fedora_resource_type->label(),
]));
}
$form_state->setRedirectUrl($fedora_resource_type->urlInfo('collection'));
}
}

842
src/Plugin/Search/FedoraEntitySearch.php

@ -0,0 +1,842 @@
<?
/**
* @file
* Contains \Drupal\islandoraclaw\Plugin\Search\FedoraEntitySearch.
*/
namespace Drupal\islandoraclaw\Plugin\Search;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Config\Config;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\SelectExtender;
use Drupal\Core\Database\StatementInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessibleInterface;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Render\RendererInterface;
use Drupal\islandoraclaw\FedoraResourceInterface;
use Drupal\search\Plugin\ConfigurableSearchPluginBase;
use Drupal\search\Plugin\SearchIndexingInterface;
use Drupal\search\SearchQuery;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Handles searching for fedora_resource entities.
*
* Demonstrates integration with the search index using
* \Drupal\search\SearchQuery.
* \Drupal\search\SearchQuery adds some search
* features such as automatically including {search_dataset} in the
* query, weighting the the result scores based on the importance of individual
* words, etc.
* If these "extra features" aren't approprite for your custom content entity,
* see \Drupal\user\Plugin\Search\UserSearch as an example
* of not using \Drupal\search\SearchQuery.
*
* USAGE / INSTALLATION:
*
* # Place this plugin in the directory
* fedora_resource/Plugin/Search.
* # Clear caches (drush cr).
* # Add a "Content Entity Example Contacts" search page at
* /admin/config/search/pages and configure it as desired.
* # Confirm that the index status at dmin/config/search/pages
* accurately reflects the number of
* content_entity_example_contact items (the number of "contact"
* entities that you have created, which should be listed at
* /content_entity_example_contact/list
* # Run cron to add your entities to the search index.
*
* @see \Drupal\node\Plugin\Search\NodeSearch
* @see \Drupal\user\Plugin\Search\UserSearch
*
* Annotation for discovery by Search module.
* - 'id': unique machine name for this search plugin.
* Will be used for the `type` field in {search_index} and {search_dataset}.
* - 'title': Translatable title for the search page & navigation tab.
*
* @SearchPlugin(
* id = "fedora_resource_search",
* title = @Translation("fedora resource content search")
* )
*/
class FedoraResourceSearch extends ConfigurableSearchPluginBase implements AccessibleInterface, SearchIndexingInterface {
/**
* A database connection object.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* An entity manager object.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $entityManager;
/**
* A module manager object.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* A config object for 'search.settings'.
*
* @var \Drupal\Core\Config\Config
*/
protected $searchSettings;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The Drupal account to use for checking for access to advanced search.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $account;
/**
* The Renderer service to format the username and entity.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* An array of additional rankings from hook_ranking().
*
* @var array
*/
protected $rankings;
/**
* The list of options and info for advanced search filters.
*
* Each entry in the array has the option as the key and for its value, an
* array that determines how the value is matched in the database query. The
* possible keys in that array are:
* - column: (required) Name of the database column to match against.
* - join: (optional) Information on a table to join. By default the data is
* matched against any tables joined in the $query declaration in
* findResults().
* - operator: (optional) OR or AND, defaults to OR.
*
* For advanced search to work, probably also must modify:
* - buildSearchUrlQuery() to build the redirect URL.
* - searchFormAlter() to add fields to advanced search form.
*
* Note: In our case joins aren't needed because the {contact} table is
* joined in findResults().
*
* @var array
*/
protected $advanced = array(
'name' => array(
'column' => 'c.name',
),
);
/**
* A constant for setting and checking the query string.
*/
const ADVANCED_FORM = 'advanced-form';
/**
* {@inheritdoc}
*/
static public function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('database'),
$container->get('entity.manager'),
$container->get('module_handler'),
$container->get('config.factory')->get('search.settings'),
$container->get('language_manager'),
$container->get('renderer'),
$container->get('current_user')
);
}
/**
* Constructs \Drupal\islandoraclaw\Plugin\Search\FedoraResourceSearch.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Database\Connection $database
* A database connection object.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* An entity manager object.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* A module manager object.
* @param \Drupal\Core\Config\Config $search_settings
* A config object for 'search.settings'.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Session\AccountInterface $account
* The $account object to use for checking for access to advanced search.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, Connection $database, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, Config $search_settings, LanguageManagerInterface $language_manager, RendererInterface $renderer, AccountInterface $account = NULL) {
$this->database = $database;
$this->entityManager = $entity_manager;
$this->moduleHandler = $module_handler;
$this->searchSettings = $search_settings;
$this->languageManager = $language_manager;
$this->renderer = $renderer;
$this->account = $account;
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->addCacheTags(['fedora_resource_list']);
}
/**
* {@inheritdoc}
*/
public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) {
$result = AccessResult::allowedIfHasPermission($account, 'access content');
return $return_as_object ? $result : $result->isAllowed();
}
/**
* {@inheritdoc}
*/
public function isSearchExecutable() {
// Contact search is executable if we have keywords or an advanced
// parameter.
// At least, we should parse out the parameters and see if there are any
// keyword matches in that case, rather than just printing out the
// "Please enter keywords" message.
return !empty($this->keywords) || (isset($this->searchParameters['f']) && count($this->searchParameters['f']));
}
/**
* {@inheritdoc}
*/
public function getType() {
return $this->getPluginId();
}
/**
* {@inheritdoc}
*/
public function execute() {
if ($this->isSearchExecutable()) {
$results = $this->findResults();
if ($results) {
return $this->prepareResults($results);
}
}
return array();
}
/**
* Queries to find search results, and sets status messages.
*
* This method can assume that $this->isSearchExecutable() has already been
* checked and returned TRUE.
*
* @return \Drupal\Core\Database\StatementInterface|null
* Results from search query execute() method, or NULL if the search
* failed.
*/
protected function findResults() {
$keys = $this->keywords;
// Build matching conditions.
$query = $this->database
->select('search_index', 'i', array('target' => 'replica'))
->extend('Drupal\search\SearchQuery')
->extend('Drupal\Core\Database\Query\PagerSelectExtender');
// Join on {contact} and {users_field_data} to get user's published status.
// This join on {contact} also serves the advanced search items
// (in $this->advanced) that are in {contact}.
$query->join('contact', 'c', 'c.id = i.sid');
$query->join('users_field_data', 'ufd', 'ufd.uid = c.user_id');
$query->condition('ufd.status', 1);
$query
->searchExpression($keys, $this->getPluginId());
// @todo ===============
// Handle advanced search filters in the f query string.
// \Drupal::request()->query->get('f') is an array that looks like this in
// the URL: ?f[]=first_name:Jane&f[]=gender:f
// So $parameters['f'] looks like:
// array('first_name:Jane', 'gender:f');
// We need to parse this out into query conditions, some of which go into
// the keywords string, and some of which are separate conditions.
//
// Note: advanced form fields are added in searchFormAlter(),
// and the URL containing the "f" parameter is built in
// buildSearchUrlQuery().
$parameters = $this->getParameters();
if (!empty($parameters['f']) && is_array($parameters['f'])) {
// @todo This loop should probably be moved to a helper function.
$filters = array();
// Match any query value that is an expected option and a value
// separated by ':' like 'first_name:Jane'.
$pattern = '/^(' . implode('|', array_keys($this->advanced)) . '):([^ ]*)/i';
foreach ($parameters['f'] as $item) {
if (preg_match($pattern, $item, $m)) {
// Use the matched value as the array key to eliminate duplicates.
$filters[$m[1]][$m[2]] = $m[2];
}
}
// Now turn these into query conditions. This assumes that everything in
// $filters is a known type of advanced search as defined in
// $this->advanced.
foreach ($filters as $option => $matched) {
$info = $this->advanced[$option];
// Insert additional conditions. By default, all use the OR operator.
$operator = empty($info['operator']) ? 'OR' : $info['operator'];
$where = new Condition($operator);
foreach ($matched as $value) {
$where->condition($info['column'], $value);
}
$query->condition($where);
if (!empty($info['join'])) {
$query->join($info['join']['table'], $info['join']['alias'], $info['join']['condition']);
}
}
}
// ===============
// Add the ranking expressions.
$this->addFedoraResourceRankings($query);
// Run the query.
$find = $query
// Add the language code of the indexed item to the result of the query,
// since the entity will be rendered using the respective language.
->fields('i', array('langcode'))
// And since SearchQuery makes these into GROUP BY queries, if we add
// a field, for PostgreSQL we also need to make it an aggregate or a
// GROUP BY. In this case, we want GROUP BY.
->groupBy('i.langcode')
->limit(10)
->execute();
// Check query status and set messages if needed.
$status = $query->getStatus();
if ($status & SearchQuery::EXPRESSIONS_IGNORED) {
drupal_set_message($this->t('Your search used too many AND/OR expressions. Only the first @count terms were included in this search.', array('@count' => $this->searchSettings->get('and_or_limit'))), 'warning');
}
if ($status & SearchQuery::LOWER_CASE_OR) {
drupal_set_message($this->t('Search for either of the two terms with uppercase OR. For example, cats OR dogs.'), 'warning');
}
if ($status & SearchQuery::NO_POSITIVE_KEYWORDS) {
drupal_set_message($this->formatPlural($this->searchSettings->get('index.minimum_word_size'), 'You must include at least one keyword to match in the content, and punctuation is ignored.', 'You must include at least one keyword to match in the content. Keywords must be at least @count characters, and punctuation is ignored.'), 'warning');
}
return $find;
}
/**
* Prepares search results for rendering.
*
* @param \Drupal\Core\Database\StatementInterface $found
* Results found from a successful search query execute() method.
*
* @return array
* Array of search result item render arrays (empty array if no results).
*/
protected function prepareResults(StatementInterface $found) {
$results = array();
// 'fedora_resource' comes from the entity type id declared
// in the annotation for \Drupal\islandoraclaw\Entity\FedoraResource.
// Replace this with your entity's type id.
$entity_storage = $this->entityManager->getStorage('fedora_resource');
$entity_render = $this->entityManager->getViewBuilder('fedora_resource');
$keys = $this->keywords;
foreach ($found as $item) {
// Render the contact.
/** @var \Drupal\content_entity_example\ContactInterface $entity */
$entity = $entity_storage->load($item->sid)->getTranslation($item->langcode);
$build = $entity_render->view($entity, 'search_result', $item->langcode);
unset($build['#theme']);
// Uncomment to use removeFromSnippet() for excluding data from snippet.
/* $build['#pre_render'][] = array($this, 'removeFromSnippet'); */
// Build the snippet.
$rendered = $this->renderer->renderPlain($build);
$this->addCacheableDependency(CacheableMetadata::createFromRenderArray($build));
// Allow other modules to add to snippet.
$rendered .= ' ' . $this->moduleHandler->invokeAll('fedora_resource_update_index', [$entity]);
$extra = $this->moduleHandler->invokeAll('fedora_resource_search_result', [$entity]);
$language = $this->languageManager->getLanguage($item->langcode);
$result = array(
'link' => $entity->url(
'canonical',
array(
'absolute' => TRUE,
'language' => $language,
)
),
'type' => 'Fedora Resource',
'title' => $entity->label(),
'contact' => $entity,
'extra' => $extra,
'score' => $item->calculated_score,
'snippet' => search_excerpt($keys, $rendered, $item->langcode),
'langcode' => $entity->language()->getId(),
);
$this->addCacheableDependency($entity);
// We have to separately add the contact owner's cache tags because search
// module doesn't use the rendering system, it does its own rendering
// without taking cacheability metadata into account. So we have to do it
// explicitly here.
$this->addCacheableDependency($entity->getOwner());
// @codingStandardsIgnoreStart
// Uncomment this to display owner name and last changed time.
// $username = array(
// '#theme' => 'username',
// '#account' => $entity->getOwner(),
// );
// $result += array(
// 'user' => $this->renderer->renderPlain($username),
// 'date' => $entity->getChangedTime(),
// );
// @codingStandardsIgnoreEnd
$results[] = $result;
}
return $results;
}
/**
* Removes results data from the build array.
*
* This information is being removed from the rendered entity that is used to
* build the search result snippet.
*
* @param array $build
* The build array.
*
* @return array
* The modified build array.
*/
public function removeFromSnippet(array $build) {
// Code to remove arbitrary data from $build goes here.
// Examples:
// - unset($build['created']);
// - unset($build['uid']);.
return $build;
}
/**
* Adds the configured rankings to the search query.
*
* @param SelectExtender $query
* A query object that has been extended with the Search DB Extender.
*/
protected function addFedoraResourceRankings(SelectExtender $query) {
if ($ranking = $this->getRankings()) {
$tables = &$query->getTables();
foreach ($ranking as $rank => $values) {
if (isset($this->configuration['rankings'][$rank]) && !empty($this->configuration['rankings'][$rank])) {
$entity_rank = $this->configuration['rankings'][$rank];
// If the table defined in the ranking isn't already joined, add it.
if (isset($values['join']) && !isset($tables[$values['join']['alias']])) {
$query->addJoin($values['join']['type'], $values['join']['table'], $values['join']['alias'], $values['join']['on']);
}
$arguments = isset($values['arguments']) ? $values['arguments'] : array();
$query->addScore($values['score'], $arguments, $entity_rank);
}
}
}
}
/**
* {@inheritdoc}
*/
public function updateIndex() {
// Interpret the cron limit setting as the maximum number of entities to
// index per cron run.
$limit = (int) $this->searchSettings->get('index.cron_limit');
$result = $this->database->queryRange("SELECT c.id, MAX(sd.reindex) FROM {fedora_resource} c LEFT JOIN {search_dataset} sd ON sd.sid = c.id AND sd.type = :type WHERE sd.sid IS NULL OR sd.reindex <> 0 GROUP BY c.id ORDER BY MAX(sd.reindex) is null DESC, MAX(sd.reindex) ASC, c.id ASC", 0, $limit, array(':type' => $this->getPluginId()), array('target' => 'replica'));
$rids = $result->fetchCol();
if (!$rids) {
return;
}
// 'fedora_resource' comes from the entity type id declared
// in the annotation for \Drupal\islandoraclaw\Entity\FedoraResource.
// Replace this with your entity's type id.
$entity_storage = $this->entityManager->getStorage('fedora_resource');
foreach ($entity_storage->loadMultiple($rids) as $entity) {
$this->indexFedoraResource($entity);
}
}
/**
* Indexes a single contact.
*
* @param \Drupal\content_entity_example\ContactInterface $entity
* The contact to index.
*/
protected function indexFedoraResource(FedoraResourceInterface $entity) {
$languages = $entity->getTranslationLanguages();
// 'content_entity_example_contact' comes from the entity type id declared
// in the annotation for \Drupal\content_entity_example\Entity\Contact.
// Replace this with your entity's type id.
$entity_render = $this->entityManager->getViewBuilder('fedora_resource');
foreach ($languages as $language) {
$entity = $entity->getTranslation($language->getId());
// Render the contact.
$build = $entity_render->view($entity, 'search_index', $language->getId());
unset($build['#theme']);
// Add the title to text so it is searchable.
$build['search_title'] = [
'#prefix' => '',
'#plain_text' => $entity->label(),
'#suffix' => '',
'#weight' => -1000,
];
$text = $this->renderer->renderPlain($build);
// Fetch extra data normally not visible.
$extra = $this->moduleHandler->invokeAll('fedora_resource_update_index', [$entity]);
foreach ($extra as $t) {
$text .= $t;
}
// Update index, using search index "type" equal to the plugin ID.
search_index($this->getPluginId(), $entity->id(), $language->getId(), $text);
}
}
/**
* {@inheritdoc}
*/
public function indexClear() {
// All ContactSearch pages share a common search index "type" equal to
// the plugin ID.
search_index_clear($this->getPluginId());
}
/**
* {@inheritdoc}
*/
public function markForReindex() {
// All ContactSearch pages share a common search index "type" equal to
// the plugin ID.
search_mark_for_reindex($this->getPluginId());
}
/**
* {@inheritdoc}
*/
public function indexStatus() {
$total = $this->database->query('SELECT COUNT(*) FROM {fedora_resource}')->fetchField();
$remaining = $this->database->query("SELECT COUNT(DISTINCT c.id) FROM {contact} c LEFT JOIN {search_dataset} sd ON sd.sid = c.id AND sd.type = :type WHERE sd.sid IS NULL OR sd.reindex <> 0", array(':type' => $this->getPluginId()))->fetchField();
return array('remaining' => $remaining, 'total' => $total);
}
/**
* {@inheritdoc}
*/
public function searchFormAlter(array &$form, FormStateInterface $form_state) {
$parameters = $this->getParameters();
$keys = $this->getKeywords();
$used_advanced = !empty($parameters[self::ADVANCED_FORM]);
if ($used_advanced) {
$f = isset($parameters['f']) ? (array) $parameters['f'] : array();
$defaults = $this->parseAdvancedDefaults($f, $keys);
}
else {
$defaults = array('keys' => $keys);
}
$form['basic']['keys']['#default_value'] = $defaults['keys'];
// Add advanced search keyword-related boxes.
$form['advanced'] = array(
'#type' => 'details',
'#title' => t('Advanced search'),
'#attributes' => array('class' => array('search-advanced')),
'#access' => $this->account && $this->account->hasPermission('use advanced search'),
'#open' => $used_advanced,
);
$form['advanced']['keywords-fieldset'] = array(
'#type' => 'fieldset',
'#title' => t('Keywords'),
);
$form['advanced']['keywords-fieldset']['keywords']['or'] = array(
'#type' => 'textfield',
'#title' => t('Containing any of the words'),
'#size' => 30,
'#maxlength' => 255,
'#default_value' => isset($defaults['or']) ? $defaults['or'] : '',
);
$form['advanced']['keywords-fieldset']['keywords']['phrase'] = array(
'#type' => 'textfield',
'#title' => t('Containing the phrase'),
'#size' => 30,
'#maxlength' => 255,
'#default_value' => isset($defaults['phrase']) ? $defaults['phrase'] : '',
);
$form['advanced']['keywords-fieldset']['keywords']['negative'] = array(
'#type' => 'textfield',
'#title' => t('Containing none of the words'),
'#size' => 30,
'#maxlength' => 255,
'#default_value' => isset($defaults['negative']) ? $defaults['negative'] : '',
);
$form['advanced']['misc-fieldset'] = array(
'#type' => 'fieldset',
);
// \Drupal\search\SearchQuery requires that there be valid keywords
// submitted in the standard fields.
$form['advanced']['misc-fieldset']['note'] = array(
'#markup' => t('You must still enter keyword(s) above when using these fields.'),
'#weight' => -10,
);
$form['advanced']['misc-fieldset']['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#description' => t('Search %field field for exact matches.', array('%field' => 'Name')),
'#default_value' => isset($defaults['name']) ? $defaults['name'] : array(),
);
$form['advanced']['submit'] = array(
'#type' => 'submit',
'#value' => t('Advanced search'),
'#prefix' => '',
'#suffix' => '',
'#weight' => 100,
);
}
/**
* {@inheritdoc}
*/
public function buildSearchUrlQuery(FormStateInterface $form_state) {
// Read keyword and advanced search information from the form values,
// and put these into the GET parameters.
$keys = trim($form_state->getValue('keys'));
$advanced = FALSE;
// Collect extra filters.
$filters = array();
// Advanced form, custom_content_entity_example_contact fields.
if ($form_state->hasValue('name') && !empty(($value = trim($form_state->getValue('name'))))) {
$filters[] = 'name:' . $value;
$advanced = TRUE;
}
// Advanced form, keywords fields.
if ($form_state->getValue('or') != '') {
if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' ' . $form_state->getValue('or'), $matches)) {
$keys .= ' ' . implode(' OR ', $matches[1]);
$advanced = TRUE;
}
}
if ($form_state->getValue('negative') != '') {
if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' ' . $form_state->getValue('negative'), $matches)) {
$keys .= ' -' . implode(' -', $matches[1]);
$advanced = TRUE;
}
}
if ($form_state->getValue('phrase') != '') {
$keys .= ' "' . str_replace('"', ' ', $form_state->getValue('phrase')) . '"';
$advanced = TRUE;
}
$keys = trim($keys);
// Put the keywords and advanced parameters into GET parameters. Make sure
// to put keywords into the query even if it is empty, because the page
// controller uses that to decide it's time to check for search results.
$query = array('keys' => $keys);
if ($filters) {
$query['f'] = $filters;
}
// Record that the person used the advanced search form, if they did.
if ($advanced) {
$query[self::ADVANCED_FORM] = '1';
}
return $query;
}
/**
* Parses the advanced search form default values.
*
* @param array $f
* The 'f' query parameter set up in self::buildUrlSearchQuery(), which
* contains the advanced query values.
* @param string $keys
* The search keywords string, which contains some information from the
* advanced search form.
*
* @return array
* Array of default form values for the advanced search form, including
* a modified 'keys' element for the bare search keywords.
*/
protected function parseAdvancedDefaults($f, $keys) {
$defaults = array();
// Split out the advanced search parameters.
foreach ($f as $advanced) {
list($key, $value) = explode(':', $advanced, 2);
if (!isset($defaults[$key])) {
$defaults[$key] = array();
}
$defaults[$key][] = $value;
}
// Split out the negative, phrase, and OR parts of keywords.
// For phrases, the form only supports one phrase.
$matches = array();
$keys = ' ' . $keys . ' ';
if (preg_match('/ "([^"]+)" /', $keys, $matches)) {
$keys = str_replace($matches[0], ' ', $keys);
$defaults['phrase'] = $matches[1];
}
// Negative keywords: pull all of them out.
if (preg_match_all('/ -([^ ]+)/', $keys, $matches)) {
$keys = str_replace($matches[0], ' ', $keys);
$defaults['negative'] = implode(' ', $matches[1]);
}
// OR keywords: pull up to one set of them out of the query.
if (preg_match('/ [^ ]+( OR [^ ]+)+ /', $keys, $matches)) {
$keys = str_replace($matches[0], ' ', $keys);
$words = explode(' OR ', trim($matches[0]));
$defaults['or'] = implode(' ', $words);
}
// Put remaining keywords string back into keywords.
$defaults['keys'] = trim($keys);
return $defaults;
}
/**
* Gathers ranking definitions from hook_ranking().
*
* @return array
* An array of ranking definitions.
*/
protected function getRankings() {
if (!$this->rankings) {
$this->rankings = $this->moduleHandler->invokeAll('ranking');
}
return $this->rankings;
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
$configuration = array(
'rankings' => array(),
);
return $configuration;
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
// Output form for defining rank factor weights.
$form['content_ranking'] = array(
'#type' => 'details',
'#title' => t('Content ranking'),
'#open' => TRUE,
);
$form['content_ranking']['info'] = array(
'#markup' => '' . $this->t('Influence is a numeric multiplier used in ordering search results. A higher number means the corresponding factor has more influence on search results; zero means the factor is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') . '',
);
// Prepare table.
$header = [$this->t('Factor'), $this->t('Influence')];
$form['content_ranking']['rankings'] = array(
'#type' => 'table',
'#header' => $header,
);
// Note: reversed to reflect that higher number = higher ranking.
$range = range(0, 10);
$options = array_combine($range, $range);
foreach ($this->getRankings() as $var => $values) {
$form['content_ranking']['rankings'][$var]['name'] = array(
'#markup' => $values['title'],
);
$form['content_ranking']['rankings'][$var]['value'] = array(
'#type' => 'select',
'#options' => $options,
'#attributes' => ['aria-label' => $this->t("Influence of '@title'", ['@title' => $values['title']])],
'#default_value' => isset($this->configuration['rankings'][$var]) ? $this->configuration['rankings'][$var] : 0,
);
}
return $form;
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
foreach ($this->getRankings() as $var => $values) {
if (!$form_state->isValueEmpty(['rankings', $var, 'value'])) {
$this->configuration['rankings'][$var]
= $form_state->getValue(['rankings', $var, 'value']);
}
else {
unset($this->configuration['rankings'][$var]);
}
}
}
}

23
templates/fedora-resource-content-add-list.html.twig

@ -0,0 +1,23 @@
{#
/**
* @file
* Default theme implementation to present a list of custom content entity types/bundles.
*
* Available variables:
* - types: A collection of all the available custom entity types/bundles.
* Each type/bundle contains the following:
* - link: A link to add a content entity of this type.
* - description: A description of this content entity types/bundle.
*
* @see template_preprocess_fedora_resource_content_add_list()
*
* @ingroup themeable
*/
#}
{% spaceless %}
<dl>
{% for type in types %}
<dt>{{ type.link }}</dt>
{% endfor %}
</dl>
{% endspaceless %}

22
templates/fedora_resource.html.twig

@ -0,0 +1,22 @@
{#
/**
* @file fedora_resource.html.twig
* Default theme implementation to present Fedora resource data.
*
* This template is used when viewing Fedora resource pages.
*
*
* Available variables:
* - content: A list of content items. Use 'content' to print all content, or
* - attributes: HTML attributes for the container element.
*
* @see template_preprocess_fedora_resource()
*
* @ingroup themeable
*/
#}
<div{{ attributes.addClass('fedora_resource') }}>
{% if content %}
{{- content -}}
{% endif %}
</div>
Loading…
Cancel
Save