hasAttribute('role')) { return null; } $roles = explode(' ', strtolower(trim($element->getAttribute('role')))); $requiredParentMap = [ 'listitem' => ['list', 'group'], 'menuitem' => ['menu', 'menubar', 'group'], 'menuitemcheckbox' => ['menu', 'menubar'], 'menuitemradio' => ['menu', 'menubar'], 'tab' => ['tablist'], 'treeitem' => ['tree', 'group'], 'cell' => ['row'], 'gridcell' => ['row'], 'columnheader' => ['row'], 'rowheader' => ['row'], 'option' => ['listbox', 'group'], 'row' => ['grid', 'table', 'treegrid', 'rowgroup'] ]; foreach ($roles as $role) { if (isset($requiredParentMap[$role])) { $hasRequiredParent = $this->hasParentWithRole($element, $requiredParentMap[$role]); if (!$hasRequiredParent) { $expectedStr = implode(' veya ', $requiredParentMap[$role]); return $this->createViolation( $element, "ARIA rolü '{$role}' olan eleman gerekli üst eleman rollerinden hiçbirine sahip değil.", "Bu elemanı rolü {$expectedStr} olan bir üst elemanın içine yerleştirin." ); } } } return null; } /** * @param array $requiredRoles */ private function hasParentWithRole(DOMElement $element, array $requiredRoles): bool { $parent = $element->parentNode; while ($parent !== null && $parent instanceof DOMElement) { if ($parent->hasAttribute('role')) { $parentRoles = explode(' ', strtolower(trim($parent->getAttribute('role')))); foreach ($parentRoles as $pRole) { if (in_array($pRole, $requiredRoles)) { return true; } } } // For native HTML semantics fallback (e.g.