Drupal Standards Validation Checklist
Drupal Standards Validation Checklist
Comprehensive validation checklist for ensuring code quality and compliance with Drupal coding standards. Use this checklist before commits, during code review, and as part of CI/CD validation.
Quick Reference Checklist
Copy and use in commit messages or PR descriptions:
Drupal Standards Validation:
- [ ] declare(strict_types=1) at file top
- [ ] Type hints on ALL parameters
- [ ] Return types on ALL methods
- [ ] No \Drupal:: calls (dependency injection only)
- [ ] All lines <= 80 characters
- [ ] DocBlocks for classes and methods
- [ ] @param and @return tags complete
- [ ] No TODOs, HACKs, or temporary comments
- [ ] Proper namespace and use statements
- [ ] PHPCS and PHPStan passing
PHP File Standards
File Header & Declarations
-
<?phptag at the very first line (no blank lines before) -
declare(strict_types=1);as second line - Blank line after declare statement
- Proper namespace declaration:
namespace Drupal\module_name\Subdir; - Use statements alphabetically sorted
- No trailing whitespace anywhere
- Single blank line at end of file
Correct Example:
<?php declare(strict_types=1); namespace Drupal\agent_buildkit_eca\Plugin\ECA\Action; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\PluginBase; use Drupal\eca\Plugin\ECA\Action\ActionBase; use Symfony\Component\DependencyInjection\ContainerInterface;
Violations:
- Missing
declare(strict_types=1); - Blank lines before namespace
- Unsorted use statements (case-sensitive alphabetical)
- Use statements not properly organized
Code Formatting
Line Length (STRICT REQUIREMENT)
- All lines ** 80 characters** (Drupal standard)
- Lines >80 chars broken into multiple lines
- Indentation: 2 spaces (never tabs)
- No trailing whitespace on any line
Violation - Line Too Long:
// WRONG - 86 characters public function executeAgent(string $agent_id, array $inputs, string $runtime = 'native'): array {
Fix - Proper Breaking:
// CORRECT - Split across multiple lines public function executeAgent( string $agent_id, array $inputs, string $runtime = 'native' ): array {
Line Length Validation Commands:
# Check for lines > 80 characters grep -r ".{81,}" src/ --include="*.php" --include="*.module" # Count violations grep -r ".{81,}" src/ --include="*.php" | wc -l # Show line and number grep -n ".{81,}" src/Controller/*.php
Indentation & Spacing
- 2-space indentation (Drupal standard, not 4)
- Single space around operators:
$a = $b + $c - No space inside parentheses:
function($param)notfunction( $param ) - Blank line between method definitions
- Blank line after opening curly braces in classes
Correct:
class MyClass { protected $property; public function method(): void { $result = $this->calculate($value); } private function calculate(int $value): int { return $value * 2; } }
Control Structures
- Opening braces on same line:
if (...) {notif (...)\n{ - Closing braces on own line
- Single statement blocks still require braces
- Space before opening parenthesis in control structures
Violations:
// WRONG - Single line with no braces if ($condition) return $value; // WRONG - Brace on wrong line if ($condition) { return $value; } // WRONG - No space before parenthesis if($condition) { return $value; }
Correct:
// CORRECT if ($condition) { return $value; } if ($condition) { return $value; } else { return null; }
Array Formatting
- Use
[]syntax (notarray()) - Multi-line arrays: one element per line
- Trailing comma on last element (modern PHP)
- Proper indentation within arrays
Violations:
// WRONG - Old syntax $data = array('key' => 'value'); // WRONG - Multiple on one line $data = ['key1' => 'value1', 'key2' => 'value2']; // WRONG - Missing trailing comma $data = [ 'key1' => 'value1', 'key2' => 'value2' ];
Correct:
// CORRECT $data = [ 'key1' => 'value1', 'key2' => 'value2', ]; // Simple arrays can be inline $colors = ['red', 'green', 'blue'];
String Formatting
- Use double quotes for strings with variables
- Use single quotes for literal strings
- Use string interpolation:
"{$var}"not concatenation - Use
t()function for translatable strings - Multi-line strings: use heredoc/nowdoc
Violations:
// WRONG - Concatenation $message = 'Hello ' . $name . ' welcome to ' . $site; // WRONG - Single quotes with variable $url = 'http://example.com/' . $path; // WRONG - No translation wrapper echo 'Error: ' . $message;
Correct:
// CORRECT - Interpolation $message = "Hello {$name} welcome to {$site}"; // CORRECT - Translatable $message = $this->t('Error: @error', ['@error' => $error]); // CORRECT - Translation with replacement $message = $this->t( 'Hello @name, welcome to @site!', [ '@name' => $name, '@site' => $site, ] );
Type Safety & Type Hints
Parameter Type Hints
- ALL parameters have type hints
- No
mixedtype (use specific types) - Nullable types use
?Typesyntax:?string $value = null - Union types for multiple options:
string|int|array - Array types specific:
arrayorArrayInterface
Violations:
// WRONG - No type hints public function getData($id, $options) { // ... } // WRONG - Using mixed public function process(mixed $data): mixed { // ... } // WRONG - No null type public function getValue($default) { // ... }
Correct:
// CORRECT - All parameters typed public function getData( int $id, array $options = [] ): array { // ... } // CORRECT - Nullable when needed public function getValue(string $key, ?string $default = null): ?string { // ... } // CORRECT - Union type public function process(string|int|array $data): bool { // ... }
Return Type Hints
- ALL methods have return type declarations
- No
voidfor methods that return nothing (use explicit return type) - Return type before method body:
): Type { - Nullable return:
?TypeorType|null
Violations:
// WRONG - No return type public function getData($id) { return $this->storage->load($id); } // WRONG - Using void for method with side effects public function execute(): void { $this->doSomething(); return null; // Redundant }
Correct:
// CORRECT - Explicit return types public function getData(int $id): ?EntityInterface { return $this->storage->load($id); } public function execute(): void { $this->doSomething(); } public function getStatus(): string { return 'healthy'; }
Strict Type Checking
-
declare(strict_types=1);required in all files - No type coercion tricks
- Explicit casting when needed:
(int)$value,(string)$data - Use
is_*functions for type checking:is_string($value)
Example with strict types:
<?php declare(strict_types=1); namespace Drupal\agent_buildkit_eca; class TypeSafeExample { public function calculateTotal(int $base, int $percentage): float { // With strict_types=1, only int values accepted return $base + ($base * $percentage / 100); } public function processData(array $items): int { $count = 0; foreach ($items as $item) { if (is_string($item)) { $count++; } } return $count; } }
Documentation Standards
Class Documentation
- Class has DocBlock comment
- Starts with one-line description
- Followed by detailed description (if needed)
- Includes
@see,@link, etc. when referencing - Document all public properties
Correct Class Documentation:
/** * Client for communicating with agent-buildkit and Langflow APIs. * * Handles both native agent-buildkit execution and Langflow-based * runtime execution. Supports health checks and agent status monitoring. * * @see https://gitlab.com/blueflyio/agent-platform/agent-buildkit */ class AgentBuildKitClient { /** * The HTTP client. * * @var \GuzzleHttp\ClientInterface */ protected $httpClient; }
Method/Function Documentation
- ALL public and protected methods have DocBlocks
- First line: concise description (ends with period)
- Longer description: provide context and details
-
@param Type $name- for every parameter -
@param array $optionswith nested documentation -
@return Type- for every method -
@throws \ExceptionClass- for every exception -
@see URL- link to related documentation - Align parameter documentation for readability
Violation - Missing Documentation:
// WRONG - No DocBlock public function executeAgent($agent_id, $inputs, $runtime) { // ... } // WRONG - Incomplete documentation /** * Execute an agent. */ public function executeAgent(string $agent_id, array $inputs): array { // Missing @param and @return }
Correct - Complete Documentation:
/** * Execute an agent with provided inputs. * * Supports both native agent-buildkit and Langflow runtimes. * When $wait is true, blocks until execution completes. * * @param string $agent_id * The agent ID (or flow ID for Langflow). * @param array $inputs * Input data for the agent execution. * @param string $runtime * Runtime to use ('native' or 'langflow'). Defaults to 'native'. * @param bool $wait * Whether to wait for execution completion. Defaults to TRUE. * * @return array * Execution result with keys: * - executionId: Unique execution identifier * - status: Execution status (completed, failed, running) * - outputs: Agent output data * - metrics: Array of duration, cost, tokensUsed * * @throws \Exception * When API communication fails or JSON is invalid. * * @see \Drupal\agent_buildkit_eca\AgentBuildKitClient::executeLangflow() */ public function executeAgent( string $agent_id, array $inputs, string $runtime = 'native', bool $wait = TRUE ): array { // Implementation }
Documentation for Complex Parameters
- Array parameters document all keys
- Optional parameters marked clearly
- Default values documented
- Constraints documented (max length, allowed values)
Example - Complex Parameters:
/** * Process configuration options. * * @param array $options * Array of options with the following keys: * - timeout: (int, optional) Timeout in seconds. Defaults to 30. * - retries: (int, optional) Number of retries. Defaults to 3. * - headers: (array, optional) Custom HTTP headers. * - auth: (string, required) Bearer token for authentication. * * @return bool * TRUE if processed successfully, FALSE otherwise. * * @throws \InvalidArgumentException * If required 'auth' key is missing. */ public function processOptions(array $options): bool { // Implementation }
Dependency Injection & Services
Prohibition of Direct Drupal Calls
- NO
\Drupal::calls in services/classes - NO
\Drupal::service()anywhere - NO
\Drupal::entityTypeManager() - NO
\Drupal::configFactory() - NO
\Drupal::logger() - Exception: only in procedural hooks (Drupal limitation)
Violation - Direct Drupal Calls:
// WRONG - Direct service access public function myFunction() { $entity = \Drupal::entityTypeManager()->getStorage('node')->load(1); $config = \Drupal::configFactory()->get('my_module.settings'); \Drupal::logger('my_module')->info('Message'); }
Correct - Dependency Injection:
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Config\ConfigFactoryInterface; use Psr\Log\LoggerInterface; class MyService { protected EntityTypeManagerInterface $entityTypeManager; protected ConfigFactoryInterface $configFactory; protected LoggerInterface $logger; public function __construct( EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, LoggerInterface $logger ) { $this->entityTypeManager = $entity_type_manager; $this->configFactory = $config_factory; $this->logger = $logger; } public function myFunction(): void { $entity = $this->entityTypeManager->getStorage('node')->load(1); $config = $this->configFactory->get('my_module.settings'); $this->logger->info('Message'); } }
Constructor Injection Pattern
- All dependencies injected via constructor
- Use type-hinted parameters
- Store in protected properties
- Use in methods via
$this->property
Correct Pattern:
/** * Service for handling agent execution. */ class ExecuteAgent { /** * The agent buildkit client. * * @var \Drupal\agent_buildkit_eca\AgentBuildKitClient */ protected $agentClient; /** * Constructs ExecuteAgent service. * * @param \Drupal\agent_buildkit_eca\AgentBuildKitClient $agent_client * The agent client service. */ public function __construct(AgentBuildKitClient $agent_client) { $this->agentClient = $agent_client; } /** * Execute agent workflow. */ public function execute(): void { $result = $this->agentClient->executeAgent('agent_id', []); } }
Service Definition
- Service defined in
*.services.yml - Proper class reference
- All dependencies declared
- Tags documented if applicable
Correct services.yml:
services: agent_buildkit_eca.client: class: Drupal\agent_buildkit_eca\AgentBuildKitClient arguments: - '@http_client' - '@config.factory' agent_buildkit_eca.execute_action: class: Drupal\agent_buildkit_eca\Plugin\ECA\Action\ExecuteAgent arguments: - '@agent_buildkit_eca.client' tags: - { name: 'eca_action_plugin' }
Common Violations & Fixes
1. String Concatenation Issues
Violation:
$message = 'Hello ' . $name . ' welcome to ' . $site; $url = 'http://example.com/' . $path . '?id=' . $id;
Fix:
$message = "Hello {$name} welcome to {$site}"; $url = "http://example.com/{$path}?id={$id}";
2. Missing Parameter Type Hints
Violation:
public function getData($id, $options = []) { return $this->storage->load($id); }
Fix:
public function getData(int $id, array $options = []): ?EntityInterface { return $this->storage->load($id); }
3. No Return Type Declaration
Violation:
public function getStatus() { return $this->status; } public function execute() { $this->doSomething(); }
Fix:
public function getStatus(): string { return $this->status; } public function execute(): void { $this->doSomething(); }
4. Incomplete Documentation
Violation:
/** * Process data. */ public function processData(array $data, string $format, int $depth) { // Missing parameter and return documentation }
Fix:
/** * Process data with specified format and depth. * * Transforms data according to the given format specification, * respecting the maximum nesting depth. * * @param array $data * Data array to process. * @param string $format * Output format (json, xml, csv). * @param int $depth * Maximum nesting depth (1-10). * * @return string * Formatted output. * * @throws \InvalidArgumentException * If format is unsupported or depth is out of range. */ public function processData( array $data, string $format, int $depth ): string { // Implementation }
5. TODOs and HACKs
Violation:
public function importData() { // TODO: Add error handling $data = $this->fetchData(); // HACK: Temporary workaround for API inconsistency if (isset($data['result'])) { return $data['result']; } // @fixme: This needs refactoring return $data; }
Fix:
/** * Import data from remote source. * * Note: Temporary mapping for API inconsistency documented in * https://gitlab.com/blueflyio/project/-/issues/123 * * @return array * Imported data. * * @throws \RuntimeException * When data fetch fails. * * @see https://gitlab.com/blueflyio/project/-/issues/123 */ public function importData(): array { try { $data = $this->fetchData(); } catch (\Exception $e) { throw new \RuntimeException('Failed to fetch data: ' . $e->getMessage()); } // API returns 'result' key, normalize to 'data' for consistency return $data['result'] ?? $data; }
6. Unsorted Use Statements
Violation:
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\node\Entity\Node; use Drupal\Core\Form\FormBase; use GuzzleHttp\ClientInterface;
Fix - Alphabetically Sorted:
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Form\FormBase; use Drupal\node\Entity\Node; use GuzzleHttp\ClientInterface;
7. Line Length Violations
Violation - 96 characters:
public function executeAgent(string $agent_id, array $inputs, string $runtime = 'native', bool $wait = TRUE): array {
Fix - Under 80 characters:
public function executeAgent( string $agent_id, array $inputs, string $runtime = 'native', bool $wait = TRUE ): array {
PHPCS Validation
Running PHPCS
# Check entire module vendor/bin/phpcs --standard=Drupal,DrupalPractice modules/custom/my_module # Check specific file vendor/bin/phpcs --standard=Drupal src/Service/MyService.php # Check with all details vendor/bin/phpcs -vvv --standard=Drupal modules/custom/my_module # Dry-run auto-fix (preview changes) vendor/bin/phpcbf --standard=Drupal --dry-run src/ # Auto-fix violations vendor/bin/phpcbf --standard=Drupal src/
PHPCS Configuration
Create phpcs.xml.dist in project root:
<?xml version="1.0" encoding="UTF-8"?> <ruleset name="drupal_module"> <description>Drupal module coding standards</description> <arg name="extensions" value="php,module,inc,install,test,profile"/> <arg name="colors"/> <arg value="p"/> <exclude-pattern>*/vendor/*</exclude-pattern> <exclude-pattern>*/node_modules/*</exclude-pattern> <exclude-pattern>*/tests/fixtures/*</exclude-pattern> <rule ref="Drupal"/> <rule ref="DrupalPractice"/> <!-- Strict line length enforcement --> <rule ref="Drupal.Files.LineLength"> <properties> <property name="lineLimit" value="80"/> </properties> </rule> <file>.</file> </ruleset>
PHPStan Static Analysis
Running PHPStan
# Analyze module (level 6) vendor/bin/phpstan analyze modules/custom/my_module --level=6 # Analyze at highest level (8) vendor/bin/phpstan analyze --level=8 src/ # Generate baseline for existing errors vendor/bin/phpstan analyze --generate-baseline # View baseline vendor/bin/phpstan analyze --no-baseline
PHPStan Configuration
Create phpstan.neon in project root:
includes: - vendor/mglaman/phpstan-drupal/extension.neon parameters: level: 6 paths: - src - tests scanDirectories: - web/core - web/modules/contrib excludePaths: - */tests/fixtures/* - */vendor/* drupal: drupal_root: web
PHPStan Error Examples
Violation - Untyped property:
// Line 15: Property $client has no type hint protected $client;
Fix:
/** * HTTP client. * * @var \GuzzleHttp\ClientInterface */ protected $client;
Pre-Commit Validation
Pre-Commit Checklist
Before every commit, verify:
- All lines <= 80 characters:
grep -r ".{81,}" src/ -
declare(strict_types=1);in all PHP files - Type hints on all parameters
- Return types on all methods
- No
\Drupal::calls (except in hooks) - DocBlocks on all public/protected methods
- No TODOs, HACKs, or @fixme comments
- Alphabetically sorted use statements
- PHPCS passing:
vendor/bin/phpcs --standard=Drupal src/ - PHPStan passing:
vendor/bin/phpstan analyze --level=6 src/
Git Pre-Commit Hook
Create .husky/pre-commit (TypeScript):
#!/usr/bin/env node const { execSync } = require('child_process'); const fs = require('fs'); // Get PHP files being committed const output = execSync( 'git diff --cached --name-only --diff-filter=ACM | grep -E "\\.php$|\\.module$"' ).toString().trim(); if (!output) { process.exit(0); } const files = output.split('\n'); console.log('Running PHPCS validation...'); try { execSync(`vendor/bin/phpcs --standard=Drupal,DrupalPractice ${files.join(' ')}`); } catch (error) { console.error('PHPCS violations found. Please fix before committing.'); console.error('Run: vendor/bin/phpcbf --standard=Drupal ' + files.join(' ')); process.exit(1); } console.log('Running PHPStan analysis...'); try { execSync(`vendor/bin/phpstan analyze ${files.join(' ')} --level=6`); } catch (error) { console.error('PHPStan errors found. Please fix before committing.'); process.exit(1); } console.log('All validations passed!');
CI/CD Integration
GitLab CI Configuration
# .gitlab-ci.yml stages: - test - build phpcs: stage: test image: php:8.2-cli before_script: - composer install script: - vendor/bin/phpcs --standard=Drupal,DrupalPractice src/ modules/custom/ allow_failure: false only: - merge_requests - development - /^release\/.*$/ phpstan: stage: test image: php:8.2-cli before_script: - composer install script: - vendor/bin/phpstan analyze src/ modules/custom/ --level=6 allow_failure: false only: - merge_requests - development - /^release\/.*$/ design_taste: stage: test script: - buildkit drupal taste src/ modules/custom/ allow_failure: true only: - merge_requests
GitLab Merge Request Rules
Set in Settings > Merge Requests > Merge request approvals:
- Require approval from code owner
- Require all discussions resolved
- Block if CI pipeline fails
- Block if PHPCS/PHPStan fail
- Require test coverage >= 80%
Validation Automation
Quick Validation Script
#!/bin/bash # validate-drupal.sh MODULE_PATH="${1:-.}" ERRORS=0 echo "=== Drupal Standards Validation ===" echo "Module path: $MODULE_PATH" echo "" # Check line length echo "Checking line length (max 80 chars)..." LINE_VIOLATIONS=$(grep -r ".{81,}" "$MODULE_PATH" --include="*.php" --include="*.module" 2>/dev/null | wc -l) if [ "$LINE_VIOLATIONS" -gt 0 ]; then echo " ERROR: $LINE_VIOLATIONS lines exceed 80 characters" grep -r ".{81,}" "$MODULE_PATH" --include="*.php" --include="*.module" 2>/dev/null | head -5 ERRORS=$((ERRORS + 1)) fi # Check for missing declare strict_types echo "Checking for declare(strict_types=1)..." MISSING_STRICT=$(find "$MODULE_PATH" -name "*.php" -type f ! -exec grep -l "declare(strict_types=1)" {} \; | wc -l) if [ "$MISSING_STRICT" -gt 0 ]; then echo " WARNING: $MISSING_STRICT PHP files missing declare(strict_types=1)" fi # Check for Drupal:: calls echo "Checking for \\Drupal:: direct calls..." DRUPAL_CALLS=$(grep -r '\\Drupal::' "$MODULE_PATH" --include="*.php" 2>/dev/null | grep -v '//' | wc -l) if [ "$DRUPAL_CALLS" -gt 0 ]; then echo " WARNING: $DRUPAL_CALLS direct \\Drupal:: calls found" grep -r '\\Drupal::' "$MODULE_PATH" --include="*.php" 2>/dev/null | grep -v '//' | head -3 fi # Check for TODOs and HACKs echo "Checking for TODOs and HACKs..." ISSUES=$(grep -r -i '// TODO\|// HACK\|@fixme' "$MODULE_PATH" --include="*.php" 2>/dev/null | wc -l) if [ "$ISSUES" -gt 0 ]; then echo " WARNING: $ISSUES TODOs/HACKs found" grep -r -i '// TODO\|// HACK\|@fixme' "$MODULE_PATH" --include="*.php" 2>/dev/null | head -3 fi # Run PHPCS if command -v vendor/bin/phpcs &> /dev/null; then echo "" echo "Running PHPCS..." vendor/bin/phpcs --standard=Drupal,DrupalPractice "$MODULE_PATH" 2>/dev/null || ERRORS=$((ERRORS + 1)) fi # Run PHPStan if command -v vendor/bin/phpstan &> /dev/null; then echo "" echo "Running PHPStan..." vendor/bin/phpstan analyze "$MODULE_PATH" --level=6 2>/dev/null || ERRORS=$((ERRORS + 1)) fi echo "" echo "=== Validation Complete ===" if [ $ERRORS -eq 0 ]; then echo "All checks passed!" exit 0 else echo "Errors found: $ERRORS" exit 1 fi
Usage:
chmod +x validate-drupal.sh ./validate-drupal.sh src/ ./validate-drupal.sh modules/custom/my_module
Code Review Checklist
When reviewing Drupal code, verify:
File Structure
-
<?phpis first line -
declare(strict_types=1);is second line - Proper namespace and use statements
- No trailing whitespace
Type Safety
- All parameters have type hints
- All methods have return types
- No
mixedtypes used - Strict types enforced
Documentation
- Class has DocBlock
- All public methods documented
- @param tags for all parameters
- @return tags on all methods
- @throws tags for exceptions
Code Quality
- No lines > 80 characters
- 2-space indentation consistent
- Proper brace placement
- No TODOs or HACKs
- No
\Drupal::calls (except in hooks)
Testing
- Unit tests for all public methods
- Test coverage >= 80%
- Tests follow Drupal standards
- Tests pass locally and in CI
Performance
- No unnecessary loops
- No repeated database queries
- Proper caching where needed
- Efficient algorithms
IDE Integration
PHPStorm Configuration
-
Settings > PHP > Quality Tools > PHP_CodeSniffer
- Path to PHP CodeSniffer:
/path/to/vendor/bin/phpcs - Coding standard: Drupal, DrupalPractice
- Path to PHP CodeSniffer:
-
Settings > PHP > Quality Tools > PHPStan
- Path to PHPStan:
/path/to/vendor/bin/phpstan - Configuration file:
/path/to/phpstan.neon
- Path to PHPStan:
-
Settings > Editor > Inspections
- Enable: PHP_CodeSniffer validation
- Enable: PHPStan validation
VS Code Configuration
Install extensions:
ikappas.phpcs- PHP CodeSnifferSanderRonde.phpstan-vscode- PHPStan
Configure .vscode/settings.json:
{ "phpcs.enable": true, "phpcs.standard": "Drupal,DrupalPractice", "phpcs.executablePath": "${workspaceFolder}/vendor/bin/phpcs", "phpstan.enabled": true, "phpstan.path": "${workspaceFolder}/vendor/bin/phpstan", "phpstan.configFile": "${workspaceFolder}/phpstan.neon" }
Troubleshooting
PHPCS Not Working
# Verify installation vendor/bin/phpcs --version # Reinstall composer require --dev drupal/coder dealerdirect/phpcodesniffer-composer-installer # Clear cache rm -rf ~/.phpcs-cache
PHPStan Errors
# Update baseline vendor/bin/phpstan analyze --generate-baseline # Clear cache vendor/bin/phpstan clear-result-cache # Verbose output vendor/bin/phpstan analyze -vvv
Line Length Issues
# Find problem files grep -r ".{81,}" src/ --include="*.php" -l # Fix with PHPCBF vendor/bin/phpcbf --standard=Drupal src/ # Manual inspection grep -rn ".{81,}" src/Controller/MyController.php
Resources
- Drupal Coding Standards
- PHPCS Wiki
- PHPStan User Guide
- Drupal Coder Documentation
- PHP Type Declarations
Related Documentation
- Drupal Coding Standards - Full standards guide
- Module Development - Module creation guide
- Architecture Overview - System architecture
Last Updated: 2026-01-08 Maintained by: Agent Platform Development Team