view = $view; } public function generate(): void { $input = ROOT . '/views/' . $this->view . '.php'; $temporaryFiles = []; $sections = ['externalCss' => '', 'inlineCss' => '', 'externalJs' => '', 'inlineJs' => '']; $extra = ['', '']; do { $parser = new Parser($input); $fragment = $parser->parse(); $extends = $fragment->getExtends(); $this->generateAssets($fragment, $sections); $sections = array_merge($sections, $fragment->getSections()); //TODO: detect if section defined multiple times $extra[0] = $fragment->getExtra()[0] . $extra[0]; $extra[1] = $extra[1] . $fragment->getExtra()[1]; if ($extends === null) { $this->writeFinal($extra, $input, ROOT . '/cache/views/' . $this->view . '.php'); break; } $tmpFile = tempnam(sys_get_temp_dir(), 'mapg-view-'); $temporaryFiles[] = $tmpFile; $this->extendTemplate($sections, ROOT . '/views/' . $extends . '.php', $tmpFile); $input = $tmpFile; } while (true); foreach ($temporaryFiles as $tmpFile) { unlink($tmpFile); } } private function extendTemplate(array $sections, string $file, string $output): void { $inputFileHandle = fopen($file, 'r'); if (!$inputFileHandle) { throw new \Exception('Cannot open file ' . $file); } $outputFileHandle = fopen($output, 'w'); if (!$outputFileHandle) { throw new \Exception('Cannot open file ' . $output . 'for writing.'); } $lineNumber = 0; while (($line = fgets($inputFileHandle)) !== false) { ++$lineNumber; if (preg_match('/^\s*@yields\(\'([\w\/]+)\'\)\s*$/', $line, $matches)) { if (isset($sections[$matches[1]])) { fwrite($outputFileHandle, $sections[$matches[1]]); } } else { fwrite($outputFileHandle, $line); } } fclose($inputFileHandle); fclose($outputFileHandle); } private function writeFinal(array $extra, string $file, string $output): void { $dirname = pathinfo($output, PATHINFO_DIRNAME); if (!is_dir($dirname)) { mkdir($dirname, 0755, true); } $inputFileHandle = fopen($file, 'r'); if (!$inputFileHandle) { throw new \Exception('Cannot open file ' . $file); } $outputFileHandle = fopen($output, 'w'); if (!$outputFileHandle) { throw new \Exception('Cannot open file ' . $output . 'for writing.'); } fwrite($outputFileHandle, $extra[0]); while (($line = fgets($inputFileHandle)) !== false) { fwrite($outputFileHandle, $line); } fwrite($outputFileHandle, $extra[1]); fclose($inputFileHandle); fclose($outputFileHandle); } private function generateAssets(ParsedFragment $fragment, array &$sections) { foreach ($fragment->getCss() as $cssFile) { $asset = $this->parseAsset($cssFile); if (isset($asset['code'])) { $sections['inlineCss'] .= '' . PHP_EOL; } elseif (isset($asset['file'])) { $sections['externalCss'] .= '' . PHP_EOL; } } foreach ($fragment->getJs() as $jsFile) { $asset = $this->parseAsset($jsFile); if (isset($asset['code'])) { $sections['inlineJs'] .= '' . PHP_EOL; } elseif (isset($asset['file'])) { $sections['externalJs'] .= '' . PHP_EOL; } } } private function parseAsset(string $asset): array { $output = []; if (preg_match('/^[\w\/\.]+$/', $asset)) { if ( empty($_ENV['DEV']) && filesize(ROOT . '/public/static/' . $asset) < self::INLINE_ASSET_LIMIT ) { $output['code'] = file_get_contents(ROOT . '/public/static/' . $asset); } else { $output['file'] = '/' . $asset . '?rev='; } } else { $output['file'] = $asset; } return $output; } }