Import old Aitemu stuff.
This commit is contained in:
parent
69f2604b5b
commit
4cc0d69351
14 changed files with 945 additions and 0 deletions
|
@ -9,6 +9,7 @@
|
|||
"require": {
|
||||
"php": ">=7.2",
|
||||
"flashwave/aitemu": "dev-master#ac3050d17e3aa31a088caf15469bb51e5b165d40",
|
||||
"twig/twig": "~2.4",
|
||||
"nesbot/carbon": "~1.22",
|
||||
"illuminate/database": "~5.5",
|
||||
"illuminate/filesystem": "~5.5",
|
||||
|
|
115
src/IO/Directory.php
Normal file
115
src/IO/Directory.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Directory container.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class Directory
|
||||
{
|
||||
/**
|
||||
* Path to this directory.
|
||||
* @var string
|
||||
*/
|
||||
public $path;
|
||||
|
||||
/**
|
||||
* Fixes the path, sets proper slashes and checks if the directory exists.
|
||||
* @param string $path
|
||||
* @throws DirectoryDoesNotExistException
|
||||
*/
|
||||
public function __construct(string $path)
|
||||
{
|
||||
$this->path = static::fixSlashes(rtrim($path, '/\\'));
|
||||
|
||||
if (!static::exists($this->path)) {
|
||||
throw new DirectoryDoesNotExistException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets contents of this directory, subdirs get their own instance.
|
||||
* @param string $pattern
|
||||
* @return array
|
||||
*/
|
||||
public function files(string $pattern = '*'): array
|
||||
{
|
||||
return array_map(function ($path) {
|
||||
if (static::exists($path)) {
|
||||
return new static($path);
|
||||
}
|
||||
|
||||
return realpath($path);
|
||||
}, glob($this->path . '/' . $pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a directory if it doesn't already exist.
|
||||
* @param string $path
|
||||
* @throws DirectoryExistsException
|
||||
* @return Directory
|
||||
*/
|
||||
public static function create(string $path): Directory
|
||||
{
|
||||
$path = static::fixSlashes($path);
|
||||
|
||||
if (static::exists($path)) {
|
||||
throw new DirectoryExistsException;
|
||||
}
|
||||
|
||||
mkdir($path);
|
||||
|
||||
return new static($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a directory, recursively if requested. Use $purge with care!
|
||||
* @param string $path
|
||||
* @param bool $purge
|
||||
* @throws DirectoryDoesNotExistException
|
||||
*/
|
||||
public static function delete(string $path, bool $purge = false): void
|
||||
{
|
||||
$path = static::fixSlashes($path);
|
||||
|
||||
if (!static::exists($path)) {
|
||||
throw new DirectoryDoesNotExistException;
|
||||
}
|
||||
|
||||
if ($purge) {
|
||||
$dir = new static($path);
|
||||
|
||||
foreach ($dir->files() as $file) {
|
||||
if ($file instanceof self) {
|
||||
static::delete($file->path, true);
|
||||
} else {
|
||||
File::delete($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rmdir($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a directory exists.
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function exists(string $path): bool
|
||||
{
|
||||
$path = static::fixSlashes($path);
|
||||
return file_exists($path) && is_dir($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes operating system specific slashing.
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public static function fixSlashes(string $path): string
|
||||
{
|
||||
return str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
|
||||
}
|
||||
}
|
11
src/IO/DirectoryDoesNotExistException.php
Normal file
11
src/IO/DirectoryDoesNotExistException.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Thrown when a directory doesn't exist.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class DirectoryDoesNotExistException extends IOException
|
||||
{
|
||||
}
|
11
src/IO/DirectoryExistsException.php
Normal file
11
src/IO/DirectoryExistsException.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Thrown when a folder already exists.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class DirectoryExistsException extends IOException
|
||||
{
|
||||
}
|
333
src/IO/File.php
Normal file
333
src/IO/File.php
Normal file
|
@ -0,0 +1,333 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
use ErrorException;
|
||||
|
||||
/**
|
||||
* Wrapper for f* (file stream) functions and other cool stuff.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class File
|
||||
{
|
||||
/**
|
||||
* Open + Read flag.
|
||||
*/
|
||||
public const OPEN_READ = 'rb';
|
||||
|
||||
/**
|
||||
* Open + Write flag.
|
||||
*/
|
||||
public const OPEN_WRITE = 'xb';
|
||||
|
||||
/**
|
||||
* Open + Read + Write flag.
|
||||
*/
|
||||
public const OPEN_READ_WRITE = 'rb+';
|
||||
|
||||
/**
|
||||
* Create (truncates!) + Write flag.
|
||||
*/
|
||||
public const CREATE_WRITE = 'wb';
|
||||
|
||||
/**
|
||||
* Create (truncates!) + Read + Write flag.
|
||||
*/
|
||||
public const CREATE_READ_WRITE = 'wb+';
|
||||
|
||||
/**
|
||||
* Open + Write flag.
|
||||
*/
|
||||
public const OPEN_CREATE_WRITE = 'cb';
|
||||
|
||||
/**
|
||||
* Open or Create + Read + Write flag.
|
||||
*/
|
||||
public const OPEN_CREATE_READ_WRITE = 'cb+';
|
||||
|
||||
/**
|
||||
* Resource/stream container.
|
||||
* @var resource
|
||||
*/
|
||||
private $resource;
|
||||
|
||||
/**
|
||||
* Filename.
|
||||
* @var string
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* Real, fixed path.
|
||||
* @var string
|
||||
*/
|
||||
public $path = '';
|
||||
|
||||
/**
|
||||
* Filesize in bytes.
|
||||
* @var int
|
||||
*/
|
||||
public $size = 0;
|
||||
|
||||
/**
|
||||
* ID of file owner.
|
||||
* @var int
|
||||
*/
|
||||
public $owner = 0;
|
||||
|
||||
/**
|
||||
* ID of file's owning group.
|
||||
* @var int
|
||||
*/
|
||||
public $group = 0;
|
||||
|
||||
/**
|
||||
* Last time this file has been accessed.
|
||||
* @var int
|
||||
*/
|
||||
public $accessTime = 0;
|
||||
|
||||
/**
|
||||
* Last time this file has been modified.
|
||||
* @var int
|
||||
*/
|
||||
public $modifiedTime = 0;
|
||||
|
||||
/**
|
||||
* Current stream position.
|
||||
* @var int
|
||||
*/
|
||||
public $position = 0;
|
||||
|
||||
/**
|
||||
* Fixes path and opens resource.
|
||||
* @param string $path
|
||||
* @param string $mode
|
||||
* @throws FileDoesNotExistException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function __construct(string $path, string $mode)
|
||||
{
|
||||
$path = Directory::fixSlashes($path);
|
||||
$this->path = realpath($path);
|
||||
$this->name = basename($this->path);
|
||||
|
||||
try {
|
||||
$this->resource = fopen($path, $mode, false);
|
||||
} catch (ErrorException $e) {
|
||||
throw new FileDoesNotExistException($e->getMessage());
|
||||
}
|
||||
|
||||
if (!is_resource($this->resource)) {
|
||||
throw new IOException('Failed to create resource.');
|
||||
}
|
||||
|
||||
$this->updateMetaData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the meta data of the resource.
|
||||
*/
|
||||
private function updateMetaData(): void
|
||||
{
|
||||
$meta = fstat($this->resource);
|
||||
$this->size = intval($meta['size']);
|
||||
$this->owner = intval($meta['uid']);
|
||||
$this->group = intval($meta['gid']);
|
||||
$this->accessTime = intval($meta['atime']);
|
||||
$this->modifiedTime = intval($meta['mtime']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the position variable.
|
||||
*/
|
||||
private function updatePosition(): void
|
||||
{
|
||||
$this->position = ftell($this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the close method.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of a temporary file.
|
||||
* @param string $prefix
|
||||
* @return File
|
||||
*/
|
||||
public static function temp(string $prefix = 'Misuzu'): File
|
||||
{
|
||||
return new static(tempnam(sys_get_temp_dir(), $prefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a file exists.
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function exists(string $path): bool
|
||||
{
|
||||
$path = realpath(Directory::fixSlashes($path));
|
||||
return file_exists($path) && is_file($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file permanently, use with care!
|
||||
* @param string $path
|
||||
* @throws FileDoesNotExistException
|
||||
*/
|
||||
public static function delete(string $path): void
|
||||
{
|
||||
$path = realpath(Directory::fixSlashes($path));
|
||||
|
||||
if (!is_string($path) || !static::exists($path)) {
|
||||
throw new FileDoesNotExistException;
|
||||
}
|
||||
|
||||
unlink($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the resource context.
|
||||
*/
|
||||
public function close(): void
|
||||
{
|
||||
if (is_resource($this->resource)) {
|
||||
fclose($this->resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the position to 0.
|
||||
*/
|
||||
public function start(): void
|
||||
{
|
||||
rewind($this->resource);
|
||||
$this->updatePosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the position to the end of the file.
|
||||
*/
|
||||
public function end(): void
|
||||
{
|
||||
fseek($this->resource, 0, SEEK_END);
|
||||
$this->updatePosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position.
|
||||
* @param int $offset
|
||||
* @param bool $relative
|
||||
* @return int
|
||||
*/
|
||||
public function position(int $offset, bool $relative = false): int
|
||||
{
|
||||
fseek($this->resource, $offset, $relative ? SEEK_CUR : SEEK_SET);
|
||||
$this->updatePosition();
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current position is the end of the file.
|
||||
* @return bool
|
||||
*/
|
||||
public function atEOF(): bool
|
||||
{
|
||||
return feof($this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find the position of a string in the context.
|
||||
* @param string $string
|
||||
* @return int
|
||||
*/
|
||||
public function find(string $string): int
|
||||
{
|
||||
while ($this->position < $this->size) {
|
||||
$find = strpos($this->read(8192), $string);
|
||||
|
||||
if ($find !== false) {
|
||||
return $find + $this->position;
|
||||
}
|
||||
|
||||
$this->position($this->position + 8192);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the file and reads from it.
|
||||
* @param int $length
|
||||
* @throws IOException
|
||||
* @return string
|
||||
*/
|
||||
public function read(int $length = null): string
|
||||
{
|
||||
if ($length === null) {
|
||||
$length = $this->size;
|
||||
$this->start();
|
||||
}
|
||||
|
||||
flock($this->resource, LOCK_SH);
|
||||
$data = fread($this->resource, $length);
|
||||
flock($this->resource, LOCK_UN);
|
||||
|
||||
if ($data === false) {
|
||||
throw new IOException('Read failed.');
|
||||
}
|
||||
|
||||
$this->updateMetaData();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character at the current position.
|
||||
* @return string
|
||||
*/
|
||||
public function char(): string
|
||||
{
|
||||
return fgetc($this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the file, writes to the stream and flushes to file.
|
||||
* @param string $data
|
||||
* @param int $length
|
||||
* @throws IOException
|
||||
*/
|
||||
public function write(string $data, int $length = 0): void
|
||||
{
|
||||
if ($length > 0) {
|
||||
$length = strlen($data);
|
||||
}
|
||||
|
||||
flock($this->resource, LOCK_EX);
|
||||
$write = fwrite($this->resource, $data, $length);
|
||||
$flush = fflush($this->resource);
|
||||
flock($this->resource, LOCK_UN);
|
||||
|
||||
if ($write === false || $flush === false) {
|
||||
throw new IOException('Write failed.');
|
||||
}
|
||||
|
||||
$this->updateMetaData();
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as write except it moves to the end of the file first.
|
||||
* @param string $data
|
||||
* @param int $length
|
||||
*/
|
||||
public function append(string $data, int $length = 0): void
|
||||
{
|
||||
$this->end();
|
||||
$this->write($data, $length);
|
||||
}
|
||||
}
|
11
src/IO/FileDoesNotExistException.php
Normal file
11
src/IO/FileDoesNotExistException.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Thrown when a file doesn't exist.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class FileDoesNotExistException extends IOException
|
||||
{
|
||||
}
|
11
src/IO/FileExistsException.php
Normal file
11
src/IO/FileExistsException.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Thrown when a file already exists.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class FileExistsException extends IOException
|
||||
{
|
||||
}
|
11
src/IO/IOException.php
Normal file
11
src/IO/IOException.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Misuzu\IO;
|
||||
|
||||
/**
|
||||
* Holds the base I/O exception.
|
||||
* @package Misuzu\IO
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class IOException extends \Exception
|
||||
{
|
||||
}
|
98
src/Net/CIDR.php
Normal file
98
src/Net/CIDR.php
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
namespace Misuzu\Net;
|
||||
|
||||
/**
|
||||
* CIDR functions.
|
||||
* @package Misuzu\Net
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class CIDR
|
||||
{
|
||||
/**
|
||||
* Matches an IP to a CIDR range.
|
||||
* @param string $ip
|
||||
* @param string $range
|
||||
* @return bool
|
||||
*/
|
||||
public static function match($ip, $range)
|
||||
{
|
||||
[$net, $mask] = explode('/', $range);
|
||||
|
||||
$ipv = IP::version($ip);
|
||||
$rangev = IP::version($net);
|
||||
|
||||
if (!$ipv || !$rangev || $ipv !== $rangev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($ipv) {
|
||||
case IP::V6:
|
||||
return static::matchV6($ip, $net, $mask);
|
||||
|
||||
case IP::V4:
|
||||
return static::matchV4($ip, $net, $mask);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches an IPv4 to a CIDR range.
|
||||
* @param string $ip
|
||||
* @param string $net
|
||||
* @param int $mask
|
||||
* @return bool
|
||||
*/
|
||||
private static function matchV4($ip, $net, $mask)
|
||||
{
|
||||
$ip = ip2long($ip);
|
||||
$net = ip2long($net);
|
||||
$mask = -1 << (32 - $mask);
|
||||
return ($ip & $mask) === $net;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches an IPv6 to a CIDR range.
|
||||
* @param string $ip
|
||||
* @param string $net
|
||||
* @param int $mask
|
||||
* @return bool
|
||||
*/
|
||||
private static function matchV6($ip, $net, $mask)
|
||||
{
|
||||
$ip = inet_pton($ip);
|
||||
$net = inet_pton($net);
|
||||
$mask = static::createV6Mask($mask);
|
||||
return ($ip & $mask) === $net;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an IPv6 mask to bytes.
|
||||
* @param int $mask
|
||||
* @return int
|
||||
*/
|
||||
private static function createV6Mask($mask)
|
||||
{
|
||||
$range = str_repeat("f", $mask / 4);
|
||||
|
||||
switch ($mask % 4) {
|
||||
case 1:
|
||||
$range .= '8';
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$range .= 'c';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$range .= 'e';
|
||||
break;
|
||||
}
|
||||
|
||||
$range = str_pad($range, 32, '0');
|
||||
$range = pack('H*', $range);
|
||||
|
||||
return $range;
|
||||
}
|
||||
}
|
82
src/Net/IP.php
Normal file
82
src/Net/IP.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
namespace Misuzu\Net;
|
||||
|
||||
/**
|
||||
* IP functions.
|
||||
* @package Misuzu\Net
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class IP
|
||||
{
|
||||
public const V4 = 4;
|
||||
public const V6 = 6;
|
||||
|
||||
/**
|
||||
* Attempts to get the remote ip address, falls back to IPv6 localhost.
|
||||
* @return string
|
||||
*/
|
||||
public static function remote(string $fallback = '::1'): string
|
||||
{
|
||||
return $_SERVER['REMOTE_ADDR'] ?? $fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects IP version.
|
||||
* @param string $ip
|
||||
* @return int
|
||||
*/
|
||||
public static function version(string $ip): int
|
||||
{
|
||||
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
return static::V6;
|
||||
}
|
||||
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||
return static::V4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a printable IP address into an packed binary string.
|
||||
* @param string $ip
|
||||
* @throws NetInvalidAddressException
|
||||
* @return string
|
||||
*/
|
||||
public static function unpack($ip)
|
||||
{
|
||||
$ipv = static::version($ip);
|
||||
|
||||
if ($ipv === 6) {
|
||||
return current(unpack('A16', inet_pton($ip)));
|
||||
}
|
||||
|
||||
if ($ipv === 4) {
|
||||
return current(unpack('A4', inet_pton($ip)));
|
||||
}
|
||||
|
||||
throw new NetInvalidAddressException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a binary unpacked IP to a printable unpacked IP.
|
||||
* @param string $bin
|
||||
* @throws NetAddressTypeException
|
||||
* @return string
|
||||
*/
|
||||
public static function pack($bin)
|
||||
{
|
||||
$len = strlen($bin);
|
||||
|
||||
if ($len !== 4 && $len !== 16) {
|
||||
throw new NetAddressTypeException;
|
||||
}
|
||||
|
||||
return inet_ntop(pack("A{$len}", $bin));
|
||||
}
|
||||
}
|
11
src/Net/NetAddressTypeException.php
Normal file
11
src/Net/NetAddressTypeException.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Misuzu\Net;
|
||||
|
||||
/**
|
||||
* Thrown when Net doesn't know how to handle the IP type.
|
||||
* @package Misuzu\Net
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class NetAddressTypeException extends NetException
|
||||
{
|
||||
}
|
11
src/Net/NetException.php
Normal file
11
src/Net/NetException.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Misuzu\Net;
|
||||
|
||||
/**
|
||||
* Holds the base net exception.
|
||||
* @package Misuzu\Net
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class NetException extends \Exception
|
||||
{
|
||||
}
|
11
src/Net/NetInvalidAddressException.php
Normal file
11
src/Net/NetInvalidAddressException.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Misuzu\Net;
|
||||
|
||||
/**
|
||||
* Thrown when Net has to handle an invalid IP.
|
||||
* @package Misuzu\Net
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class NetInvalidAddressException extends NetException
|
||||
{
|
||||
}
|
228
src/TemplateEngine.php
Normal file
228
src/TemplateEngine.php
Normal file
|
@ -0,0 +1,228 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use Twig_Environment;
|
||||
use Twig_Loader_Filesystem;
|
||||
use Twig_SimpleFilter;
|
||||
use Twig_SimpleFunction;
|
||||
|
||||
/**
|
||||
* Wrapper for Twig.
|
||||
* @package Misuzu
|
||||
* @author flashwave <me@flash.moe>
|
||||
*/
|
||||
class TemplateEngine
|
||||
{
|
||||
/**
|
||||
* Utility |filters().
|
||||
*/
|
||||
private const UTILITY_FILTERS = [
|
||||
'json_decode',
|
||||
//'byte_symbol',
|
||||
];
|
||||
|
||||
/**
|
||||
* Utility functions().
|
||||
*/
|
||||
private const UTILITY_FUNCTIONS = [
|
||||
//'route',
|
||||
//'config',
|
||||
//'session_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Template file extension.
|
||||
*/
|
||||
private const FILE_EXTENSION = '.twig';
|
||||
|
||||
/**
|
||||
* Container for twig.
|
||||
* @var Twig_Environment
|
||||
*/
|
||||
private $twig;
|
||||
|
||||
private $loader;
|
||||
|
||||
/**
|
||||
* Render arguments.
|
||||
* @var array
|
||||
*/
|
||||
private $vars = [];
|
||||
|
||||
/**
|
||||
* Creates the twig environment and registers the utility filters and functions.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->loader = new Twig_Loader_Filesystem;
|
||||
$this->twig = new Twig_Environment($this->loader, [
|
||||
'cache' => false,
|
||||
'strict_variables' => true,
|
||||
'auto_reload' => false,
|
||||
'debug' => false,
|
||||
]);
|
||||
|
||||
foreach (static::UTILITY_FILTERS as $filter) {
|
||||
$this->addFilter($filter, $filter);
|
||||
}
|
||||
|
||||
foreach (static::UTILITY_FUNCTIONS as $function) {
|
||||
$this->addFunction($function, $function);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles debug mode on or off.
|
||||
* @param bool $mode
|
||||
*/
|
||||
public function debug(bool $mode): void
|
||||
{
|
||||
if ($this->twig->isDebug() === $mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($mode) {
|
||||
$this->twig->enableDebug();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->twig->disableDebug();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles cache auto reloading on or off.
|
||||
* @param bool $mode
|
||||
*/
|
||||
public function autoReload(bool $mode): void
|
||||
{
|
||||
if ($this->twig->isAutoReload() === $mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($mode) {
|
||||
$this->twig->enableAutoReload();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->twig->disableAutoReload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache path and alternatively turns it off.
|
||||
* @param string $path
|
||||
*/
|
||||
public function cache(bool $path): void
|
||||
{
|
||||
$this->twig->setCache($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a template path, first one is regarded as the master.
|
||||
* @param string $name
|
||||
* @param string $path
|
||||
*/
|
||||
public function addPath(string $name, string $path): void
|
||||
{
|
||||
if (count($this->loader->getPaths()) < 1) {
|
||||
$this->loader->addPath($path);
|
||||
}
|
||||
|
||||
$this->loader->addPath($path, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets render vars.
|
||||
* @param array $vars
|
||||
*/
|
||||
public function vars(array $vars): void
|
||||
{
|
||||
$this->vars = array_merge($this->vars, $vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts . to / and appends the file extension.
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
private function fixPath(string $path): string
|
||||
{
|
||||
// if the .twig extension if already present just assume that the path is already correct
|
||||
if (substr($path, 0 - strlen(static::FILE_EXTENSION)) === static::FILE_EXTENSION) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
return str_replace('.', '/', $path) . static::FILE_EXTENSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a template file.
|
||||
* @param string $path
|
||||
* @param array $vars
|
||||
* @return string
|
||||
*/
|
||||
public function render(string $path, array $vars = null): string
|
||||
{
|
||||
$path = static::fixPath($path);
|
||||
|
||||
if ($vars !== null) {
|
||||
$this->vars($vars);
|
||||
}
|
||||
|
||||
if (!$this->exists($path, Twig_Loader_Filesystem::MAIN_NAMESPACE)) {
|
||||
$namespace = $this->findNamespace($path);
|
||||
|
||||
if ($namespace !== null) {
|
||||
$path = '@' . $this->findNamespace($path) . '/' . $path;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->twig->render($path, $this->vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a function.
|
||||
* @param string $name
|
||||
* @param Callable $callable
|
||||
*/
|
||||
public function addFunction(string $name, Callable $callable = null): void
|
||||
{
|
||||
$this->twig->addFunction(new Twig_SimpleFunction($name, $callable === null ? $name : $callable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a filter.
|
||||
* @param string $name
|
||||
* @param Callable $callable
|
||||
*/
|
||||
public function addFilter(string $name, Callable $callable = null): void
|
||||
{
|
||||
$this->twig->addFilter(new Twig_SimpleFilter($name, $callable === null ? $name : $callable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds in which namespace a template exists.
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function findNamespace(string $path): string
|
||||
{
|
||||
foreach ($this->loader->getNamespaces() as $namespace) {
|
||||
if ($this->exists($path, $namespace)) {
|
||||
return $namespace;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a template exists.
|
||||
* @param string $path
|
||||
* @param string $namespace
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(string $path, string $namespace): bool
|
||||
{
|
||||
return $this->loader->exists('@' . $namespace . '/' . static::fixPath($path));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue