### Initialize DDEV Project and Install Drupal Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Standard DDEV commands to configure a project, start the environment, install Drupal using Composer, and set up Drush. ```sh mkdir d10m && cd d10m ddev config --project-type=drupal10 --docroot=web ddev start ddev composer create drupal/recommended-project:^10 ddev composer require drush/drush ddev drush site:install --account-name=admin --account-pass=admin -y ddev launch ``` -------------------------------- ### Clone Drupal Starter Project and Start Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Clone a pre-configured Drupal starter project, start DDEV, install Drupal, set up local settings and config sync, and import configuration. ```sh git clone git@github.com:selwynpolit/drupalstarter.git my-drupal-site cd my-drupal-site ddev start ddev drush site:install --account-name=admin --account-pass=admin -y # setup settings.local.php as above # setup your config sync directory ddev cim -y ``` -------------------------------- ### DDEV Drupal 10 Project Setup Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Commands to set up a new Drupal 10 project with DDEV, including configuration, starting the environment, installing Drupal, and adding Drush. ```sh mkdir dmulti && cd dmulti ddev config --project-type=drupal10 --docroot=web ddev start ddev composer create drupal/recommended-project:^10 ddev composer require drush/drush ddev drush site:install --account-name=admin --account-pass=admin -y ddev launch # or automatically log in with ddev launch $(ddev drush uli) ``` -------------------------------- ### Install Drupal 11 with DDEV Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Commands to configure and start a new Drupal 11 site using DDEV. This includes setting the PHP version and installing Drupal. ```sh mkdir my-drupal-site && cd my-drupal-site ddev config --project-type=drupal11 --php-version=8.3 --docroot=web ddev start ddev composer create drupal/recommended-project:^11 ddev composer require drush/drush ddev drush site:install --account-name=admin --account-pass=admin -y # Display a one-time link (CTRL/CMD + Click) from the command below to log in and edit your admin account details. ddev drush uli ## Or this will open a browser and you can log in with username: `admin` and password: `admin` ddev launch # Or automatically log in with ddev launch $(ddev drush uli) ``` -------------------------------- ### Install Node.js and Dependencies Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/contribute.md Installs the latest Node.js version, globally installs pnpm, and then installs project dependencies. Ensure nvm is installed and configured. ```sh nvm install node npm install -g pnpm pnpm install ``` -------------------------------- ### Copy Example Local Settings Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Copy the example local settings file to your default directory. This file will be used for local development configurations. ```sh cp web/sites/example.settings.local.php web/sites/default/settings.local.php ``` -------------------------------- ### Install All Composer Dependencies Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/composer.md Run `composer install` to install all dependencies, including those in the `require-dev` section, typically used for local development. ```sh composer install ``` ```sh composer install --dev ``` -------------------------------- ### nc Output Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Example output from `nc -z localhost 9000` indicating a successful connection to port 9000. ```text Connection to localhost port 9000 [tcp/cslistener] succeeded! ``` -------------------------------- ### Install Oh My Zsh Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/setup_mac.md Installs Oh My Zsh, a framework for managing Zsh configuration, by downloading and executing an installation script. ```bash sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" ``` -------------------------------- ### YAML Configuration File Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/config.md Example of a YAML file storing configuration data, typically found in the config sync directory. ```yaml pizza_rest_endpoint: 'https://pbx.pizza.com/pbx-service/' ``` -------------------------------- ### Copy .env Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/dtt.md Copies the example .env file to .env, which can be used to configure environment variables for DDev projects. ```bash cd web/core cp .env.example .env ``` -------------------------------- ### Install ESLint for JavaScript Consistency Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/javascript.md These bash commands install ESLint and the Drupal configuration, then run ESLint on custom modules and themes. Ensure Node.js, npm, and npx are installed first. ```bash # Before running these commands, install node.js, npm, and npx npm install eslint --save-dev npm i eslint-config-drupal npx eslint modules/custom/ npx eslint themes/custom/ ``` -------------------------------- ### lsof Output Example (php-fpm) Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Example output from `lsof -i TCP:9000` showing `php-fpm` listening on the Xdebug port. ```text COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME php-fpm 732 selwyn 7u IPv4 0x4120ed57a07e871f 0t0 TCP localhost:cslistener (LISTEN) php-fpm 764 selwyn 8u IPv4 0x4120ed57a07e871f 0t0 TCP localhost:cslistener (LISTEN) php-fpm 765 selwyn 8u IPv4 0x4120ed57a07e871f 0t0 TCP localhost:cslistener (LISTEN) ``` -------------------------------- ### netstat Output Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Example output from `netstat -an | grep 9000` indicating a listener on port 9000. ```text tcp46 0 0 *.9000 *.* LISTEN ``` -------------------------------- ### lsof Output Example (PhpStorm) Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Example output from `lsof -i TCP:9000` showing PhpStorm listening on the Xdebug port. ```text COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME phpstorm 24380 selwyn 525u IPv6 0xb7fc31a42f1fb36d 0t0 TCP *:cslistener (LISTEN) ``` -------------------------------- ### Install Subsite using DDEV Drush Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Use the `ddev drush site:install` command to install a subsite. This command requires specifying database URL, admin credentials, site name, database prefix, and subdirectory. ```sh ddev drush site:install --db-url=mysql://db:db@db:3306/db --account-name=admin --account-pass=admin --site-name="Subsite 3" --db-prefix=subsite3_ --sites-subdir=subsite3 --site-mail=subsite3@example.com ``` -------------------------------- ### Install ngrok Utility Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/setup_mac.md Installs ngrok, a tool for securely exposing local servers to the internet, often used with ddev share. ```bash brew install ngrok ``` -------------------------------- ### Example Custom List Style View Template Path Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/twig.md An example of a custom template file path for a specific view with a list style. ```path ~/Sites/dirt/web/themes/custom/dirt_bootstrap/templates/views/views-view-list--resource-library.html.twig ``` -------------------------------- ### PHPUnit Output Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/dtt.md Example output from running the TeamTest with PHPUnit, showing test results and variable dump. ```text PHPUnit 9.5.24 #StandWithUkraine Runtime: PHP 8.1.9 Configuration: /Users/selwyn/Sites/tea/phpunit.xml . 1 / 1 (100%) array(11) { uid = string(4) 5101 fullname = string(12) Voter 1 Test name = string(7) Voter 1 mail = string(24) voter1@mightycitizen.com status = string(1) 1 firstname = string(7) Voter 1 lastname = string(4) Test title = NULL phone = NULL roles = array(2) { 0 = string(13) authenticated 1 = string(9) srp_voter } voter_role = string(8) educator } Time: 00:00.773, Memory: 44.50 MB OK (1 test, 5 assertions) ``` -------------------------------- ### Composer.json require-dev Section Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/composer.md An example of the `require-dev` section in a `composer.json` file, listing development-specific packages. ```json "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "drupal/coder": "^8.3", "drupal/core-dev": "^10.3", "drupal/devel": "^5.2", "squizlabs/php_codesniffer": "^3.7" }, ``` -------------------------------- ### Site Configuration Example using ControllerBase Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/routes.md Fetches site name, slogan, and email from system.site configuration using the config shortcut. ```php // Get the site name, slogan and email from the system.site config. $config = $this->config('system.site'); $site_name = $config->get('name'); $slogan = $config->get('slogan'); $email = $config->get('mail'); ``` -------------------------------- ### Install Drupal Core Dev Dependencies Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/dtt.md Install the drupal/core-dev package to get PHPUnit and other development tools. Use --dev and --update-with-all-dependencies to ensure all necessary packages are installed. ```bash composer require drupal/core-dev --dev --update-with-all-dependencies ``` -------------------------------- ### PHPUnit Test Execution Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/dtt.md Example output of running PHPUnit tests, showing test status, runtime, and memory usage. ```text > $ vendor/bin/phpunit > docroot/modules/custom/tea_teks/modules/tea_teks_voting/tests/src/ExistingSite/VotingPageTest.php PHPUnit 9.5.24 #StandWithUkraine Runtime: PHP 8.1.9 Configuration: /Users/selwyn/Sites/tea/phpunit.xml . 1 / 1 (100%) Time: 00:00.830, Memory: 46.50 MB OK (1 test, 3 assertions) ``` -------------------------------- ### Install Module After Resolving Dependencies Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/composer.md After successfully updating conflicting dependencies, attempt to install the target module again. This example shows the successful installation of `drupal/csv_serialization` version 4.0.0 after resolving the previous conflict. ```sh composer require 'drupal/csv_serialization:^4.0' ./composer.json has been updated Running composer update drupal/csv_serialization Gathering patches for root package. Loading composer repositories with package information Updating dependencies Lock file operations: 0 installs, 1 update, 0 removals - Upgrading drupal/csv_serialization (3.0.0 => 4.0.0) Writing lock file Installing dependencies from lock file (including require-dev) Package operations: 0 installs, 1 update, 0 removals - Downloading drupal/csv_serialization (4.0.0) Gathering patches for root package. Gathering patches for dependencies. This might take a minute. - Upgrading drupal/csv_serialization (3.0.0 => 4.0.0): Extracting archive Package webmozart/path-util is abandoned, you should avoid using it. Use symfony/filesystem instead. Generating autoload files 99 packages you are using are looking for funding. Use the `composer fund` command to find out more! phpstan/extension-installer: Extensions installed Found 1 security vulnerability advisory affecting 1 package. Run "composer audit" for a full list of advisories. ``` -------------------------------- ### MySQL Command Line Client Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/queries.md Example of connecting to a MySQL database using the command line client and executing a query to list table sizes. ```sh ddev drush sqlc Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 134650 Server version: 5.7.42-0ubuntu0.18.04.1-log (Ubuntu) Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [db]> SELECT table_name, round(((data_length + index_length) / 1024 / 1024), 2) as SIZE_MB FROM information_schema.TABLES WHERE table_schema = DATABASE() ORDER BY SIZE_MB DESC LIMIT 10; ``` -------------------------------- ### Drush Update Database Command Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/upgrade.md This is an example of the output from `drush updb` when deprecated core modules are still installed, indicating a need for removal. ```bash $ drush updb [error] (Currently using Removed core modules You must add the following contributed modules and reload this page. * CKEditor [1] * Color [2] * Quick Edit [3] * RDF [4] These modules are installed on your site but are no longer provided by Core. For more information, read the documentation on deprecated modules. [5] [1] https://www.drupal.org/project/ckeditor [2] https://www.drupal.org/project/color [3] https://www.drupal.org/project/quickedit [4] https://www.drupal.org/project/rdf [5] https://www.drupal.org/node/3223395#s-recommendations-for-deprecated-modules ) ``` -------------------------------- ### Install and Configure NVM (Node Version Manager) Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/setup_mac.md Install NVM using Homebrew and set up the NVM directory. Add NVM to your shell's configuration file to load it automatically. ```bash brew install nvm ``` ```bash mkdir ~/.nvm ``` ```bash export NVM_DIR="$HOME/.nvm" [ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" # This loads nvm [ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion ``` ```bash nvm --version 0.39.7 ``` ```bash nvm install node ``` -------------------------------- ### Copy settings.local.php Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Copy the example local settings file to the default directory. This is the first step in configuring local development settings. ```bash $ cp sites/example.settings.local.php sites/default/settings.local.php ``` -------------------------------- ### Get Installed Module Version using Drush Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/hooks.md Use Drush to retrieve the currently installed update version for a specific module. Replace 'my_module' with the actual module name. ```bash # Get the installed version of a module drush ev "echo \Drupal::service('update.update_hook_registry')->getInstalledVersion('my_module');" ``` -------------------------------- ### Drush Command File Example Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/drush.md A complete Drush command file demonstrating command definition, argument and option handling, and service injection. ```php get('token'), $container->get('entity_type.manager'), ); } /** * Command description here. */ #[CLI\Command(name: 'drush_play2:command-name', aliases: ['foo'])] #[CLI\Argument(name: 'arg1', description: 'Argument description.')] #[CLI\Option(name: 'option-name', description: 'Option description')], #[CLI\Usage(name: 'drush_play2:command-name foo', description: 'Usage description')], public function commandName($arg1, $options = ['option-name' => 'default']) { $this->logger()->success(dt('Achievement unlocked.')); } /** * An example of the table output format. */ #[CLI\Command(name: 'drush_play2:token', aliases: ['token'])] #[CLI\FieldLabels(labels: [ 'group' => 'Group', 'token' => 'Token', 'name' => 'Name' ])] #[CLI\DefaultTableFields(fields: ['group', 'token', 'name'])] #[CLI\FilterDefaultField(field: 'name')], public function token($options = ['format' => 'table']): RowsOfFields { $all = $this->token->getInfo(); foreach ($all['tokens'] as $group => $tokens) { foreach ($tokens as $key => $token) { $rows[] = [ 'group' => $group, 'token' => $key, 'name' => $token['name'], ]; } } return new RowsOfFields($rows); } } ``` -------------------------------- ### Install Acquia CLI (acli) Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/setup_mac.md Download and install the Acquia Command Line Interface (acli) tool. Ensure the 'bin' directory is in your PATH for accessibility. ```bash curl -OL https://github.com/acquia/cli/releases/latest/download/acli.phar ``` ```bash chmod +x acli.phar ``` ```bash mv acli.phar ~/bin ``` ```bash acli auth:login ``` ```bash mkdir ~/bin ``` ```bash export PATH="$HOME/bin:$PATH" ``` -------------------------------- ### Get Total Size of Drupal Files Directory Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/general.md Use this command to get a human-readable summary of the total disk space used by the Drupal files directory. Ensure the path is correct for your Drupal installation. ```sh du -sh /var/www/html/docroot/sites/default/files/ ``` -------------------------------- ### Start Local Development Server Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/contribute.md Starts the Vitepress development server to preview changes locally. Access the site via the provided URL or by pressing 'o'. Use 'h' for help. ```sh pnpm run book:dev ``` -------------------------------- ### Install Hook to Set System Mail Interface Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/services.md An example of a Drupal install hook that modifies the system mail configuration to use a custom mail plugin. It checks if the 'hello_world' plugin already exists before adding it. ```php /* * \Drupal::configFactory() retrieves the configuration factory. * * This is mostly used to change the override settings on the configuration * factory. For example, changing the language or turning all overrides on * or off. */ /** * Implements hook_install(). */ function hello_world_install() { $config = \Drupal::configFactory()->getEditable('system.mail'); $mail_plugins = $config->get('interface'); if (in_array('hello_world', array_keys($mail_plugins))) { return; } $mail_plugins['hello_world'] = 'hello_world_mail'; $config->set('interface', $mail_plugins); $config->save(); } ``` -------------------------------- ### Perform a GET request using Drupal::httpClient Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/off-island.md This example demonstrates how to initialize the HTTP client and make a GET request to retrieve data from an external API. It shows how to access the response body and decode JSON data. ```php public function example1() { //Initialize client; $client = \Drupal::httpClient(); $uri = 'https://demo.ckan.org/api/3/action/package_list'; // Returns a GuzzleHttp\Psr7\Response. $response = $client->request('GET', 'https://demo.ckan.org/api/3/action/package_list'); // Or using the magic method. $response = $client->get($uri); // Returns a GuzzleHttp\Psr7\Stream. $stream = $response->getBody(); $json_data = Json::decode($stream); $help = $json_data['help']; $success = $json_data['success']; $result = $json_data['result'][0]; $msg = "
URI: " . $uri; $msg .= "
Help: " . $help; $msg .= "
Success: " . $success; $msg .= "
Result: " . $result; $build['content'] = [ '#type' => 'item', '#markup' => $this->t($msg), ]; return $build; } ``` -------------------------------- ### Generate One-Time Login for Main Site Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Use this command to get a one-time login link for the primary site in a multisite setup. ```sh ddev drush uli https://d10m.ddev.site/user/reset/1/1746197983/FzB_nebAqHFZmdsBJXpjYC_wjx7RAgjL352qZyaz81M/login ``` -------------------------------- ### Load Zsh Plugins Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/setup_mac.md Specify the plugins to load when Zsh starts. Add plugins wisely, as too many can slow down shell startup. ```zsh plugins=(git) ``` ```zsh plugins=(git z macos zsh-autosuggestions zsh-syntax-highlighting sudo) ``` ```zsh plugins=(git osx zsh-syntax-highlighting) ``` -------------------------------- ### Get Current Document Root Path Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/links.md Obtains the real path to the document root of the Drupal installation. Useful for file system operations. ```php $image_path = \Drupal::service('file_system')->realpath(); ``` -------------------------------- ### Example Script Execution and Output Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/general.md This demonstrates how to execute the './find-broken-links.sh' script with a log file and shows a sample of its output, indicating the source page and the broken URL found. ```bash ./find-broken-links.sh wget.log ``` ```text Source: https://www.austinprogressivecalendar.com/node/92 Broken: https://www.austinprogressivecalendar.com/sites/default/files/styles/huge/public/inserted-images/content_landod8_2019-02-08_13-23-14.png?itok=h9R-_TbV Source: https://www.austinprogressivecalendar.com/node/92 Broken: https://www.austinprogressivecalendar.com/sites/default/files/styles/medium/public/inserted-images/content_landod8_2019-02-08_13-23-14.png?itok=yyuKDoPc Source: https://www.austinprogressivecalendar.com/node/92 Broken: https://www.austinprogressivecalendar.com/sites/default/files/styles/huge/public/inserted-images/incoming_connection_from_xdebug_2019-02-08_13-44-31.png?itok=1YPHA40R ``` -------------------------------- ### Retrieve Drupal Date Range Field Values Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/dates.md Access the start and end values of a date range field using magic getters, get(), or getValue(). ```php // Magic getters. $start = $event_node->field_event_date_range->value $end = $event_node->field_event_date_range->end_value ``` ```php // Using get(). $start = $event_node->get('field_event_date_range')->value $end = $event_node->get('field_event_date_range')->end_value ``` ```php // Using getValue(). $start = $event_node->get('field_event_date_range')->getValue()[0]['value']; $end = $event_node->get('field_event_date_range')->getValue()[0]['end_value']; ``` -------------------------------- ### Define Batch Operations and Parameters Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/bq.md This example shows how to define a batch with multiple operations, passing parameters to the first operation. The `file` key specifies the path to the file containing the batch functions. ```php $batch = [ 'title' => t('Exporting'), 'operations' => [ ['my_function_1', [$account->id(), 'story']], ['my_function_2', []], ], 'finished' => 'my_finished_callback', 'file' => 'path_to_file_containing_my_functions', ]; batch_set($batch); // Only needed if not inside a form _submit handler. // Setting redirect in batch_process. batch_process('node/1'); ``` -------------------------------- ### Routing for Modal Examples Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/modals.md Defines routes for displaying modal dialogs. 'modal_examples.example1' renders links to open modals, while 'modal_examples.modal1' is a route that can display a modal directly, accepting parameters like 'program_id' and 'type'. ```yaml # Controller with buttons to open modals modal_examples.example1: path: '/modal-examples/example1' defaults: _title: 'Modal Examples (example1)' _controller: '\Drupal\modal_examples\Controller\ModalExamplesController::buildExample1' requirements: _permission: 'access content' # first modal modal_examples.modal1: path: '/modal-examples/modal1/{program_id}/{type}' defaults: _title: 'Modal 1 with parameters' _controller: '\Drupal\modal_examples\Controller\ModalExamplesController::buildModal1' requirements: _permission: 'access content' options: parameters: program_id: type: no_cache: 'TRUE' # Second modal # You can't use this route directly ``` -------------------------------- ### Implement hook_node_presave for Node Manipulation Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/nodes-and-fields.md Use hook_node_presave to modify node data before it is saved. This example handles 'catastrophe_notice' content type, calculating end dates and setting titles based on governmental body and start date. It also populates initial start and end dates for extensions. ```php /** * Implements hook_ENTITY_TYPE_presave(). */ function ogg_mods_node_presave(NodeInterface $node) { switch ($node->getType()) { case 'catastrophe_notice': $end_date = NULL != $node->get('field_cn_start_end_dates')->end_value ? $node->get('field_cn_start_end_dates')->end_value : 'n/a'; $govt_body = NULL != $node->field_cn_governmental_body->value ? $node->field_cn_governmental_body->value : 'Unnamed Government Body'; $start_date_val = $node->get('field_cn_start_date')->value; $accountProxy = " // Anonymous users automatically fill out the end_date. if (!$account->hasPermission('administer catastrophe notice')) { $days = intval($node->get('field_cn_suspension_length')->value) - 1; $end_date = DrupalDateTime::createFromFormat('Y-m-d', $start_date_val); $end_date->modify("+$days days"); $end_date = $end_date->format("Y-m-d"); $node->set('field_cn_end_date', $end_date); } // Always reset the title. $title = substr($govt_body, 0, 200) . " - $start_date_val"; $node->setTitle($title); /* * Fill in Initial start and end dates if this is an extension of * a previously submitted notice. */ $extension = $node->get('field_cn_extension')->value; if ($extension) { $previous_notice_nid = $node->get('field_cn_original_notice')->target_id; $previous_notice = Node::load($previous_notice_nid); if ($previous_notice) { $initial_start = $previous_notice->get('field_cn_start_date')->value; $initial_end = $previous_notice->get('field_cn_end_date')->value; $node->set('field_cn_initial_start_date', $initial_start); $node->set('field_cn_initial_end_date', $initial_end); } } break; } } ``` -------------------------------- ### Install jq (JSON Processor) Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/setup_mac.md Install 'jq', a lightweight and flexible command-line JSON processor. It's useful for parsing and manipulating JSON data. ```bash brew install jq ``` -------------------------------- ### Submit Form and Get Values Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/forms.md This function is called when a user submits the form. Extract entries from `$form_state` to process them. This example uses the State API to store values. ```php $values = $form_state->getValues(); $address1 = $values['footer_address1']; $address2 = $values['footer_address2']; $address3 = $values['footer_address3']; $email = $values['email']; $logo_url = $values['logo_url']; $facebook = $values['facebook']; $linkedin = $values['linkedin']; $instagram = $values['instagram']; $twitter = $values['twitter']; $youtube = $values['youtube']; ``` -------------------------------- ### Upgrading DDEV with Homebrew Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Command to upgrade the DDEV installation using Homebrew. After upgrading, it's recommended to run `ddev stop` and `ddev start` to reconfigure the project. ```bash brew upgrade ddev ``` -------------------------------- ### Symfony Route Definition with PHP Attributes Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/routes.md A basic Symfony controller example demonstrating route definition using PHP attributes. Ensure you have the necessary Symfony components installed. ```php // src/Controller/BlogController.php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; class BlogController extends AbstractController { #[Route('/blog', name: 'blog_list')] public function list(): Response { // ... } } ``` -------------------------------- ### Remove 'Team Content' Prefix with Regex in PHP Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/php.md This example shows how to remove a specific string, like 'Team Content', from the start of a string using `preg_replace` and a case-insensitive flag. ```php // Remove Team Content regardless of case from the beginning of a string. // #i is the case-insensitive flag. $bundle_label = preg_replace('#^(Team Content)#i', 'Team', $bundle_label); ``` -------------------------------- ### Controller example for multiTest Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/nodes-and-fields.md A comprehensive example from a controller demonstrating various uses of `smartMultiValueFieldSetter` with both text and entity reference fields, including taxonomy fields. ```php public function multiTest() { $str = '

Results

'; $node = Node::load(35); // Write to index 0, 1, 2. self::smartMultiValueFieldSetter($node, 'field_condiment', 'ketchup', 0); self::smartMultiValueFieldSetter($node, 'field_condiment', 'mayo', 1); self::smartMultiValueFieldSetter($node, 'field_condiment', 'mustard', 2); //$node->save(); $field_name = 'field_condiment'; $field_type = $node->get($field_name)->getFieldDefinition()->getType(); $contents = $node->get($field_name)->getValue(); $str .= "
Field: " . $field_name; $str .= ", type: " . $field_type; $str .= "
Values: "; foreach ($contents as $item) { $str .= $item['value'] . ', '; } self::smartMultiValueFieldSetter($node, 'field_condiment', 'mustard', 2, 'dummy', TRUE); $contents = $node->get($field_name)->getValue(); $str .= "
Values: "; foreach ($contents as $item) { $str .= $item['value'] . ', '; } self::smartMultiValueFieldSetter($node, 'field_condiment', 'ketchup', 1, 'dummy', TRUE); $contents = $node->get($field_name)->getValue(); $str .= "
Values: "; foreach ($contents as $item) { $str .= $item['value'] . ', '; } ``` -------------------------------- ### Drush Commands for Finding Routes Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/routes.md Examples of Drush commands used to inspect and find information about defined routes in a Drupal installation. These commands help in debugging and understanding routing configurations. ```sh $ drush route $ drush route --path=/user/1 $ drush route --name=update.status $ sh route --url=https://example.com/node/1 ``` -------------------------------- ### Install Devel Module and Devel Generate Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Installs the Devel module and its associated 'devel_generate' functionality for creating dummy content. Use this for development purposes only. ```sh ddev composer require drupal/devel --dev ddev drush en devel devel_generate -y ``` -------------------------------- ### Get URL String from Link Field Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/nodes-and-fields.md Safely retrieves the URL string from a link field, checking if the field is empty first. This is a simplified example for obtaining a URL from a link field. ```php $citation_link = $citation->get('field_link'); if (!$citation_link->isEmpty()) { $citation_link = $citation->field_link->first()->getUrl()->toString(); } ``` -------------------------------- ### Create and Log In as a New User Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/dtt.md This snippet demonstrates how to create a new user, optionally specifying a name and role, and then log in as that user. The user and their associated data will be automatically cleaned up after the test run. ```php // Creates a user. Will be automatically cleaned up at the end of the test. $user = $this->createUser([], 'Fred Bloggs', TRUE); $this->drupalLogin($user); $this->drupalGet('user'); ``` -------------------------------- ### Update Conflicting Dependency Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/composer.md If a dependency is blocking the installation of a required module version, try updating that dependency first. This example updates `drupal/views_data_export` to a version compatible with the desired `drupal/csv_serialization` version. ```sh composer update drupal/views_data_export Gathering patches for root package. Loading composer repositories with package information Updating dependencies Lock file operations: 0 installs, 1 update, 0 removals - Upgrading drupal/views_data_export (1.3.0 => 1.4.0) Writing lock file Installing dependencies from lock file (including require-dev) Package operations: 0 installs, 1 update, 0 removals - Downloading drupal/views_data_export (1.4.0) Gathering patches for root package. Gathering patches for dependencies. This might take a minute. - Upgrading drupal/views_data_export (1.3.0 => 1.4.0): Extracting archive - Applying patches for drupal/views_data_export https://www.drupal.org/files/issues/2021-02-17/2887450-40.patch (Add drush command views-data-export) ... ``` -------------------------------- ### Install bat (Syntax Highlighting Cat) Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/setup_mac.md Install 'bat', a utility that enhances the 'cat' command with syntax highlighting, making code output more readable. ```bash brew install bat ``` -------------------------------- ### Common Drush Alias Commands Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/drush.md Examples of common Drush alias commands for clearing cache, enabling modules, and dumping databases. These require global Drush installation or DDEV integration. ```sh drush @mysite cr drush @mysite en devel drush @mysite sql-dump >dbprod.sql drush rsync (To rsync files to/from sites. More on that below) ``` -------------------------------- ### Diagnose Composer Dependency Conflicts Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/composer.md Use `composer require` to attempt module installation. If it fails, analyze the error message to identify conflicting packages and their version requirements. This example shows a conflict with `drupal/views_data_export`. ```sh composer require 'drupal/csv_serialization:^4.0' ./composer.json has been updated Running composer update drupal/csv_serialization Gathering patches for root package. Loading composer repositories with package information Updating dependencies Your requirements could not be resolved to an installable set of packages. Problem 1 - drupal/views_data_export is locked to version 1.3.0 and an update of this package was not requested. - drupal/views_data_export 1.3.0 requires drupal/csv_serialization ~1.4 || ~2.0 || ~3 -> found drupal/csv_serialization[dev-1.x, dev-2.x, dev-3.x, 1.4.0, 1.5.0, 1.x-dev (alias of dev-1.x), 2.0.0-beta1, ..., 2.x-dev (alias of dev-2.x), 3.0.0-beta1, ..., 3.x-dev (alias of dev-3.x)] but it conflicts with your root composer.json require (^4.0). Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions. Installation failed, reverting ./composer.json and ./composer.lock to their original content. ``` -------------------------------- ### Configure Memcache Servers and Bins in settings.php Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/caching.md Add these settings to `web/sites/default/settings.php` to configure Memcached servers and specify which cache bins should use Memcached. A key prefix is recommended for multisite installations. ```php //Memcache settings $settings['memcache']['servers'] = ['memcached:11211' => 'default']; $settings['memcache']['bins'] = ['default' => 'default']; // For multisite installations, you can use a key prefix to avoid cache collisions. // This is useful if you have multiple sites using the same Memcached server. $settings['memcache']['key_prefix'] = 'abc_'; $settings['cache']['default'] = 'cache.backend.memcache'; // $settings['cache']['bins']['render'] = 'cache.backend.memcache'; $settings['cache']['bins']['bootstrap'] = 'cache.backend.database'; $settings['cache']['bins']['config'] = 'cache.backend.database'; $settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.memcache'; $settings['cache']['bins']['page'] = 'cache.backend.memcache'; $settings['memcache']['cache_lifetime'] = 3600; // Set a longer cache lifetime (e.g., 1 hour) ``` -------------------------------- ### Install Drupal 10 with DDEV Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Use these commands to set up a new Drupal 10 site locally with DDEV. Ensure Docker and DDEV are installed first. ```sh mkdir my-drupal10-site cd my-drupal10-site ddev config --project-type=drupal10 --docroot=web ddev start ddev composer create drupal/recommended-project:^10 # ddev config --update ddev composer require drush/drush ddev drush site:install --account-name=admin --account-pass=admin -y # Display a one-time link (CTRL/CMD + Click) from the command below to log in and edit your admin account details. ddev drush uli ## Or this will open a browser and you can log in with username: `admin` and password: `admin` ddev launch # Or automatically log in with ddev launch $(ddev drush uli) ``` -------------------------------- ### Extract URL String from Link Field Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/links.md Get the URL object from a link field, then convert it to a string using 'toString()'. This example handles potential null values and uses 'first()' for single-value fields. ```php if ($sf_contract) { // first() returns a Drupal\nlink\nPlugin\nFieldType\nLinkItem $vendor_url = $sf_contract->field_vendor_url->first(); if ($vendor_url) { // returns a Drupal\nCore\nUrl. $vendor_url = $vendor_url->getUrl(); $vendor_url_string = $vendor_url->toString(); } ``` -------------------------------- ### Get URI from External Link Field Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/links.md Obtain the URI string from an external link field. This example demonstrates accessing a nested link field through an entity reference and uses 'getUri()' or 'toString()' on the URL object. ```php $vendor_url = $node->field_sf_contract_ref->entity->field_vendor_url->first()->getUrl(); if ($vendor_url) { $vendor_url = $vendor_url->getUri(); //OR $vendor_url = $vendor_url->toString(); } ``` -------------------------------- ### Enable Local Development Services in settings.local.php Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/debugging.md Add this to your `settings.local.php` file to enable local development services by including the `development.services.yml` file. ```php /** * Enable local development services. */ $settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml'; ``` -------------------------------- ### Initialize Git Repository and Push Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/development.md Commands to initialize a Git repository, add all project files, make an initial commit, and push to a remote origin. Replace the origin URL with your actual repository URL. ```sh git init git add . git commit -m "first commit" git branch -M main # Use your own repo here git remote add origin git@github.com:hotshotcoderdude/ddev102.git git push -u origin main ``` -------------------------------- ### Set Cache with Permanent Expiration Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/caching.md This example demonstrates writing an array of data to the cache with a permanent expiration using \Drupal::cache()->set() and retrieving it using \Drupal::cache()->get(). Data is stored in the cache_default table. ```php // Write data to the cache. $cache_id = "expectations.program.$this->programNid.vote.$this->voteNumber.publisher.$this->publisherNid"; \Drupal::cache()->set($cache_id, $this->expectations, Cache::PERMANENT); // Read from the cache. $cache_data = \Drupal::cache()->get($cache_id); ``` -------------------------------- ### Handle HTTP basic authentication with Guzzle Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/off-island.md This example demonstrates how to make a GET request with HTTP basic authentication and includes exception handling for potential authentication failures. Errors are logged to Drupal's watchdog and displayed to the user. ```php public function example2() { $msg = ""; $client = \Drupal::httpClient(); $uri = 'https://api.github.com/user'; try { $request = $client->get($uri, [ 'auth' => ['username', 'password'] ]); $response = $request->getBody(); $msg .= "
GET"; $msg .= "
URI: " . $uri; } catch (ClientException $e) { \Drupal::messenger()->addError($e->getMessage()); watchdog_exception('guzzle_examples', $e); } catch (\Exception $e) { \Drupal::messenger()->addError($e->getMessage()); watchdog_exception('guzzle_examples', $e); } $build['content'] = [ '#type' => 'item', '#markup' => $this->t($msg), ]; return $build; } ``` -------------------------------- ### Show All Databases Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/queries.md The `SHOW DATABASES` command lists all available databases on the server. This provides an overview of the database landscape. ```sql MariaDB [db]> show databases; +--------------------+ | Database | +--------------------+ | db | | information_schema | | test | +--------------------+ 3 rows in set (0.015 sec) ``` -------------------------------- ### Send synchronous HTTP requests using magic methods Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/off-island.md This example illustrates the use of magic methods provided by Guzzle for sending various types of synchronous HTTP requests (GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT) to specified URIs. ```php $response = $client->get('http://httpbin.org/get'); $response = $client->delete('http://httpbin.org/delete'); $response = $client->head('http://httpbin.org/get'); $response = $client->options('http://httpbin.org/get'); $response = $client->patch('http://httpbin.org/patch'); $response = $client->post('http://httpbin.org/post'); $response = $client->put('http://httpbin.org/put'); ``` -------------------------------- ### Get File Size from Media Field in Drupal Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/nodes-and-fields.md This example demonstrates loading a media entity, checking for a specific document field, retrieving the file ID, loading the file entity, and formatting its size. Requires `Drupal ile ile ile.entity` and `Drupal ile ile ile.entity`. ```php use Drupal\media\Entity\Media; use Drupal\file\Entity\File; $media_id = $node->field_library_media->target_id; if ($media_id) { $media_item = Media::load($media_id); // Get the file. if ($media_item->hasField('field_media_document')) { $file_id = $media_item->field_media_document->getValue()[0]['target_id']; } if (isset($file_id)) { $file = File::load($file_id); if ($file) { // Get file size. $file_size = format_size($file->getSize()); // Set file size variable. $variables['file_size'] = $file_size; } } } ``` -------------------------------- ### Using Config Service Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/services.md Illustrates how to fetch site configuration values like the site name, slogan, and email address using the config service. The configuration object for 'system.site' is accessed here. ```php // Get the site name, slogan and email from the system.site config. $config = $this->config('system.site'); $site_name = $config->get('name'); $slogan = $config->get('slogan'); $email = $config->get('mail'); ``` -------------------------------- ### Retrieve GET Parameters Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/general.md Fetches a specific GET parameter from the request query. Can also retrieve all GET parameters. ```php $query = \Drupal::request()->query->get('name'); ``` ```php $query = \Drupal::request()->query->all(); $search_term = $query['query']; $collection = $query['collection']; ``` -------------------------------- ### Memcache settings output Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/caching.md Example output showing Memcache configuration for maximum total memory ('maxbytes') and maximum item size ('item_size_max'). ```text STAT maxbytes 134217728 STAT item_size_max 1048576 STAT ext_item_size 512 ``` -------------------------------- ### Install cloc (Count Lines of Code) Source: https://github.com/selwynpolit/d9book/blob/gh-pages/book/setup_mac.md Install 'cloc', a tool used to count lines of code in various programming languages within a project. ```bash brew install cloc ```