MAPG-89 add classes that can link views into one PHP
This commit is contained in:
parent
ee6aa59253
commit
c48bbdc3c2
103
src/View/Linker.php
Normal file
103
src/View/Linker.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php namespace MapGuesser\View;
|
||||||
|
|
||||||
|
class Linker
|
||||||
|
{
|
||||||
|
private string $view;
|
||||||
|
|
||||||
|
public function __construct(string $view)
|
||||||
|
{
|
||||||
|
$this->view = $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generate(): void
|
||||||
|
{
|
||||||
|
$input = ROOT . '/views/' . $this->view . '.php';
|
||||||
|
|
||||||
|
$temporaryFiles = [];
|
||||||
|
$sections = [];
|
||||||
|
$extra = ['', ''];
|
||||||
|
|
||||||
|
do {
|
||||||
|
$parser = new Parser($input);
|
||||||
|
$fragment = $parser->parse();
|
||||||
|
|
||||||
|
$extends = $fragment->getExtends();
|
||||||
|
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
}
|
32
src/View/ParsedFragment.php
Normal file
32
src/View/ParsedFragment.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php namespace MapGuesser\View;
|
||||||
|
|
||||||
|
class ParsedFragment
|
||||||
|
{
|
||||||
|
private ?string $extends;
|
||||||
|
|
||||||
|
private array $sections;
|
||||||
|
|
||||||
|
private array $extra;
|
||||||
|
|
||||||
|
public function __construct(?string $extends, array $sections, array $extra)
|
||||||
|
{
|
||||||
|
$this->extends = $extends;
|
||||||
|
$this->sections = $sections;
|
||||||
|
$this->extra = $extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtends(): ?string
|
||||||
|
{
|
||||||
|
return $this->extends;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSections(): array
|
||||||
|
{
|
||||||
|
return $this->sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtra(): array
|
||||||
|
{
|
||||||
|
return $this->extra;
|
||||||
|
}
|
||||||
|
}
|
128
src/View/Parser.php
Normal file
128
src/View/Parser.php
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<?php namespace MapGuesser\View;
|
||||||
|
|
||||||
|
class Parser
|
||||||
|
{
|
||||||
|
private string $file;
|
||||||
|
|
||||||
|
public function __construct(string $file)
|
||||||
|
{
|
||||||
|
$this->file = $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse(): ParsedFragment
|
||||||
|
{
|
||||||
|
|
||||||
|
$sectionOpen = null;
|
||||||
|
$extraOpen = false;
|
||||||
|
|
||||||
|
$extends = null;
|
||||||
|
$sections = [];
|
||||||
|
$extra = ['', ''];
|
||||||
|
|
||||||
|
$fileHandle = fopen($this->file, 'r');
|
||||||
|
if (!$fileHandle) {
|
||||||
|
throw new \Exception('Cannot open file ' . $this->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
$lineNumber = 0;
|
||||||
|
while (($line = fgets($fileHandle)) !== false) {
|
||||||
|
++$lineNumber;
|
||||||
|
|
||||||
|
if (($extendsMatched = $this->matchExtends($line)) !== null) {
|
||||||
|
if ($extends !== null) {
|
||||||
|
throw new \Exception('Error in file ' . $this->file . ' in line ' . $lineNumber . ' - There is already an \'@extends\' declared.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$extends = $extendsMatched;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($sectionMatched = $this->matchSection($line)) !== null) {
|
||||||
|
if ($extends === null) {
|
||||||
|
throw new \Exception('Error in file ' . $this->file . ' in line ' . $lineNumber . ' - \'@section\' has no meaning if view extends nothing.');
|
||||||
|
}
|
||||||
|
if ($sectionOpen !== null) {
|
||||||
|
throw new \Exception('Parse error in file ' . $this->file . ' in line ' . $lineNumber . ' - A \'@section\' is already open (no \'@endsection\' found).');
|
||||||
|
}
|
||||||
|
|
||||||
|
$sectionOpen = $sectionMatched;
|
||||||
|
$sections[$sectionOpen] = '';
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->matchEndSection($line)) {
|
||||||
|
if ($sectionOpen === null) {
|
||||||
|
throw new \Exception('Parse error in file ' . $this->file . ' in line ' . $lineNumber . ' - Cannot end section until no \'@section\' is open.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$sectionOpen = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->matchExtra($line)) {
|
||||||
|
if ($extraOpen) {
|
||||||
|
throw new \Exception('Parse error in file ' . $this->file . ' in line ' . $lineNumber . ' - An \'@extra\' is already open (no \'@endextra\' found).');
|
||||||
|
}
|
||||||
|
|
||||||
|
$extraOpen = true;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->matchEndExtra($line)) {
|
||||||
|
if (!$extraOpen) {
|
||||||
|
throw new \Exception('Parse error in file ' . $this->file . ' in line ' . $lineNumber . ' - Cannot end extra until no \'@extra\' is open.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$extraOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sectionOpen !== null) {
|
||||||
|
$sections[$sectionOpen] .= $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($extraOpen) {
|
||||||
|
$offset = $extends === null ? 0 : 1;
|
||||||
|
$extra[$offset] .= $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($fileHandle);
|
||||||
|
|
||||||
|
return new ParsedFragment($extends, $sections, $extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function matchExtends(string $line): ?string
|
||||||
|
{
|
||||||
|
if (preg_match('/^\s*@extends\(\'([\w\/]+)\'\)\s*$/', $line, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function matchSection(string $line): ?string
|
||||||
|
{
|
||||||
|
if (preg_match('/^\s*@section\(\'(\w+)\'\)\s*$/', $line, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function matchEndSection(string $line): bool
|
||||||
|
{
|
||||||
|
return preg_match('/^\s*@endsection(?:\(\))?\s*$/', $line);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function matchExtra(string $line): bool
|
||||||
|
{
|
||||||
|
return preg_match('/^\s*@extra(?:\(\))?\s*$/', $line);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function matchEndExtra(string $line): bool
|
||||||
|
{
|
||||||
|
return preg_match('/^\s*@endextra(?:\(\))?\s*$/', $line);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user