[[]], 'summary' => [[], [200], [200, true]], 'content' => [[]], 'getRawContent' => [[]], 'rawMarkdown' => [[]], 'value' => [['content'], ['route'], ['order'], ['ordering'], ['folder'], ['slug'], ['name'], /*['frontmatter'],*/ ['header.menu'], ['header.slug']], 'title' => [[]], 'menu' => [[]], 'visible' => [[]], 'published' => [[]], 'publishDate' => [[]], 'unpublishDate' => [[]], 'process' => [[]], 'slug' => [[]], 'order' => [[]], //'id' => [[]], 'modified' => [[]], 'lastModified' => [[]], 'folder' => [[]], 'date' => [[]], 'dateformat' => [[]], 'taxonomy' => [[]], 'shouldProcess' => [['twig'], ['markdown']], 'isPage' => [[]], 'isDir' => [[]], 'exists' => [[]], // Forms 'forms' => [[]], // Routing 'urlExtension' => [[]], 'routable' => [[]], 'link' => [[], [false], [true]], 'permalink' => [[]], 'canonical' => [[], [false], [true]], 'url' => [[], [true], [true, true], [true, true, false], [false, false, true, false]], 'route' => [[]], 'rawRoute' => [[]], 'routeAliases' => [[]], 'routeCanonical' => [[]], 'redirect' => [[]], 'relativePagePath' => [[]], 'path' => [[]], //'folder' => [[]], 'parent' => [[]], 'topParent' => [[]], 'currentPosition' => [[]], 'active' => [[]], 'activeChild' => [[]], 'home' => [[]], 'root' => [[]], // Translations 'translatedLanguages' => [[], [false], [true]], 'untranslatedLanguages' => [[], [false], [true]], 'language' => [[]], // Legacy 'raw' => [[]], 'frontmatter' => [[]], 'httpResponseCode' => [[]], 'httpHeaders' => [[]], 'blueprintName' => [[]], 'name' => [[]], 'childType' => [[]], 'template' => [[]], 'templateFormat' => [[]], 'extension' => [[]], 'expires' => [[]], 'cacheControl' => [[]], 'ssl' => [[]], 'metadata' => [[]], 'eTag' => [[]], 'filePath' => [[]], 'filePathClean' => [[]], 'orderDir' => [[]], 'orderBy' => [[]], 'orderManual' => [[]], 'maxCount' => [[]], 'modular' => [[]], 'modularTwig' => [[]], //'children' => [[]], 'isFirst' => [[]], 'isLast' => [[]], 'prevSibling' => [[]], 'nextSibling' => [[]], 'adjacentSibling' => [[]], 'ancestor' => [[]], //'inherited' => [[]], //'inheritedField' => [[]], 'find' => [['/']], //'collection' => [[]], //'evaluate' => [[]], 'folderExists' => [[]], //'getOriginal' => [[]], //'getAction' => [[]], ]; /** @var Grav */ protected $grav; /** * @return void */ protected function configure(): void { $this ->setName('page-system-validator') ->setDescription('Page validator can be used to compare site before/after update and when migrating to Flex Pages.') ->addOption('record', 'r', InputOption::VALUE_NONE, 'Record results') ->addOption('check', 'c', InputOption::VALUE_NONE, 'Compare site against previously recorded results') ->setHelp('The page-system-validator command can be used to test the pages before and after upgrade'); } /** * @return int */ protected function serve(): int { $input = $this->getInput(); $io = $this->getIO(); $this->setLanguage('en'); $this->initializePages(); $io->newLine(); $this->grav = $grav = Grav::instance(); $grav->fireEvent('onPageInitialized', new Event(['page' => $grav['page']])); /** @var Config $config */ $config = $grav['config']; if ($input->getOption('record')) { $io->writeln('Pages: ' . $config->get('system.pages.type', 'page')); $io->writeln('Record tests'); $io->newLine(); $results = $this->record(); $file = $this->getFile('pages-old'); $file->save($results); $io->writeln('Recorded tests to ' . $file->filename()); } elseif ($input->getOption('check')) { $io->writeln('Pages: ' . $config->get('system.pages.type', 'page')); $io->writeln('Run tests'); $io->newLine(); $new = $this->record(); $file = $this->getFile('pages-new'); $file->save($new); $io->writeln('Recorded tests to ' . $file->filename()); $file = $this->getFile('pages-old'); $old = $file->content(); $results = $this->check($old, $new); $file = $this->getFile('diff'); $file->save($results); $io->writeln('Recorded results to ' . $file->filename()); } else { $io->writeln('page-system-validator [-r|--record] [-c|--check]'); } $io->newLine(); return 0; } /** * @return array */ private function record(): array { $io = $this->getIO(); /** @var Pages $pages */ $pages = $this->grav['pages']; $all = $pages->all(); $results = []; $results[''] = $this->recordRow($pages->root()); foreach ($all as $path => $page) { if (null === $page) { $io->writeln('Error on page ' . $path . ''); continue; } $results[$page->rawRoute()] = $this->recordRow($page); } return json_decode(json_encode($results), true); } /** * @param PageInterface $page * @return array */ private function recordRow(PageInterface $page): array { $results = []; foreach ($this->tests as $method => $params) { $params = $params ?: [[]]; foreach ($params as $p) { $result = $page->$method(...$p); if (in_array($method, ['summary', 'content', 'getRawContent'], true)) { $result = preg_replace('/name="(form-nonce|__unique_form_id__)" value="[^"]+"/', 'name="\\1" value="DYNAMIC"', $result); $result = preg_replace('`src=("|\'|")/images/./././././[^"]+\\1`', 'src="\\1images/GENERATED\\1', $result); $result = preg_replace('/\?\d{10}/', '?1234567890', $result); } elseif ($method === 'httpHeaders' && isset($result['Expires'])) { $result['Expires'] = 'Thu, 19 Sep 2019 13:10:24 GMT (REPLACED AS DYNAMIC)'; } elseif ($result instanceof PageInterface) { $result = $result->rawRoute(); } elseif (is_object($result)) { $result = json_decode(json_encode($result), true); } $ps = []; foreach ($p as $val) { $ps[] = (string)var_export($val, true); } $pstr = implode(', ', $ps); $call = "->{$method}({$pstr})"; $results[$call] = $result; } } return $results; } /** * @param array $old * @param array $new * @return array */ private function check(array $old, array $new): array { $errors = []; foreach ($old as $path => $page) { if (!isset($new[$path])) { $errors[$path] = 'PAGE REMOVED'; continue; } foreach ($page as $method => $test) { if (($new[$path][$method] ?? null) !== $test) { $errors[$path][$method] = ['old' => $test, 'new' => $new[$path][$method]]; } } } return $errors; } /** * @param string $name * @return CompiledYamlFile */ private function getFile(string $name): CompiledYamlFile { return CompiledYamlFile::instance('cache://tests/' . $name . '.yaml'); } }