diff --git a/cache_example/cache_example.routing.yml b/cache_example/cache_example.routing.yml index 3e38e9d..a35a734 100644 --- a/cache_example/cache_example.routing.yml +++ b/cache_example/cache_example.routing.yml @@ -3,4 +3,4 @@ cache_example.description: defaults: _form: '\Drupal\cache_example\Forms\CacheExampleForm' requirements: - _access: 'TRUE' + _permission: 'access content' diff --git a/cron_example/cron_example.routing.yml b/cron_example/cron_example.routing.yml index 677264c..ab824b9 100644 --- a/cron_example/cron_example.routing.yml +++ b/cron_example/cron_example.routing.yml @@ -4,4 +4,4 @@ cron_example: _form: '\Drupal\cron_example\Form\CronExampleForm' _title: 'Cron Example' requirements: - _access: 'TRUE' + _permission: 'access content' diff --git a/cron_example/src/Tests/CronExampleTestCase.php b/cron_example/src/Tests/CronExampleTestCase.php index 9511eae..6a15c04 100644 --- a/cron_example/src/Tests/CronExampleTestCase.php +++ b/cron_example/src/Tests/CronExampleTestCase.php @@ -37,7 +37,7 @@ class CronExampleTestCase extends WebTestBase { * * @var array */ - public static $modules = ['cron_example']; + public static $modules = ['cron_example', 'node']; /** * {@inheritdoc} @@ -46,7 +46,7 @@ class CronExampleTestCase extends WebTestBase { parent::setUp(); // Create user. Search content permission granted for the search block to // be shown. - $this->drupalLogin($this->drupalCreateUser(['administer site configuration'])); + $this->drupalLogin($this->drupalCreateUser(['administer site configuration', 'access content'])); $this->cronConfig = \Drupal::configFactory()->getEditable('examples.cron'); } diff --git a/dbtng_example/dbtng_example.routing.yml b/dbtng_example/dbtng_example.routing.yml index 81fc5ee..56baf53 100644 --- a/dbtng_example/dbtng_example.routing.yml +++ b/dbtng_example/dbtng_example.routing.yml @@ -4,7 +4,7 @@ dbtng_example: _title: 'DBTNG Example' _controller: '\Drupal\dbtng_example\DBTNGExampleController::entryList' requirements: - _access: 'TRUE' + _permission: 'access content' dbtng_list: path: 'examples/dbtng_example/list' @@ -12,7 +12,7 @@ dbtng_list: _title: 'List' _controller: '\Drupal\dbtng_example\DBTNGExampleController::entryList' requirements: - _access: 'TRUE' + _permission: 'access content' dbtng_add: path: 'examples/dbtng_example/add' @@ -20,7 +20,7 @@ dbtng_add: _title: 'Add Entry' _form: '\Drupal\dbtng_example\DBTNGExampleAddForm' requirements: - _access: 'TRUE' + _permission: 'access content' dbtng_update: path: 'examples/dbtng_example/update' @@ -28,7 +28,7 @@ dbtng_update: _title: 'Update Entry' _form: '\Drupal\dbtng_example\DBTNGExampleUpdateForm' requirements: - _access: 'TRUE' + _permission: 'access content' dbtng_advanced: path: 'examples/dbtng_example/advanced' @@ -36,4 +36,4 @@ dbtng_advanced: _title: 'Advanced List' _controller: '\Drupal\dbtng_example\DBTNGExampleController::entryAdvancedList' requirements: - _access: 'TRUE' + _permission: 'access content' diff --git a/email_example/email_example.routing.yml b/email_example/email_example.routing.yml index 2701dad..7e329f4 100644 --- a/email_example/email_example.routing.yml +++ b/email_example/email_example.routing.yml @@ -3,4 +3,4 @@ email_example.description: defaults: _form: '\Drupal\email_example\Form\EmailExampleGetFormPage' requirements: - _access: 'TRUE' + _permission: 'access content' diff --git a/examples.module b/examples.module index e866557..efdf09b 100644 --- a/examples.module +++ b/examples.module @@ -45,6 +45,7 @@ function examples_toolbar() { 'node_type_example' => 'config_node_type_example.description', 'page_example' => 'page_example_description', 'phpunit_example' => 'phpunit_example_description', + 'plugin_type_example' => 'plugin_type_example.description', 'simpletest_example' => 'simpletest_example_description', 'tour_example' => 'tour_example_description', ); diff --git a/field_example/field_example.routing.yml b/field_example/field_example.routing.yml index 86efe8c..3d600e1 100644 --- a/field_example/field_example.routing.yml +++ b/field_example/field_example.routing.yml @@ -4,4 +4,4 @@ field_example.description: defaults: _controller: '\Drupal\field_example\Controller\FieldExampleController::description' requirements: - _access: 'TRUE' + _permission: 'access content' diff --git a/file_example/tests/src/Kernel/StreamWrapperTest.php b/file_example/tests/src/Kernel/StreamWrapperTest.php index 530a9c0..cf74de7 100644 --- a/file_example/tests/src/Kernel/StreamWrapperTest.php +++ b/file_example/tests/src/Kernel/StreamWrapperTest.php @@ -15,7 +15,19 @@ use Drupal\Tests\file_example\MockSessionTrait; use Drupal\Core\DependencyInjection\ContainerBuilder; /** - * Base class for File_Example Drupal unit tests. + * Test of the Session Stream Wrapper Class. + * + * This test covers the PHP-level (i.e., not Drupal-specific) functions of the + * FileExampleSessionStreamWrapper class. It's not directly loaded here because + * it loads in background automatically as soon as the file_example module + * loads. + * + * The tests invoke the stream wrapper's functionality indirectly by calling + * PHP's file functions. + * + * @ingroup file_example + * @group file_example + * @group examples */ class StreamWrapperTest extends KernelTestBase { diff --git a/file_example/tests/src/Unit/SessionWrapperTest.php b/file_example/tests/src/Unit/SessionWrapperTest.php index 6f08d76..3aa9537 100644 --- a/file_example/tests/src/Unit/SessionWrapperTest.php +++ b/file_example/tests/src/Unit/SessionWrapperTest.php @@ -12,6 +12,20 @@ use Drupal\file_example\StreamWrapper\SessionWrapper; use Drupal\Tests\file_example\MockSessionTrait; /** * PHPUnit test for the SessionWrapper session manipulation class. + * + * The SessionWrapper class is a utility used to manipulate an associative + * array stored in the session object as if it were a file system. This + * greatly simplifies the code in our stream wrapper class, since + * SessionWrapper handles things like interacting with the session object, + * and also deals with translating path strings into nested arrays. + * + * The test class covers the equivalent of adding directories and files, + * reading and writing data nodes (our "files"), and clearing of arrays + * and data nodes (file deletion for purposes of the stream wrapper class). + * + * @ingroup file_example + * @group file_example + * @group examples */ class SessionWrapperTest extends UnitTestCase { diff --git a/js_example/js_example.routing.yml b/js_example/js_example.routing.yml index 603e5df..ba86225 100755 --- a/js_example/js_example.routing.yml +++ b/js_example/js_example.routing.yml @@ -4,7 +4,7 @@ js_example.info: _title: 'JavaScript Example Information' _controller: '\Drupal\js_example\Controller\JsExampleController::info' requirements: - _access: 'TRUE' + _permission: 'access content' js_example.weights: path: '/examples/js_example/weights' @@ -12,7 +12,7 @@ js_example.weights: _title: 'JS Example: see weighting in action' _controller: '\Drupal\js_example\Controller\JsExampleController::getJsWeightImplementation' requirements: - _access: 'TRUE' + _permission: 'access content' js_example.accordion: path: '/examples/js_example/accordion' @@ -20,4 +20,4 @@ js_example.accordion: _title: 'JS Example: jQuery UI accordion' _controller: '\Drupal\js_example\Controller\JsExampleController::getJsAccordionImplementation' requirements: - _access: 'TRUE' + _permission: 'access content' diff --git a/js_example/src/Tests/JsExampleTest.php b/js_example/src/Tests/JsExampleTest.php index a172e19..da003e5 100644 --- a/js_example/src/Tests/JsExampleTest.php +++ b/js_example/src/Tests/JsExampleTest.php @@ -23,17 +23,17 @@ class JsExampleTest extends WebTestBase { * * @var array */ - public static $modules = array('js_example'); + public static $modules = array('js_example', 'node'); /** * Test all the paths defined by our module. */ public function testJsExample() { - $paths = array( + $paths = [ 'examples/js_example', 'examples/js_example/weights', 'examples/js_example/accordion', - ); + ]; foreach ($paths as $path) { $this->drupalGet($path); $this->assertResponse(200, 'Visited ' . $path); diff --git a/node_type_example/node_type_example.routing.yml b/node_type_example/node_type_example.routing.yml index 6c31bdb..e3483e9 100644 --- a/node_type_example/node_type_example.routing.yml +++ b/node_type_example/node_type_example.routing.yml @@ -3,4 +3,4 @@ config_node_type_example.description: defaults: _controller: '\Drupal\node_type_example\Controller\NodeTypeExampleController::description' requirements: - _access: 'TRUE' + _permission: 'access content' diff --git a/page_example/page_example.routing.yml b/page_example/page_example.routing.yml index 5c970a1..e207227 100644 --- a/page_example/page_example.routing.yml +++ b/page_example/page_example.routing.yml @@ -20,7 +20,7 @@ page_example_description: _controller: '\Drupal\page_example\Controller\PageExampleController::description' _title: 'Page Example' requirements: - _access: 'TRUE' + _permission: 'access content' # If the user accesses http://example.com/?q=examples/page_example/simple, # the routing system will look for a route with that path. In this case it will diff --git a/phpunit_example/phpunit_example.routing.yml b/phpunit_example/phpunit_example.routing.yml index d7c3fbc..51f8e2d 100644 --- a/phpunit_example/phpunit_example.routing.yml +++ b/phpunit_example/phpunit_example.routing.yml @@ -5,4 +5,4 @@ phpunit_example_description: defaults: _controller: '\Drupal\phpunit_example\Controller\PHPUnitExampleController::description' requirements: - _access: 'TRUE' + _permission: 'access content' diff --git a/plugin_type_example/plugin_type_example.api.php b/plugin_type_example/plugin_type_example.api.php new file mode 100644 index 0000000..8ad888c --- /dev/null +++ b/plugin_type_example/plugin_type_example.api.php @@ -0,0 +1,23 @@ + $plugin_definition) { + $sandwich_plugin_info[$plugin_id]['foobar'] = t('We have altered this in the alter hook'); + } +} diff --git a/plugin_type_example/plugin_type_example.info.yml b/plugin_type_example/plugin_type_example.info.yml new file mode 100644 index 0000000..5777402 --- /dev/null +++ b/plugin_type_example/plugin_type_example.info.yml @@ -0,0 +1,7 @@ +name: Plugin type example +type: module +description: Provides an example of defining a plugin type. +package: Example modules +core: 8.x +dependencies: + - examples diff --git a/plugin_type_example/plugin_type_example.links.menu.yml b/plugin_type_example/plugin_type_example.links.menu.yml new file mode 100644 index 0000000..c607e36 --- /dev/null +++ b/plugin_type_example/plugin_type_example.links.menu.yml @@ -0,0 +1,3 @@ +plugin_type_example.description: + title: Plugin Type Example + route_name: plugin_type_example.description diff --git a/plugin_type_example/plugin_type_example.module b/plugin_type_example/plugin_type_example.module new file mode 100644 index 0000000..73855c9 --- /dev/null +++ b/plugin_type_example/plugin_type_example.module @@ -0,0 +1,55 @@ + $plugin_definition) { + $sandwich_plugin_info[$plugin_id]['foobar'] = t('We have altered this in the alter hook'); + } + + // The ham sandwich is more calorific in our system. Note that the string + // 'ham_sandwich' is the id name of the Ham Sandwich plugin, which is set + // in the annotation in + // \Drupal\plugin_type_example\Plugin\Sandwich\ExampleHamSandwich + $sandwich_plugin_info['ham_sandwich']['calories'] = 500; +} diff --git a/plugin_type_example/plugin_type_example.routing.yml b/plugin_type_example/plugin_type_example.routing.yml new file mode 100644 index 0000000..20b32ef --- /dev/null +++ b/plugin_type_example/plugin_type_example.routing.yml @@ -0,0 +1,8 @@ +# This defines our example page's path to the routing system. +plugin_type_example.description: + path: '/examples/plugin_type_example' + defaults: + _controller: '\Drupal\plugin_type_example\Controller\PluginTypeExampleController::description' + _title: 'Plugin Type Example' + requirements: + _permission: 'access content' diff --git a/plugin_type_example/plugin_type_example.services.yml b/plugin_type_example/plugin_type_example.services.yml new file mode 100644 index 0000000..bd9c129 --- /dev/null +++ b/plugin_type_example/plugin_type_example.services.yml @@ -0,0 +1,19 @@ +# This declares the plugin manager to the service container. +# For background information on the service container, see +# http://symfony.com/doc/current/book/service_container.html. +# Services declaration files such as this one are compiled to PHP code in +# sites/default/files/php/service_container, so changes here require that folder +# to be deleted in order to have Drupal notice them. +services: + # The machine name of the service. This is the string that must be passed to + # Drupal::service() to get the instantiated plugin manager. + plugin.manager.sandwich: + # This tells the service container the name of our plugin manager class. + class: Drupal\plugin_type_example\SandwichPluginManager + # The default parameters to pass to the class constructor, + # SandwichPluginManager::__construct(). + # Arguments beginning with @ are the names of other services that are being + # injected into this service. Many common ones are found in + # /core/core.services.yml. + # See https://drupal.org/node/2133171 for more detail. + arguments: ['@container.namespaces', '@cache.default', '@module_handler'] diff --git a/plugin_type_example/src/Controller/PluginTypeExampleController.php b/plugin_type_example/src/Controller/PluginTypeExampleController.php new file mode 100644 index 0000000..477c638 --- /dev/null +++ b/plugin_type_example/src/Controller/PluginTypeExampleController.php @@ -0,0 +1,129 @@ +sandwichManager = $sandwich_manager; + } + + /** + * Displays a page with an overview of our plugin type and plugins. + * + * Lists all the Sandwich plugin definitions by using methods on the + * \Drupal\plugin_type_example\SandwichPluginManager class. Lists out the + * description for each plugin found by invoking methods defined on the + * plugins themselves. You can find the plugins we have defined in the + * \Drupal\plugin_type_example\Plugin\Sandwich namespace. + */ + public function description() { + $build = array(); + + $build['intro'] = array( + '#markup' => t("This page lists the sandwich plugins we've created. The sandwich plugin type is defined in Drupal\\plugin_type_example\\SandwichPluginManager. The various plugins are defined in the Drupal\\plugin_type_example\\Plugin\\Sandwich namespace."), + ); + + // Get the list of all the sandwich plugins defined on the system from the + // plugin manager. + // Note that at this point, what we have is *definitions* of plugins, not + // the plugins themselves. + $sandwich_plugin_definitions = $this->sandwichManager->getDefinitions(); + + // Let's output a list of the plugin definitions we now have. + $items = array(); + foreach ($sandwich_plugin_definitions as $sandwich_plugin_definition) { + // Here we use various properties from the plugin definition. These values + // are defined in the annotation at the top of the plugin class: see + // ExampleHamSandwich. + $items[] = t("!id (calories: !calories, foobar: !foobar )", array( + '!id' => $sandwich_plugin_definition['id'], + '!calories' => $sandwich_plugin_definition['calories'], + '!foobar' => $sandwich_plugin_definition['foobar'], + )); + } + + // Add our list to the render array. + $build['plugin_definitions'] = array( + '#theme' => 'item_list', + '#title' => 'Sandwich plugin definitions', + '#items' => $items, + ); + + // If we want just a single plugin definition, we can use getDefinition(). + // This requires us to know the ID of the plugin we want. This is set in the + // annotation on the plugin class: see ExampleHamSandwich. + $ham_sandwich_plugin_definition = $this->sandwichManager->getDefinition('ham_sandwich'); + + // To get an actual plugin, we call createInstance() on the plugin manager, + // passing the ID of the plugin we want to load. Let's output a list of the + // actual plugins. + $items = array(); + // The array of plugin definitions is keyed by plugin id, so we can just use + // that to load our plugins. + foreach ($sandwich_plugin_definitions as $plugin_id => $sandwich_plugin_definition) { + // We now have a plugin! From here on it can be treated just as any other + // object: have its properties examined, methods called, etc. + $plugin = $this->sandwichManager->createInstance($plugin_id, array('of' => 'configuration values')); + $items[] = $plugin->description(); + } + + $build['plugins'] = array( + '#theme' => 'item_list', + '#title' => 'Sandwich plugins', + '#items' => $items, + ); + + return $build; + } + + /** + * {@inheritdoc} + * + * Override the parent method so that we can inject out sandwich plugin + * manager service into the controller. This is dependancy injection at work + * for a controller. Rather than access the global service container via + * \Drupal::service(), it's best practice to use dependancy injection. Notice + * our controller extends ControllerBase, which implements the + * ContainerInjectionInterface interface. As such we can implement a create + * method to control how our controller in instantiated. We do just that, + * passing in the sandwich plugin manager service that we need. + */ + public static function create(ContainerInterface $container) { + // Use the service container to instantiate a new instance of our + // controller. The string we pass is the machine name of the service, + // which is set in the plugin_type_example.services.yml file. We get back + // an instance of our SandwichPluginManager class, which is passed to the + // controller's constructor. + return new static($container->get('plugin.manager.sandwich')); + } + +} diff --git a/plugin_type_example/src/Plugin/Sandwich/ExampleHamSandwich.php b/plugin_type_example/src/Plugin/Sandwich/ExampleHamSandwich.php new file mode 100644 index 0000000..1c6df09 --- /dev/null +++ b/plugin_type_example/src/Plugin/Sandwich/ExampleHamSandwich.php @@ -0,0 +1,48 @@ +t('Ham, mustard, rocket, sun-dried tomatoes.'); + } + +} diff --git a/plugin_type_example/src/Plugin/Sandwich/ExampleMeatballSandwich.php b/plugin_type_example/src/Plugin/Sandwich/ExampleMeatballSandwich.php new file mode 100644 index 0000000..592ed07 --- /dev/null +++ b/plugin_type_example/src/Plugin/Sandwich/ExampleMeatballSandwich.php @@ -0,0 +1,48 @@ +t('Enjoy Italian style meatballs drenched in irresistible marinara sauce, served on freshly baked bread.'); + } + +} diff --git a/plugin_type_example/src/SandwichInterface.php b/plugin_type_example/src/SandwichInterface.php new file mode 100644 index 0000000..f1c7187 --- /dev/null +++ b/plugin_type_example/src/SandwichInterface.php @@ -0,0 +1,22 @@ +alterInfo('sandwich_info'); + + // This sets the caching method for our plugin definitions. Plugin + // definitions are cached using the provided cache backend. For our + // Sandwich plugin type, we've specified the @cache.default service be used + // in the plugin_type_example.services.yml file. The second argument is a + // cache key prefix. Out of the box Drupal with the default cache backend + // setup will store our plugin definition in the cache_default table using + // the sandwich_info key. All that is implementation details however, + // all we care about it that caching for our plugin definition is taken + // care of by this call. + $this->setCacheBackend($cache_backend, 'sandwich_info'); + } + +} diff --git a/plugin_type_example/src/Tests/PluginTypeExampleTest.php b/plugin_type_example/src/Tests/PluginTypeExampleTest.php new file mode 100644 index 0000000..1cc5e9a --- /dev/null +++ b/plugin_type_example/src/Tests/PluginTypeExampleTest.php @@ -0,0 +1,77 @@ +getDefinitions(); + + // Check we have only one sandwich plugin. + $this->assertEqual(count($sandwich_plugin_definitions), 2, 'There are two sandwich plugins defined.'); + + // Check some of the properties of the ham sandwich plugin definition. + $sandwich_plugin_definition = $sandwich_plugin_definitions['ham_sandwich']; + $this->assertEqual($sandwich_plugin_definition['calories'], 500, 'The ham sandwich plugin definition\'s calories property is set.'); + + // Check the alter hook fired and changed a property. + $this->assertEqual($sandwich_plugin_definition['foobar'], 'We have altered this in the alter hook', 'The ham sandwich plugin definition\'s foobar property is set, and was correctly altered by the plugin info alter hook.'); + + // Create an instance of the ham sandwich plugin to check it works. + $plugin = $manager->createInstance('ham_sandwich', array('of' => 'configuration values')); + + $this->assertEqual(get_class($plugin), 'Drupal\plugin_type_example\Plugin\Sandwich\ExampleHamSandwich', 'The ham sandwich plugin is instantiated and of the correct class.'); + } + + /** + * Test the output of the example page. + */ + public function testPluginExamplePage() { + $this->drupalGet('examples/plugin_type_example'); + $this->assertResponse(200, 'Example page successfully accessed.'); + + // Check we see the plugin id. + $this->assertText(t('ham_sandwich'), 'The plugin ID is output.'); + + // Check we see the plugin description. + $this->assertText(t('Ham, mustard, rocket, sun-dried tomatoes.'), 'The plugin description is output.'); + } + +} diff --git a/simpletest_example/simpletest_example.routing.yml b/simpletest_example/simpletest_example.routing.yml index 90f5822..c8a9318 100644 --- a/simpletest_example/simpletest_example.routing.yml +++ b/simpletest_example/simpletest_example.routing.yml @@ -5,4 +5,4 @@ simpletest_example_description: defaults: _controller: '\Drupal\simpletest_example\Controller\SimpleTestExampleController::description' requirements: - _access: 'TRUE' + _permission: 'access content' diff --git a/tablesort_example/tablesort_example.routing.yml b/tablesort_example/tablesort_example.routing.yml index 2fa88cd..1f232e6 100644 --- a/tablesort_example/tablesort_example.routing.yml +++ b/tablesort_example/tablesort_example.routing.yml @@ -3,4 +3,4 @@ tablesort_example_description: defaults: _controller: '\Drupal\tablesort_example\Controller\TableSortExampleController::description' requirements: - _access: 'TRUE' + _permission: 'access content'