Skip to content
Snippets Groups Projects
Commit 38680332 authored by Dries Buytaert's avatar Dries Buytaert
Browse files

Issue #2046303 by kim.pepper: Convert aggregator_form_category() to FormInterface.

parent dd95e4ba
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
Showing
with 661 additions and 136 deletions
<?php
/**
* @file
* Administration page callbacks for the Aggregator module.
*/
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Drupal\aggregator\Plugin\Core\Entity\Feed;
/**
* Form constructor to add/edit/delete aggregator categories.
*
* @param $edit
* An object containing:
* - title: A string to use for the category title.
* - description: A string to use for the category description.
* - cid: The category ID.
*
* @ingroup forms
* @see aggregator_menu()
* @see aggregator_form_category_validate()
* @see aggregator_form_category_submit()
*/
function aggregator_form_category($form, &$form_state, $edit = NULL) {
$form['title'] = array('#type' => 'textfield',
'#title' => t('Title'),
'#default_value' => isset($edit->title) ? $edit->title : '',
'#maxlength' => 64,
'#required' => TRUE,
);
$form['description'] = array('#type' => 'textarea',
'#title' => t('Description'),
'#default_value' => isset($edit->description) ? $edit->description : '',
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
if (!empty($edit->cid)) {
$form['actions']['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
$form['cid'] = array('#type' => 'hidden', '#value' => $edit->cid);
}
return $form;
}
/**
* Form validation handler for aggregator_form_category().
*
* @see aggregator_form_category_submit()
*/
function aggregator_form_category_validate($form, &$form_state) {
if ($form_state['values']['op'] == t('Save')) {
// Check for duplicate titles
if (isset($form_state['values']['cid'])) {
$category = db_query("SELECT cid FROM {aggregator_category} WHERE title = :title AND cid <> :cid", array(':title' => $form_state['values']['title'], ':cid' => $form_state['values']['cid']))->fetchObject();
}
else {
$category = db_query("SELECT cid FROM {aggregator_category} WHERE title = :title", array(':title' => $form_state['values']['title']))->fetchObject();
}
if ($category) {
form_set_error('title', t('A category named %category already exists. Enter a unique title.', array('%category' => $form_state['values']['title'])));
}
}
}
/**
* Form submission handler for aggregator_form_category().
*
* @see aggregator_form_category_validate()
*
* @todo Add delete confirmation dialog.
*/
function aggregator_form_category_submit($form, &$form_state) {
// @todo Replicate this cache invalidation when these ops are separated.
// Invalidate the block cache to update aggregator category-based derivatives.
if (Drupal::moduleHandler()->moduleExists('block')) {
Drupal::service('plugin.manager.block')->clearCachedDefinitions();
}
if ($form_state['values']['op'] == t('Delete')) {
$title = $form_state['values']['title'];
// Unset the title.
unset($form_state['values']['title']);
}
aggregator_save_category($form_state['values']);
if (isset($form_state['values']['cid'])) {
if (isset($form_state['values']['title'])) {
drupal_set_message(t('The category %category has been updated.', array('%category' => $form_state['values']['title'])));
if (arg(0) == 'admin') {
$form_state['redirect'] = 'admin/config/services/aggregator/';
return;
}
else {
$form_state['redirect'] = 'aggregator/categories/' . $form_state['values']['cid'];
return;
}
}
else {
watchdog('aggregator', 'Category %category deleted.', array('%category' => $title));
drupal_set_message(t('The category %category has been deleted.', array('%category' => $title)));
if (arg(0) == 'admin') {
$form_state['redirect'] = 'admin/config/services/aggregator/';
return;
}
else {
$form_state['redirect'] = 'aggregator/categories/';
return;
}
}
}
else {
watchdog('aggregator', 'Category %category added.', array('%category' => $form_state['values']['title']), WATCHDOG_NOTICE, l(t('view'), 'admin/config/services/aggregator'));
drupal_set_message(t('The category %category has been added.', array('%category' => $form_state['values']['title'])));
}
}
......@@ -102,11 +102,8 @@ function aggregator_menu() {
);
$items['admin/config/services/aggregator/add/category'] = array(
'title' => 'Add category',
'page callback' => 'drupal_get_form',
'page arguments' => array('aggregator_form_category'),
'access arguments' => array('administer news feeds'),
'type' => MENU_LOCAL_ACTION,
'file' => 'aggregator.admin.inc',
'route_name' => 'aggregator_category_add',
);
$items['admin/config/services/aggregator/add/opml'] = array(
'title' => 'Import OPML',
......@@ -174,12 +171,9 @@ function aggregator_menu() {
);
$items['aggregator/categories/%aggregator_category/configure'] = array(
'title' => 'Configure',
'page callback' => 'drupal_get_form',
'page arguments' => array('aggregator_form_category', 2),
'access arguments' => array('administer news feeds'),
'type' => MENU_LOCAL_TASK,
'weight' => 10,
'file' => 'aggregator.admin.inc',
'route_name' => 'aggregator_category_edit',
);
$items['aggregator/sources/%aggregator_feed'] = array(
'title callback' => 'entity_page_label',
......@@ -208,14 +202,12 @@ function aggregator_menu() {
'access arguments' => array('administer news feeds'),
'type' => MENU_LOCAL_TASK,
'weight' => 10,
'file' => 'aggregator.admin.inc',
);
$items['admin/config/services/aggregator/edit/feed/%aggregator_feed'] = array(
'title' => 'Edit feed',
'page callback' => 'entity_get_form',
'page arguments' => array(6),
'access arguments' => array('administer news feeds'),
'file' => 'aggregator.admin.inc',
);
$items['admin/config/services/aggregator/delete/feed/%aggregator_feed'] = array(
'title' => 'Delete feed',
......@@ -223,10 +215,11 @@ function aggregator_menu() {
);
$items['admin/config/services/aggregator/edit/category/%aggregator_category'] = array(
'title' => 'Edit category',
'page callback' => 'drupal_get_form',
'page arguments' => array('aggregator_form_category', 6),
'access arguments' => array('administer news feeds'),
'file' => 'aggregator.admin.inc',
'route_name' => 'aggregator_category_admin_edit',
);
$items['admin/config/services/aggregator/delete/category/%aggregator_category'] = array(
'title' => 'Delete category',
'route_name' => 'aggregator_category_delete',
);
return $items;
......@@ -455,16 +448,14 @@ function aggregator_feed_load($fid) {
* @param $cid
* The category id.
*
* @return
* An associative array describing the category.
* @return stdClass|null
* An object containing all category properties.
*
* @deprecated Use Drupal\aggregator\CategoryStorageControllerInterface::load()
* instead.
*/
function aggregator_category_load($cid) {
$categories = &drupal_static(__FUNCTION__);
if (!isset($categories[$cid])) {
$categories[$cid] = db_query('SELECT * FROM {aggregator_category} WHERE cid = :cid', array(':cid' => $cid))->fetchObject();
}
return $categories[$cid];
return Drupal::service('aggregator.category.storage')->load($cid);
}
/**
......
......@@ -67,3 +67,31 @@ aggregator_categories:
_content: '\Drupal\aggregator\Controller\AggregatorController::categories'
requirements:
_access_aggregator_categories: 'TRUE'
aggregator_category_edit:
pattern: 'aggregator/categories/{cid}/configure'
defaults:
_form: '\Drupal\aggregator\Form\CategoryAdminForm'
requirements:
_permission: 'administer news feeds'
aggregator_category_admin_edit:
pattern: 'admin/config/services/aggregator/edit/category/{cid}'
defaults:
_form: '\Drupal\aggregator\Form\CategoryAdminForm'
requirements:
_permission: 'administer news feeds'
aggregator_category_delete:
pattern: 'admin/config/services/aggregator/delete/category/{cid}'
defaults:
_form: '\Drupal\aggregator\Form\CategoryDeleteForm'
requirements:
_permission: 'administer news feeds'
aggregator_category_add:
pattern: 'admin/config/services/aggregator/add/category'
defaults:
_form: '\Drupal\aggregator\Form\CategoryAdminForm'
requirements:
_permission: 'administer news feeds'
......@@ -13,3 +13,6 @@ services:
arguments: ['@database']
tags:
- { name: access_check }
aggregator.category.storage:
class: Drupal\aggregator\CategoryStorageController
arguments: ['@database']
<?php
/**
* @file
* Contains \Drupal\aggregator\CategoryStorageController.
*/
namespace Drupal\aggregator;
use Drupal\Core\Database\Connection;
/**
* Storage controller for aggregator categories.
*/
class CategoryStorageController implements CategoryStorageControllerInterface {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* A cache of loaded categories.
*
* @var \stdClass[]
*/
protected $categories;
/**
* Creates a new CategoryStorageController object.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
*/
public function __construct(Connection $database) {
$this->database = $database;
}
/**
* {@inheritdoc}
*/
public function load($cid) {
if (!isset($this->categories[$cid])) {
$this->categories[$cid] = $this->database->query("SELECT * FROM {aggregator_category} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
}
return $this->categories[$cid];
}
/**
* {@inheritdoc}
*/
public function save($category) {
$cid = $this->database->insert('aggregator_category')
->fields(array(
'title' => $category->title,
'description' => $category->description,
'block' => 5,
))
->execute();
return $cid;
}
/**
* {@inheritdoc}
*/
public function update($category) {
$this->database->merge('aggregator_category')
->key(array('cid' => $category->cid))
->fields(array(
'title' => $category->title,
'description' => $category->description,
))
->execute();
}
/**
* {@inheritdoc}
*/
public function delete($cid) {
$this->database->delete('aggregator_category')
->condition('cid', $cid)
->execute();
}
/**
* {@inheritdoc}
*/
public function isUnique($title, $cid = NULL) {
$query = $this->database->select('aggregator_category', 'ac')
->fields('ac', array('title'))
->condition('title', $title);
if (!empty($cid)) {
$query->condition('cid', $cid, '<>');
}
$rows = $query->execute()->fetchCol();
return (empty($rows));
}
}
<?php
/**
* @file
* Contains \Drupal\aggregator\CategoryStorageControllerInterface.
*/
namespace Drupal\aggregator;
/**
* Storage Controller for aggregator categories.
*/
interface CategoryStorageControllerInterface {
/**
* Loads an aggregator category by its unique ID.
*
* @param int $cid
* The unique category ID.
*
* @return stdClass|null
* An object containing all category properties.
*/
public function load($cid);
/**
* Saves an aggregator category.
*
* @param \stdClass $category
* The category to save.
*
* @return int
* The new category ID.
*/
public function save($category);
/**
* Updates and aggregator category.
*
* @param \stdClass $category
* The category.
*/
public function update($category);
/**
* Deletes an aggregator category.
*
* @param int $cid
* The category ID.
*/
public function delete($cid);
/**
* Checks if the category title is unique.
*
* Optionally passes a category ID to exclude, if this check is for an
* existing category.
*
* @param string $title
* The category title.
* @param int $cid
* (optional) The category ID to exclude from the check.
*
* @return bool
* TRUE if the category title is unique, FALSE otherwise.
*/
public function isUnique($title, $cid = NULL);
}
......@@ -202,6 +202,10 @@ public function adminOverview() {
'title' => t('Edit'),
'href' => "admin/config/services/aggregator/edit/category/$category->cid",
);
$links['delete'] = array(
'title' => t('Delete'),
'href' => "admin/config/services/aggregator/delete/category/$category->cid",
);
$row[] = array(
'data' => array(
'#type' => 'operations',
......
<?php
/**
* @file
* Contains Drupal\aggregator\Form\CategoryAdminForm.
*/
namespace Drupal\aggregator\Form;
use Drupal\aggregator\CategoryStorageControllerInterface;
use Drupal\block\Plugin\Type\BlockManager;
use Drupal\Core\Controller\ControllerInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityManager;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Provides a form for configuring aggregator categories.
*/
class CategoryAdminForm implements FormInterface, ControllerInterface {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection.
*/
protected $database;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The category storage controller.
*
* @var \Drupal\aggregator\CategoryStorageControllerInterface.
*/
protected $categoryStorageController;
/**
* The current request.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* The block manager.
*
* @var \Drupal\block\Plugin\Type\BlockManager
*/
protected $blockManager;
/**
* Creates a new CategoryForm object.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\aggregator\CategoryStorageControllerInterface $category_storage_controller
* The category storage controller.
* @param \Drupal\block\Plugin\Type\BlockManager $block_manager
* (optional) The block manager. Used if block module is enabled.
*/
public function __construct(Connection $database, ModuleHandlerInterface $module_handler, CategoryStorageControllerInterface $category_storage_controller, BlockManager $block_manager = NULL) {
$this->database = $database;
$this->moduleHandler = $module_handler;
$this->categoryStorageController = $category_storage_controller;
$this->blockManager = $block_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
$block_manager = NULL;
if ($container->get('module_handler')->moduleExists('block')) {
$block_manager = $container->get('plugin.manager.block');
}
return new static(
$container->get('database'),
$container->get('module_handler'),
$container->get('aggregator.category.storage'),
$block_manager
);
}
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'aggregator_form_category';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, $cid = NULL, Request $request = NULL) {
$this->request = $request;
$category = $this->categoryStorageController->load($cid);
$form['title'] = array(
'#type' => 'textfield',
'#title' => t('Title'),
'#default_value' => isset($category->title) ? $category->title : '',
'#maxlength' => 64,
'#required' => TRUE,
);
$form['description'] = array(
'#type' => 'textarea',
'#title' => t('Description'),
'#default_value' => isset($category->description) ? $category->description : '',
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
if (!empty($category->cid)) {
$form['actions']['delete'] = array(
'#type' => 'submit',
'#value' => t('Delete'),
);
$form['cid'] = array('#type' => 'hidden', '#value' => $category->cid);
}
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
if ($form_state['values']['op'] == t('Save')) {
// Check for duplicate titles.
$title = $form_state['values']['title'];
if (isset($form_state['values']['cid'])) {
// Exclude the current category ID when checking if it's unique.
$unique = $this->categoryStorageController->isUnique($title, $form_state['values']['cid']);
}
else {
$unique = $this->categoryStorageController->isUnique($title);
}
if (!$unique) {
form_set_error('title', t('A category named %category already exists. Enter a unique title.', array('%category' => $title)));
}
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
// @todo Replicate this cache invalidation when these ops are separated.
// Invalidate the block cache to update aggregator category-based derivatives.
$this->clearBlockCache();
$link_path = 'aggregator/categories/';
$title = $form_state['values']['title'];
// Redirect to a confirm delete form.
if ($form_state['values']['op'] == t('Delete')) {
$cid = $form_state['values']['cid'];
$form_state['redirect'] = 'admin/config/services/aggregator/delete/category/' . $cid;
return;
}
// Update the category.
if (!empty($form_state['values']['cid'])) {
$cid = $form_state['values']['cid'];
$this->categoryStorageController->update((object) $form_state['values']);
drupal_set_message(t('The category %category has been updated.', array('%category' => $title)));
if (preg_match('/^\/admin/', $this->request->getPathInfo())) {
$form_state['redirect'] = 'admin/config/services/aggregator/';
}
else {
$form_state['redirect'] = 'aggregator/categories/' . $cid;
}
$this->updateMenuLink('update', $link_path . $cid, $title);
return;
}
// Insert the category.
$cid = $this->categoryStorageController->save((object) $form_state['values']);
watchdog('aggregator', 'Category %category added.', array('%category' => $form_state['values']['title']), WATCHDOG_NOTICE, l(t('view'), 'admin/config/services/aggregator'));
drupal_set_message(t('The category %category has been added.', array('%category' => $title)));
$this->updateMenuLink('insert', $link_path . $cid, $title);
}
/**
* Clear the block cached definitions.
*/
protected function clearBlockCache() {
if (!empty($this->blockManager)) {
$this->blockManager->clearCachedDefinitions();
}
}
/**
* Updates a category menu link.
*
* @param string $op
* The operation to perform.
* @param string $link_path
* The path of the menu link.
* @param string $title
* The title of the menu link.
*
* @see menu_link_maintain()
*/
protected function updateMenuLink($op, $link_path, $title) {
if (isset($op) && $this->moduleHandler->moduleExists('menu_link')) {
menu_link_maintain('aggregator', $op, $link_path, $title);
}
}
}
<?php
/**
* @file
* Contains \Drupal\aggregator\Form\CategoryDeleteForm.
*/
namespace Drupal\aggregator\Form;
use Drupal\aggregator\CategoryStorageControllerInterface;
use Drupal\Core\Controller\ControllerInterface;
use Drupal\Core\Entity\EntityManager;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Provides a confirm delete form.
*/
class CategoryDeleteForm extends ConfirmFormBase implements ControllerInterface {
/**
* The category to be deleted.
*
* @var array
*/
protected $category;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManager
*/
protected $entityManager;
/**
* The category storage controller.
*
* @var \Drupal\aggregator\CategoryStorageControllerInterface
*/
protected $categoryStorageController;
/**
* The current request.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* Creates a new CategoryDeleteForm.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\Entity\EntityManager $entity_manager
* The entity manager.
* @param CategoryStorageControllerInterface $category_storage_controller
* The category storage controller.
*/
public function __construct(ModuleHandlerInterface $module_handler, EntityManager $entity_manager, CategoryStorageControllerInterface $category_storage_controller) {
$this->moduleHandler = $module_handler;
$this->entityManager = $entity_manager;
$this->categoryStorageController = $category_storage_controller;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static (
$container->get('module_handler'),
$container->get('plugin.manager.entity'),
$container->get('aggregator.category.storage')
);
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return t('Are you sure you want to delete the category %title?', array('%title' => $this->category->title));
}
/**
* {@inheritdoc}
*/
public function getCancelPath() {
return 'admin/config/services/aggregator';
}
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'aggregator_category_delete';
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return t('Delete');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return t('This will delete the aggregator category, the menu item for this category, and any related category blocks.');
}
/**
* Form constructor.
*
* @param array $form
* An associative array containing the structure of the form.
* @param array $form_state
* An associative array containing the current state of the form.
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request.
* @param int|null $cid
* The category ID.
*
* @return array
* The form structure.
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* If the cid param or category is not found.
*/
public function buildForm(array $form, array &$form_state, Request $request = NULL, $cid = NULL) {
$category = $this->categoryStorageController->load($cid);
if (empty($cid) || empty($category)) {
throw new NotFoundHttpException();
}
$this->category = $category;
$this->request = $request;
return parent::buildForm($form, $form_state, $request);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$cid = $this->category->cid;
$title = $this->category->title;
$this->categoryStorageController->delete($cid);
// Make sure there is no active block for this category.
$this->deleteBlocks($cid);
watchdog('aggregator', 'Category %category deleted.', array('%category' => $title));
drupal_set_message(t('The category %category has been deleted.', array('%category' => $title)));
if (preg_match('/^\/admin/', $this->request->getPathInfo())) {
$form_state['redirect'] = 'admin/config/services/aggregator/';
}
else {
$form_state['redirect'] = 'aggregator';
}
$this->updateMenuLink('delete', 'aggregator/categories/' . $cid, $title);
}
/**
* Delete aggregator category blocks.
*
* @param int $cid
* The category ID.
*/
protected function deleteBlocks($cid) {
if ($this->moduleHandler->moduleExists('block')) {
foreach ($this->entityManager->getStorageController('block')->loadByProperties(array('plugin' => 'aggregator_category_block:' . $cid)) as $block) {
$block->delete();
}
}
}
/**
* Updates a category menu link.
*
* @param string $op
* The operation to perform.
* @param string $link_path
* The path of the menu link.
* @param string $title
* The title of the menu link.
*
* @see menu_link_maintain()
*/
protected function updateMenuLink($op, $link_path, $title) {
if (isset($op) && $this->moduleHandler->moduleExists('menu_link')) {
menu_link_maintain('aggregator', $op, $link_path, $title);
}
}
}
......@@ -286,6 +286,14 @@ public function submit(array $form, array &$form_state) {
$form_state['redirect'] = 'admin/structure/block/list/' . $entity->get('theme');
}
/**
* {@inheritdoc}
*/
public function delete(array $form, array &$form_state) {
parent::delete($form, $form_state);
$form_state['redirect'] = 'admin/structure/block/manage/' . $this->entity->id() . '/delete';
}
/**
* Generates a unique machine name for a block.
*
......
......@@ -135,6 +135,13 @@ function testBlock() {
// is my_block_instance_name.
$xpath = $this->buildXPathQuery('//div[@id=:id]/*', array(':id' => 'block-' . strtr(strtolower($block['machine_name']), '-', '_')));
$this->assertNoFieldByXPath($xpath, FALSE, 'Block found in no regions.');
// Test deleting the block from the edit form.
$this->drupalGet('admin/structure/block/manage/' . $block['theme'] . '.' . $block['machine_name']);
$this->drupalPost(NULL, array(), t('Delete'));
$this->assertRaw(t('Are you sure you want to delete the block %name?', array('%name' => $block['settings[label]'])));
$this->drupalPost(NULL, array(), t('Delete'));
$this->assertRaw(t('The block %name has been removed.', array('%name' => $block['settings[label]'])));
}
/**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment