OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

TemplateScopeTest.php

3 KB
<?php

declare(strict_types=1);

/**
 * Vorlagen, die eine Klasse selbst einbindet, laufen in deren Geltungsbereich:
 * `$this` ist dort der Controller bzw. die Anwendung, nicht die View. Jeder
 * `$this->…`-Aufruf einer solchen Vorlage muss es an der einbindenden Klasse
 * also wirklich geben – sonst steht an der Stelle kein Text, sondern ein
 * Abbruch, und zwar erst beim Aufruf der Seite.
 */
return static function (): void {

    $wurzel = dirname(__DIR__);

    /**
     * Alle Vorlagen, die irgendwo unter src/ per include/require eingebunden
     * werden, mit der Klasse, in deren Geltungsbereich das geschieht.
     *
     * @return array<int,array{vorlage:string,klasse:string,quelle:string}>
     */
    $einbindungen = static function () use ($wurzel): array {
        $treffer = [];
        $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($wurzel . '/src'));
        foreach ($it as $datei) {
            if (!$datei->isFile() || $datei->getExtension() !== 'php') {
                continue;
            }
            $quelle = (string)file_get_contents($datei->getPathname());
            // include dirname(__DIR__, N) . '/templates/…php'
            if (!preg_match_all(
                '#(?:include|require)(?:_once)?\s+dirname\(__DIR__,\s*(\d+)\)\s*\.\s*\'(/templates/[^\']+\.php)\'#',
                $quelle,
                $m,
                PREG_SET_ORDER
            )) {
                continue;
            }
            preg_match('/^namespace\s+([^;]+);/m', $quelle, $ns);
            preg_match('/^(?:final\s+)?(?:abstract\s+)?class\s+(\w+)/m', $quelle, $kl);
            if (!isset($ns[1], $kl[1])) {
                continue;
            }
            foreach ($m as $einzel) {
                $vorlage = $wurzel . $einzel[2];
                if (!is_file($vorlage)) {
                    continue;
                }
                $treffer[] = [
                    'vorlage' => $einzel[2],
                    'klasse'  => trim($ns[1]) . '\\' . $kl[1],
                    'quelle'  => str_replace($wurzel . '/', '', $datei->getPathname()),
                ];
            }
        }
        return $treffer;
    };

    $stellen = $einbindungen();

    test('Es gibt Vorlagen, die ohne View eingebunden werden', function () use ($stellen) {
        assertTrue(count($stellen) >= 3, 'Die Suche findet die bekannten Einbindungen nicht mehr');
    });

    test('Jeder Aufruf einer solchen Vorlage existiert an der einbindenden Klasse', function () use ($stellen, $wurzel) {
        foreach ($stellen as $stelle) {
            $inhalt = (string)file_get_contents($wurzel . $stelle['vorlage']);
            preg_match_all('/\$this->([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/', $inhalt, $m);
            foreach (array_unique($m[1]) as $methode) {
                assertTrue(
                    method_exists($stelle['klasse'], $methode),
                    $stelle['vorlage'] . ' ruft $this->' . $methode . '() auf, '
                        . $stelle['klasse'] . ' (' . $stelle['quelle'] . ') kennt das nicht'
                );
            }
        }
    });

    test('Übersetzen und Maskieren heißt überall gleich', function () {
        // Dieselbe Schreibweise in Vorlagen, gleich ob View, Controller oder
        // Anwendung sie einbindet.
        foreach ([\OpenNIT\Core\View::class, \OpenNIT\Controllers\BaseController::class, \OpenNIT\Core\Application::class] as $klasse) {
            assertTrue(method_exists($klasse, 'te'), $klasse . ' kennt te() nicht');
        }
    });
};