feat(Misc): Initial commit

parents
# JSON API Extras
This module provides extra functionality on top of JSON API. You should not need
this module to get an spec compliant JSON API.
This module adds the following features:
- Allows you to customize the URL for your resource under the `/jsonapi`
prefix.
- Allows you to customize the resource type to other than
`${entityTypeId}--${bundle}`.
- Lets you remove fields from the JSON API output.
jsonapi_extras.resource_config.*:
type: config_entity
label: 'Resource Config config'
mapping:
id:
type: string
label: 'Original Resource plugin ID.'
path:
type: string
label: 'Path'
description: 'The path for the resource.'
resourceType:
type: string
label: 'Type'
description: 'The value for the resource type.'
resourceFields:
type: sequence
label: 'Fields'
sequence:
type: jsonapi_extras.resource_field
jsonapi_extras.resource_field:
type: mapping
mapping:
publicName:
type: string
label: 'Public attribute name'
id:
type: string
label: 'Resource field type'
class:
type: string
label: 'Wrapper class'
postNormalizationCallbacks:
type: sequence
label: 'Post-normalization callbacks'
description: 'Set of static callbacks to be executed in sequence after normalization.'
sequence:
type: callable
# TODO: Probably worth creating a data type to validate that it's a callable.
callable:
type: string
name: JSON API Extras
type: module
description: Builds on top of JSON API to deliver extra functionality.
core: 8.x
dependencies:
- jsonapi
entity.resource_config.add_form:
route_name: 'entity.resource_config.add_form'
title: 'Add Resource Config'
appears_on:
- entity.resource_config.collection
entity.resource_config.collection:
title: JSON API
description: 'Configure JSON API extras.'
parent: system.admin_config_services
route_name: entity.resource_config.collection
<?php
/**
* @file
* Contains \Drupal\jsonapi_extras\Entity\ResourceConfig.
*/
namespace Drupal\jsonapi_extras\Entity;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Config\Entity\ConfigEntityBase;
/**
* Defines the Resource Config entity.
*
* @ConfigEntityType(
* id = "resource_config",
* label = @Translation("Resource Config"),
* handlers = {
* "list_builder" = "Drupal\jsonapi_extras\ResourceConfigListBuilder",
* "form" = {
* "add" = "Drupal\jsonapi_extras\Form\ResourceConfigForm",
* "edit" = "Drupal\jsonapi_extras\Form\ResourceConfigForm",
* "delete" = "Drupal\jsonapi_extras\Form\ResourceConfigDeleteForm"
* },
* "route_provider" = {
* "html" = "Drupal\jsonapi_extras\ResourceConfigHtmlRouteProvider",
* },
* },
* config_prefix = "resource_config",
* admin_permission = "administer site configuration",
* entity_keys = {
* "id" = "id",
* "label" = "label",
* "uuid" = "uuid"
* },
* links = {
* "canonical" = "/admin/config/services/resource_config/{resource_config}",
* "add-form" = "/admin/config/services/resource_config/add",
* "edit-form" = "/admin/config/services/resource_config/{resource_config}/edit",
* "delete-form" = "/admin/config/services/resource_config/{resource_config}/delete",
* "collection" = "/admin/config/services/resource_config"
* }
* )
*/
class ResourceConfig extends ConfigEntityBase {
/**
* The Resource Config ID.
*
* @var string
*/
protected $id;
/**
* The path for the resource.
*
* @var string
*/
protected $path;
/**
* The type for the resource.
*
* @var string
*/
protected $resourceType;
/**
* Resource fields.
*
* @var array
*/
protected $resourceFields = [];
/**
* {@inheritdoc}
*/
public function __construct(array $values, $entity_type) {
parent::__construct(static::addDefaults($values), $entity_type);
}
/**
* {@inheritdoc}
*/
public static function addDefaults(array $values) {
$default_field = [
'data' => [
'column' => 'value',
],
'id' => 'field',
];
if (!empty($values['resourceFields'])) {
$values['resourceFields'] = array_map(function ($value) use ($default_field) {
if (!is_array($value)) {
// Avoid PHP blowing up.
return $value;
}
$defaults = NestedArray::mergeDeep($default_field, $value);
// If the field has a callback, that makes it a callback resource field.
if (!empty($defaults['callback'])) {
$defaults['id'] = 'callback';
unset($defaults['data']);
}
// If the process callbacks are empty, remove them.
if (isset($defaults['processCallbacks']) && !$defaults['processCallbacks']) {
unset($defaults['processCallbacks']);
}
return $defaults;
}, $values['resourceFields']);
}
return $values;
}
}
<?php
/**
* @file
* Contains \Drupal\jsonapi_extras\Form\ResourceConfigDeleteForm.
*/
namespace Drupal\jsonapi_extras\Form;
use Drupal\Core\Entity\EntityConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
/**
* Builds the form to delete Resource Config entities.
*/
class ResourceConfigDeleteForm 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.resource_config.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());
}
}
<?php
/**
* @file
* Contains \Drupal\jsonapi_extras\Form\ResourceConfigForm.
*/
namespace Drupal\jsonapi_extras\Form;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\jsonapi\ResourceType\ResourceTypeRepository;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Class ResourceConfigForm.
*
* @package Drupal\jsonapi_extras\Form
*/
class ResourceConfigForm extends EntityForm {
/**
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $bundleInfo;
/**
* @var \Drupal\jsonapi\ResourceType\ResourceTypeRepository
*/
protected $resourceTypeRepository;
/**
* EntityBundlePicker constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info
*/
public function __construct(EntityTypeBundleInfoInterface $bundle_info, ResourceTypeRepository $resource_type_repository) {
$this->bundleInfo = $bundle_info;
$this->resourceTypeRepository = $resource_type_repository;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.bundle.info'),
$container->get('jsonapi.resource_type.repository')
);
}
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$entity_types = $this->entityTypeManager->getDefinitions();
$entity_type_options = array_reduce($entity_types, function ($carry, EntityTypeInterface $entity_type) {
$carry[$entity_type->id()] = $entity_type->getLabel();
return $carry;
}, []);
$form['entity_type_id'] = [
'#title' => $this->t('Entity Type'),
'#type' => 'select',
'#options' => $entity_type_options,
'#empty_option' => $this->t('- Select -'),
'#required' => TRUE,
'#ajax' => [
'callback' => '::bundleCallback',
'wrapper' => 'bundle-wrapper',
],
];
// Disable caching on this form.
$form_state->setCached(FALSE);
$form['actions'] = [
'#type' => 'actions',
];
// Add a submit button that handles the submission of the form.
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
];
$form['bundle_wrapper'] = [
'#type' => 'container',
'#attributes' => ['id' => 'bundle-wrapper'],
];
$form['fields_wrapper'] = [
'#type' => 'container',
'#attributes' => ['id' => 'fields-wrapper'],
];
if (!$entity_type_id = $form_state->getValue('entity_type_id')) {
return $form;
}
$has_bundles = (bool) $this->entityTypeManager
->getDefinition($entity_type_id)->getBundleEntityType();
if ($has_bundles) {
$bundles = [];
$bundle_info = $this->bundleInfo->getBundleInfo($entity_type_id);
foreach ($bundle_info as $bundle_id => $info) {
$bundles[$bundle_id] = $info['translatable']
? $this->t($info['label'])
: $info['label'];
}
$form['bundle_wrapper']['bundle_id'] = [
'#type' => 'select',
'#empty_option' => $this->t('- Select -'),
'#title' => $this->t('Bundle'),
'#options' => $bundles,
'#required' => TRUE,
'#ajax' => [
'callback' => '::bundleCallback',
'wrapper' => 'bundle-wrapper',
],
];
}
else {
$form['bundle_wrapper']['bundle_id'] = [
'#type' => 'hidden',
'#value' => $entity_type_id,
];
}
$bundle = $has_bundles
? $form_state->getValue('bundle_id')
: $entity_type_id;
if ($resource_type = $this->resourceTypeRepository->get($entity_type_id, $bundle)) {
// Get the JSON API resource type.
$form['bundle_wrapper']['fields_wrapper']['header'] = [
'#type' => 'html_tag',
'#tag' => 'h2',
'#value' => $this->t('Override @type', [
'@type' => $resource_type->getTypeName(),
'@entity_type' => $entity_type_id,
'@bundle' => $bundle,
]),
];
}
return $form;
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$resource_config = $this->entity;
$status = $resource_config->save();
switch ($status) {
case SAVED_NEW:
drupal_set_message($this->t('Created the %label Resource Config.', [
'%label' => $resource_config->label(),
]));
break;
default:
drupal_set_message($this->t('Saved the %label Resource Config.', [
'%label' => $resource_config->label(),
]));
}
$form_state->setRedirectUrl($resource_config->urlInfo('collection'));
}
/**
* Implements callback for Ajax event on entity type or bundle selection.
*
* @param array $form
* From render array.
*
* @return array
* Color selection section of the form.
*/
public function bundleCallback(array &$form) {
return $form['bundle_wrapper'];
}
}
<?php
/**
* @file
* Contains \Drupal\jsonapi_extras\ResourceConfigHtmlRouteProvider.
*/
namespace Drupal\jsonapi_extras;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
use Symfony\Component\Routing\Route;
/**
* Provides routes for Resource Config entities.
*
* @see \Drupal\Core\Entity\Routing\AdminHtmlRouteProvider
* @see \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider
*/
class ResourceConfigHtmlRouteProvider 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;
}
}
}
<?php
/**
* @file
* Contains \Drupal\jsonapi_extras\ResourceConfigListBuilder.
*/
namespace Drupal\jsonapi_extras;
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a listing of Resource Config entities.
*/
class ResourceConfigListBuilder extends ConfigEntityListBuilder {
/**
* {@inheritdoc}
*/
public function buildHeader() {
$header['label'] = $this->t('Resource Config');
$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);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment