| | 1. | Developing for Drupal 9 |
| 2 | | Introducing Drupal (for developers) |
| 2 | | How did we get too Drupal 9? |
| 4 | | Developing for Drupal |
| 5 | | Technologies that drive Drupal |
| 5 | | PHP |
| 5 | | Databases and MySQL |
| 5 | | The web server |
| 6 | | Drupal architecture |
| 10 | | Drupal's major subsystems |
| 15 | | Tools for developing in Drupal |
| 18 | | Summary |
| | 2. | Creating Your First Module |
| 20 | | Creating a module |
| 22 | | Your first hook implementation |
| 25 | | Route and controller |
| 29 | | Services |
| 33 | | Using services in Drupal |
| 33 | | Injecting the service into our Controller |
| 36 | | Invoked Controllers |
| 36 | | The Form API |
| 41 | | Altering forms |
| 43 | | Custom submit handlers |
| 44 | | Rendering forms |
| 45 | | Service dependencies |
| 47 | | Blocks |
| 47 | | Our first block plugin |
| 50 | | Block configuration |
| 52 | | Working with links |
| 52 | | The URL |
| 53 | | The link |
| 54 | | Which way to link? |
| 54 | | Event Dispatcher and redirects |
| 54 | | Redirecting from a Controller |
| 55 | | Redirecting from subscriber |
| 60 | | Dispatching events |
| 64 | | Summary |
| | 3. | Logging and Mailing |
| 66 | | Logging |
| 67 | | The Drupal logging theory |
| 68 | | Our own logger channel |
| 69 | | Our own logger |
| 71 | | Logging for Hello World |
| 73 | | Logging recap |
| 73 | | Mail API |
| 73 | | The theory behind the Mail API |
| 74 | | Implementing hook_mail() |
| 76 | | Sending emails |
| 79 | | Altering someone else's emails |
| 80 | | Custom mails plugins |
| 85 | | Mail API recap |
| 85 | | Tokens |
| 85 | | The Token API |
| 86 | | Uing Tokens |
| 87 | | Defining new tokens |
| 90 | | Tokens recap |
| 90 | | Summary |
| | | Theming |
| 92 | | Business logic versus presentation logic |
| 93 | | Twig |
| 94 | | Theme hooks |
| 97 | | Theme hook suggestions |
| 98 | | Render arrays |
| 99 | | The structure of a render array |
| 101 | | The render pipeline |
| 103 | | Assets and libraries |
| 103 | | Libraries |
| 106 | | Common theme hooks |
| 107 | | Lists |
| 108 | | Links |
| 109 | | Tables |
| 110 | | Attributes |
| 111 | | Layouts |
| 111 | | Defining layouts |
| 112 | | Rendering a layout |
| 113 | | Theming our Hello World module |
| 119 | | Summary |
| | 5. | Menus and Menu Links |
| 122 | | The menu system |
| 122 | | Menus |
| 122 | | Menu links |
| 126 | | MenuLink trees |
| 126 | | Rendering menus |
| 129 | | Working with menu links |
| 129 | | Defining menu links |
| 130 | | Manipulating menu links |
| 131 | | Defining local tasks |
| 132 | | Defining local actions |
| 133 | | Defining contextual links |
| 136 | | Summary |
| | 6. | Data Modeling and Storage |
| 140 | | Different types of data storage |
| 141 | | State API |
| 142 | | TempStore |
| 144 | | Private TempStore |
| 145 | | Shared TempStore |
| 146 | | Tempstore recap |
| 146 | | UserData API |
| 148 | | Configuration API |
| 148 | | Introduction |
| 152 | | Configuration storage |
| 163 | | Configuration recap |
| 164 | | Entities |
| 164 | | Content versus configuratio enntity types |
| 166 | | Entity type plugins |
| 173 | | Fields |
| 179 | | Entity types recap |
| 179 | | TypedData |
| 179 | | Why TypedData? |
| 180 | | What is TypedData? |
| 181 | | The low-level API |
| 184 | | Content entities |
| 186 | | TypedData recap |
| 186 | | Interacting with the Entity API |
| 186 | | Querying entities |
| 189 | | Loading entities |
| 190 | | Reading entities |
| 195 | | Manipulating entities |
| 196 | | Creating entities |
| 197 | | Rendering content entities |
| 199 | | Pseudo fields |
| 201 | | Entity validation |
| 207 | | |
| | 7. | Your Own Custom Entity and Plugin Types |
| 210 | | Our custom content entity type |
| 227 | | Entity updates |
| 229 | | Our custom plugin type |
| 235 | | Our custom configuration etity type |
| 251 | | The Importer plugin |
| 257 | | Content entiity bundles |
| 271 | | Our own Drush command |
| 277 | | Summary |
| | 8. | The Database API |
| 280 | | The Schema API |
| 283 | | Running queries |
| 284 | | Select querier |
| 288 | | Pagers |
| 291 | | Insert queries |
| 292 | | Update queries |
| 292 | | Delete queries |
| 293 | | TTransactions |
| 294 | | Query alters |
| 297 | | Update hooks |
| 300 | | Post update hooks |
| 300 | | Summary |
| | 9. | Custom Fields |
| 304 | | A recap of Field type plugins |
| 306 | | Field type |
| 316 | | Field widget |
| 325 | | Field formatter |
| 331 | | Fields settings |
| 334 | | Using our custom field type as a base field |
| 336 | | Summary |
| | 10. | Access control |
| 338 | | Introduction to the Drupal access system |
| 339 | | Roles and permissions under the hood |
| 340 | | Defining permissions |
| 341 | | Checking the user credentials |
| 342 | | Route access |
| 345 | | Custom route access |
| 351 | | Programmatically checking access on routes |
| 352 | | Bonus - dynamic route options for access control |
| 357 | | CSRF protection on routes |
| 359 | | Altering routes |
| 361 | | Entity access |
| 364 | | Injecting services into Entity handlers |
| 366 | | Entity access hooks |
| 368 | | Field access |
| 369 | | Entity access in routes |
| 370 | | Node access grant |
| 378 | | Block access |
| 380 | | Summary |
| | 11. | Caching |
| 382 | | Introduction to caching |
| 384 | | Cacheability metadata |
| 384 | | Cache tags |
| 385 | | Cache contexts |
| 386 | | Max-age |
| 386 | | Using the cache metadata |
| 392 | | Placeholders and lazy building |
| 393 | | Lazy builders |
| 397 | | Using the Cache API |
| 400 | | Creating our own cache bin |
| 400 | | Summary |
| | 12. | JavaScript and the Ajax API |
| 404 | | JavaScript in Drupal |
| 404 | | Drupal behaviors |
| 409 | | Drupal settings |
| 410 | | The Ajax API |
| 410 | | Ajax links |
| 413 | | Ajax in forms |
| 427 | | The States (Frm) system |
| 429 | | Summary |
| | 13. | Internationalization and Languages |
| 432 | | Introduction to the multilingual ecosystem |
| 432 | | Language |
| 433 | | Content translation |
| 433 | | Configuration translation |
| 434 | | Interface translation |
| 435 | | Internationalization |
| 439 | | Content entities and the Translation API |
| 441 | | Summary |
| | 14. | Batches, Queues, and Cron |
| 444 | | Batch-powered update hooks |
| 446 | | Batch operations |
| 446 | | Creating the batch |
| 448 | | Batch operations |
| 453 | | Crop |
| 456 | | Queues |
| 456 | | Introduction in the Queue API |
| 457 | | Cron-based queues |
| 461 | | Processing a queue programmatically |
| 462 | | The Lock API |
| 465 | | Summary |
| | 15. | Views |
| 468 | | Entities in Views |
| 469 | | Exposing custom data to Views |
| 469 | | Views data |
| 478 | | Custom Views field |
| 482 | | Field configuration |
| 485 | | Custom Views filter |
| 490 | | Custom Views argument |
| 492 | | Views theming |
| 493 | | Views hooks |
| 493 | | Summary |
| | 16. | Working with Files and Images |
| 496 | | The filesystem |
| 498 | | Stream wrappers |
| 499 | | Managed versus unmanaged files |
| 499 | | Using the File and Image fields |
| 502 | | Working with managed files |
| 502 | | Attaching managed files to entities |
| 505 | | Helpful functions for dealing with managed files |
| 506 | | Managed file uploads |
| 519 | | Our own stream wrapper |
| 530 | | Working with unmanaged files |
| 531 | | Private filesystem |
| 534 | | Images |
| 535 | | Iage toolkits |
| 536 | | Image styles |
| 537 | | Rendering images |
| 538 | | Summary |
| | 17. | Automated Testing |
| 542 | | Testing methodologies in Drupal 9 |
| 543 | | PHPUnit |
| 545 | | Registering tets |
| 545 | | Unit tests |
| 551 | | Mocked dependencies |
| 557 | | Kernel tests |
| 558 | | TeamCleaner test |
| 560 | | Csvimporter test |
| 565 | | Functioonal tests |
| 565 | | Configuration for Functional tests |
| 566 | | Hello World page test |
| 570 | | Hello World form test |
| 572 | | Functional JavaScript tests |
| 572 | | Time test |
| 574 | | Csvimporter test |
| 580 | | Summary |
| | 18. | Drupal security |
| 584 | | Cross-Site Scripting (XSS) |
| 584 | | Sanitization methods in Drupal 9 |
| 586 | | Double escaping |
| 587 | | SQL Injection |
| 587 | | Cross-Site Request Forgery (CSRF) |
| 588 | | Summary |
| | | Other Books You May Enjoy |
| | | Index |