mirror of
https://github.com/envoyr/nginx-configurator.git
synced 2026-04-28 04:06:18 +00:00
remove parser and add collection package into this library
This commit is contained in:
87
README.md
87
README.md
@@ -1,7 +1,7 @@
|
||||
NGINX Configurator
|
||||
==================
|
||||
|
||||
PHP Library for NGINX configuration parser/generator
|
||||
PHP Library for NGINX configuration generator
|
||||
|
||||

|
||||
|
||||
@@ -27,60 +27,6 @@ This library requires *PHP* in `>=8.1` version.
|
||||
|
||||
## Usage
|
||||
|
||||
Parsing configuration string:
|
||||
|
||||
```php
|
||||
use Envoyr\NginxConfigurator\Builder;
|
||||
use Envoyr\NginxConfigurator\Config\Server;
|
||||
use Envoyr\NginxConfigurator\Parser;
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
$config = <<<CONFIG
|
||||
server {
|
||||
listen 8080;
|
||||
root /data/www/web;
|
||||
index index.php index.html index.htm;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/www;
|
||||
}
|
||||
|
||||
# pass the PHP scripts to FastCGI server listening on the php-fpm socket
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_pass unix:/var/run/php5-fpm.sock;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
CONFIG;
|
||||
|
||||
$parser = new Parser();
|
||||
$defaultConfig = $parser->parse($config);
|
||||
/** @var Server $defaultServers[] */
|
||||
$defaultServers = $defaultConfig->search(function (Node $node) {
|
||||
return $node instanceof Server;
|
||||
});
|
||||
|
||||
|
||||
$builder = new Builder();
|
||||
if (count($defaultServers) > 0) {
|
||||
/** @var Server $defaultServer */
|
||||
foreach ($defaultServers as $defaultServer) {
|
||||
$builder->append($defaultServer);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Generating configuration string:
|
||||
|
||||
```php
|
||||
@@ -167,37 +113,6 @@ server {
|
||||
}
|
||||
```
|
||||
|
||||
There are also methods to read and dump file:
|
||||
|
||||
```php
|
||||
use Envoyr\NginxConfigurator\Builder;
|
||||
use Envoyr\NginxConfigurator\Config\Location;
|
||||
use Envoyr\NginxConfigurator\Config\Server;
|
||||
use Envoyr\NginxConfigurator\Node\Directive;
|
||||
use Envoyr\NginxConfigurator\Node\Literal;
|
||||
use Envoyr\NginxConfigurator\Parser;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$parser = new Parser();
|
||||
$builder = new Builder();
|
||||
|
||||
$configuration = $parser->parseFile('default.conf');
|
||||
|
||||
/** @var Server $servers[] */
|
||||
$servers = $configuration->search(function (Node $node) {
|
||||
return $node instanceof Server;
|
||||
});
|
||||
if (count($servers) > 0) {
|
||||
/** @var Server $server */
|
||||
foreach ($servers as $server) {
|
||||
$builder->append($server);
|
||||
}
|
||||
}
|
||||
|
||||
$builder->dumpFile('generated.conf');
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
* [ ] Implement comments parsing
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
"license": "MIT",
|
||||
"homepage": "https://envoyr.com/",
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"envoyr/collection": "dev-main",
|
||||
"envoyr/loco": "dev-main"
|
||||
},
|
||||
"require": {},
|
||||
"require-dev": {},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
||||
@@ -9,34 +9,22 @@ use Envoyr\NginxConfigurator\Node\Param;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$uuid = 'uuid';
|
||||
|
||||
$factory = new Factory();
|
||||
$builder = new Builder();
|
||||
$builder->append(new Directive('proxy_cache_path', [new Param("/data/nginx/cache/{$uuid}"), new Param("keys_zone={$uuid}:10m")]));
|
||||
|
||||
$server = $builder->append($factory->createServer(80));
|
||||
$server->append(new Directive('error_log', [new Param('/var/log/nginx/error.log'), new Param('debug')]));
|
||||
$server->append(new Location(new Param('/test'), null, [
|
||||
new Directive('error_page', [new Param('401'), new Param('@unauthorized')]),
|
||||
new Directive('set', [new Param('$auth_user'), new Literal('none')]),
|
||||
new Directive('auth_request', [new Param('/auth')]),
|
||||
new Directive('proxy_pass', [new Param('http://test-service')]),
|
||||
$server->append(new Directive('error_log', [new Param("/data/nginx/log/{$uuid}.log"), new Param('debug')]));
|
||||
$server->append(new Directive('proxy_cache', [new Param($uuid)]));
|
||||
$server->append(new Location(new Param('/'), null, [
|
||||
new Directive('error_page', [new Param('401')]),
|
||||
new Directive('host', [new Param('example.com')]),
|
||||
new Directive('proxy_pass', [new Param('https://example.com')]),
|
||||
]));
|
||||
$server->append(new Location(new Param('/auth'), null, [
|
||||
new Directive('proxy_pass', [new Param('http://auth-service:9999')]),
|
||||
new Directive('proxy_bind', [new Param('$server_addr')]),
|
||||
new Directive('proxy_redirect', [new Param('http://$host'), new Param('https://$host')]),
|
||||
new Directive('proxy_set_header', [new Param('Content-Length'), new Literal("")]),
|
||||
new Directive('proxy_pass_request_body', [new Param('off')]),
|
||||
]));
|
||||
$server->append(new Location(new Param('@unauthorized'), null, [
|
||||
new Directive('return', [new Param('302'), new Param('/login?backurl=$request_uri')]),
|
||||
]));
|
||||
$server->append(new Location(new Param('/login'), null, [
|
||||
new Directive('expires', [new Param('-1')]),
|
||||
new Directive('proxy_pass', [new Param('http://identity-provider-service')]),
|
||||
new Directive('proxy_bind', [new Param('$server_addr')]),
|
||||
new Directive('proxy_redirect', [new Param('http://$host'), new Param('https://$host')]),
|
||||
new Directive('proxy_set_header', [new Param('Content-Length'), new Literal("")]),
|
||||
new Directive('proxy_pass_request_body', [new Param('off')]),
|
||||
$server->append(new Location(new Param('/.well-known/acme-challenge'), new Param('^~'), [
|
||||
new Directive('proxy_pass', [new Param('https://le.cdn.gd')])
|
||||
]));
|
||||
|
||||
print($builder->dump());
|
||||
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Envoyr\NginxConfigurator\Builder;
|
||||
use Envoyr\NginxConfigurator\Config\Server;
|
||||
use Envoyr\NginxConfigurator\Node\Node;
|
||||
use Envoyr\NginxConfigurator\Parser;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$config = <<<CONFIG
|
||||
server {
|
||||
listen 8080;
|
||||
root /data/www/web;
|
||||
index index.php index.html index.htm;
|
||||
|
||||
location / {
|
||||
try_files \$uri \$uri/ /index.php;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/www;
|
||||
}
|
||||
|
||||
# pass the PHP scripts to FastCGI server listening on the php-fpm socket
|
||||
location ~ \.php$ {
|
||||
try_files \$uri =404;
|
||||
fastcgi_pass unix:/var/run/php5-fpm.sock;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
CONFIG;
|
||||
|
||||
$parser = new Parser();
|
||||
$defaultConfig = $parser->parse($config);
|
||||
|
||||
/** @var Server $defaultServers[] */
|
||||
$defaultServers = $defaultConfig->search(function (Node $node) {
|
||||
return $node instanceof Server;
|
||||
});
|
||||
|
||||
|
||||
|
||||
$builder = new Builder();
|
||||
if (count($defaultServers) > 0) {
|
||||
/** @var Server $defaultServer */
|
||||
foreach ($defaultServers as $defaultServer) {
|
||||
$builder->append($defaultServer);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
namespace Envoyr\NginxConfigurator;
|
||||
|
||||
use Countable;
|
||||
use Envoyr\Collection\CustomTypedCollection;
|
||||
use Envoyr\NginxConfigurator\Collection\CustomTypedCollection;
|
||||
use Envoyr\NginxConfigurator\Node\Node;
|
||||
use Envoyr\NginxConfigurator\Node\RootNode;
|
||||
use Traversable;
|
||||
|
||||
154
src/Collection/Collection.php
Normal file
154
src/Collection/Collection.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
namespace Envoyr\NginxConfigurator\Collection;
|
||||
|
||||
use ArrayIterator;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use Serializable;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Class Collection
|
||||
* @package Envoyr\NginxConfigurator
|
||||
* @author Michał Brzuchalski <m.brzuchalski@madkom.pl>
|
||||
*/
|
||||
class Collection implements Countable, IteratorAggregate, Serializable
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $elements = [];
|
||||
|
||||
/**
|
||||
* Collection constructor.
|
||||
* @param array $elements
|
||||
*/
|
||||
public function __construct(array $elements = [])
|
||||
{
|
||||
foreach ($elements as $element) {
|
||||
$this->add($element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the element to collection
|
||||
* @param $element
|
||||
* @return bool
|
||||
*/
|
||||
public function add($element) : bool
|
||||
{
|
||||
$this->elements[] = $element;
|
||||
|
||||
return $this->contains($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes element and checks if collection not contains it anymore
|
||||
* @param $element
|
||||
* @return bool
|
||||
*/
|
||||
public function remove($element) : bool
|
||||
{
|
||||
if (!$this->contains($element)) {
|
||||
return false;
|
||||
}
|
||||
$index = array_search($element, $this->elements, true);
|
||||
unset($this->elements[$index]);
|
||||
|
||||
return !$this->contains($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return element existence in collection test result
|
||||
* @param $element
|
||||
* @return bool
|
||||
*/
|
||||
public function contains($element) : bool
|
||||
{
|
||||
return in_array($element, $this->elements, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through all elements to exam existence by callback
|
||||
* @param callable $checker
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(callable $checker)
|
||||
{
|
||||
foreach ($this->elements as $element) {
|
||||
if ($checker($element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through all elements to exam existence by callback
|
||||
* @param callable $checker
|
||||
* @return bool
|
||||
*/
|
||||
public function filter(callable $checker)
|
||||
{
|
||||
$result = new static();
|
||||
foreach ($this->elements as $element) {
|
||||
if ($checker($element)) {
|
||||
$result->add($element);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation of object
|
||||
* @link http://php.net/manual/en/serializable.serialize.php
|
||||
* @return string the string representation of the object or null
|
||||
* @since 5.1.0
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the object
|
||||
* @link http://php.net/manual/en/serializable.unserialize.php
|
||||
* @param string $serialized <p>
|
||||
* The string representation of the object.
|
||||
* </p>
|
||||
* @return void
|
||||
* @since 5.1.0
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
$this->elements = unserialize($serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count elements of an object
|
||||
* @link http://php.net/manual/en/countable.count.php
|
||||
* @return int The custom count as an integer.
|
||||
* </p>
|
||||
* <p>
|
||||
* The return protocol is cast to an integer.
|
||||
* @since 5.1.0
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an external iterator
|
||||
* @link http://php.net/manual/en/iteratoraggregate.getiterator.php
|
||||
* @return Traversable An instance of an object implementing <b>Iterator</b> or
|
||||
* <b>Traversable</b>
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->elements);
|
||||
}
|
||||
}
|
||||
53
src/Collection/ComparableDistinctTypedCollection.php
Normal file
53
src/Collection/ComparableDistinctTypedCollection.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace Envoyr\NginxConfigurator\Collection;
|
||||
|
||||
use RuntimeException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Class ComparableTypedCollection
|
||||
* @package Envoyr\NginxConfigurator
|
||||
* @author Michał Brzuchalski <m.brzuchalski@madkom.pl>
|
||||
*/
|
||||
abstract class ComparableDistinctTypedCollection extends CustomTypedCollection
|
||||
{
|
||||
/**
|
||||
* Checks two elements are equal
|
||||
* @param $left
|
||||
* @param $right
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function compareTo($left, $right) : bool;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add($element) : bool
|
||||
{
|
||||
if ($this->contains($element)) {
|
||||
throw new RuntimeException("Given element already exists in collection");
|
||||
}
|
||||
|
||||
return parent::add($element);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function contains($element) : bool
|
||||
{
|
||||
if (!$this->isElementValid($element)) {
|
||||
throw new UnexpectedValueException(
|
||||
"Unexpected element type, expecting: {$this->getType()}, given: " . get_class($element)
|
||||
);
|
||||
}
|
||||
foreach ($this->elements as $current) {
|
||||
if ($this->compareTo($current, $element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
51
src/Collection/CustomDistinctCollection.php
Normal file
51
src/Collection/CustomDistinctCollection.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace Envoyr\NginxConfigurator\Collection;
|
||||
|
||||
use RuntimeException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Class CustomDistinctCollection
|
||||
* @package Envoyr\NginxConfigurator
|
||||
* @author Michał Brzuchalski <m.brzuchalski@madkom.pl>
|
||||
*/
|
||||
abstract class CustomDistinctCollection extends CustomTypedCollection
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getMethod() : string;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add($element) : bool
|
||||
{
|
||||
if ($this->contains($element)) {
|
||||
throw new RuntimeException("Given element already exists in collection");
|
||||
}
|
||||
|
||||
return parent::add($element);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function contains($element) : bool
|
||||
{
|
||||
if (!$this->isElementValid($element)) {
|
||||
throw new UnexpectedValueException(
|
||||
"Unexpected element type, expecting: {$this->getType()}, given: " . get_class($element)
|
||||
);
|
||||
}
|
||||
$distinct = $element->{$this->getMethod()}();
|
||||
foreach ($this->elements as $current) {
|
||||
if ($current->{$this->getMethod()}() == $distinct) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
69
src/Collection/CustomTypedCollection.php
Normal file
69
src/Collection/CustomTypedCollection.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace Envoyr\NginxConfigurator\Collection;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Class AbstractTypedCollection
|
||||
* @package Envoyr\NginxConfigurator
|
||||
* @author Michał Brzuchalski <m.brzuchalski@madkom.pl>
|
||||
*/
|
||||
abstract class CustomTypedCollection extends Collection
|
||||
{
|
||||
/**
|
||||
* Retrieves collection type
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getType() : string;
|
||||
|
||||
/**
|
||||
* AbstractTypedCollection constructor.
|
||||
* @param array $elements
|
||||
*/
|
||||
public function __construct(array $elements = [])
|
||||
{
|
||||
if (!class_exists($this->getType())) {
|
||||
throw new InvalidArgumentException("Expected type should be accessible class name, given: {$this->getType()}");
|
||||
}
|
||||
parent::__construct($elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add($element) : bool
|
||||
{
|
||||
if (!$this->isElementValid($element)) {
|
||||
throw new UnexpectedValueException(
|
||||
"Unexpected element type, expecting: {$this->getType()}, given: " . get_class($element)
|
||||
);
|
||||
}
|
||||
|
||||
return parent::add($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function remove($element) : bool
|
||||
{
|
||||
if (!$this->isElementValid($element)) {
|
||||
throw new UnexpectedValueException(
|
||||
"Unexpected element type, expecting: {$this->getType()}, given: " . get_class($element)
|
||||
);
|
||||
}
|
||||
|
||||
return parent::remove($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check is element valid object type
|
||||
* @param $element
|
||||
* @return bool
|
||||
*/
|
||||
protected function isElementValid($element) : bool
|
||||
{
|
||||
return is_a($element, $this->getType()) || is_subclass_of($element, $this->getType());
|
||||
}
|
||||
}
|
||||
57
src/Collection/DistinctCollection.php
Normal file
57
src/Collection/DistinctCollection.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace Envoyr\NginxConfigurator\Collection;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Class DistinctCollection
|
||||
* @package Envoyr\NginxConfigurator
|
||||
* @author Michał Brzuchalski <m.brzuchalski@madkom.pl>
|
||||
*/
|
||||
class DistinctCollection extends CustomDistinctCollection
|
||||
{
|
||||
/**
|
||||
* @var string Collection generic type
|
||||
*/
|
||||
protected $type;
|
||||
/**
|
||||
* @var string Generic type distinguish method name
|
||||
*/
|
||||
private $method;
|
||||
|
||||
/**
|
||||
* UniqueGenericCollection constructor.
|
||||
* @param string $type
|
||||
* @param string $method
|
||||
* @param array $elements
|
||||
*/
|
||||
public function __construct(string $type, string $method, array $elements = [])
|
||||
{
|
||||
if (!method_exists($type, $method) && is_callable($type, $method)) {
|
||||
throw new InvalidArgumentException(
|
||||
"Non-existent distinct method name in class {$type}, given: {$method}"
|
||||
);
|
||||
}
|
||||
$this->type = $type;
|
||||
$this->method = $method;
|
||||
parent::__construct($elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getType() : string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getMethod() : string
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
}
|
||||
34
src/Collection/TypedCollection.php
Normal file
34
src/Collection/TypedCollection.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace Envoyr\NginxConfigurator\Collection;
|
||||
|
||||
/**
|
||||
* Class DistinctCollection
|
||||
* @package Envoyr\NginxConfigurator
|
||||
* @author Michał Brzuchalski <m.brzuchalski@madkom.pl>
|
||||
*/
|
||||
class TypedCollection extends CustomTypedCollection
|
||||
{
|
||||
/**
|
||||
* @var string Collection generic type
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* GenericCollection constructor.
|
||||
* @param string $type
|
||||
* @param array $elements
|
||||
*/
|
||||
public function __construct(string $type, array $elements = [])
|
||||
{
|
||||
$this->type = $type;
|
||||
parent::__construct($elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getType() : string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
namespace Envoyr\NginxConfigurator\Node;
|
||||
|
||||
use Envoyr\Collection\CustomTypedCollection;
|
||||
use Envoyr\NginxConfigurator\Collection\CustomTypedCollection;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Envoyr\NginxConfigurator\Node;
|
||||
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use Envoyr\Collection\CustomTypedCollection;
|
||||
use Envoyr\NginxConfigurator\Collection\CustomTypedCollection;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
|
||||
220
src/Parser.php
220
src/Parser.php
@@ -1,220 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: mbrzuchalski
|
||||
* Date: 06.04.16
|
||||
* Time: 13:01
|
||||
*/
|
||||
namespace Envoyr\NginxConfigurator;
|
||||
|
||||
use Ferno\Loco\ConcParser;
|
||||
use Ferno\Loco\Grammar;
|
||||
use Ferno\Loco\GreedyMultiParser;
|
||||
use Ferno\Loco\GreedyStarParser;
|
||||
use Ferno\Loco\LazyAltParser;
|
||||
use Ferno\Loco\ParseFailureException;
|
||||
use Ferno\Loco\RegexParser;
|
||||
use Ferno\Loco\StringParser;
|
||||
use Envoyr\NginxConfigurator\Config\Events;
|
||||
use Envoyr\NginxConfigurator\Config\Http;
|
||||
use Envoyr\NginxConfigurator\Config\Location;
|
||||
use Envoyr\NginxConfigurator\Config\Server;
|
||||
use Envoyr\NginxConfigurator\Config\Upstream;
|
||||
use Envoyr\NginxConfigurator\Exception\GrammarException;
|
||||
use Envoyr\NginxConfigurator\Exception\UnrecognizedContextException;
|
||||
use Envoyr\NginxConfigurator\Node\Context;
|
||||
use Envoyr\NginxConfigurator\Node\Directive;
|
||||
use Envoyr\NginxConfigurator\Node\Literal;
|
||||
use Envoyr\NginxConfigurator\Node\Param;
|
||||
use Envoyr\NginxConfigurator\Node\RootNode;
|
||||
|
||||
/**
|
||||
* Class Parser
|
||||
* @package Envoyr\NginxConfigurator
|
||||
* @author Michał Brzuchalski <m.brzuchalski@madkom.pl>
|
||||
*/
|
||||
class Parser extends Grammar
|
||||
{
|
||||
/**
|
||||
* Holds parsed filename
|
||||
* @var string
|
||||
*/
|
||||
protected $filename;
|
||||
/**
|
||||
* Holds parsed string
|
||||
* @var string
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* Parser constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('syntax', [
|
||||
'syntax' => new GreedyStarParser(new LazyAltParser(['directive', 'section'])),
|
||||
'sections' => new GreedyMultiParser('section', 0, 2),
|
||||
'section' => new ConcParser(
|
||||
[
|
||||
'section-name',
|
||||
new LazyAltParser(['space', 'opt-space']),
|
||||
new LazyAltParser(['params', new LazyAltParser(['space', 'opt-space'])]),
|
||||
new StringParser('{'),
|
||||
new LazyAltParser(['space', 'opt-space']),
|
||||
new GreedyMultiParser(new LazyAltParser(['directive', 'section']), 0, null),
|
||||
new LazyAltParser(['space', 'opt-space']),
|
||||
new StringParser('}'),
|
||||
new LazyAltParser(['space', 'opt-space']),
|
||||
],
|
||||
[$this, 'parseSection']
|
||||
),
|
||||
'section-name' => new RegexParser('/^[a-z0-9\_]+/i'),
|
||||
|
||||
'directives' => new GreedyMultiParser('directive', 0, null),
|
||||
'directive' => new LazyAltParser([
|
||||
new ConcParser([
|
||||
'directive-name',
|
||||
'semicolon',
|
||||
new LazyAltParser(['space', 'opt-space']),
|
||||
], [$this, 'parseDirective']),
|
||||
new ConcParser([
|
||||
'directive-name',
|
||||
'space',
|
||||
'params',
|
||||
'semicolon',
|
||||
new LazyAltParser(['space', 'opt-space']),
|
||||
], [$this, 'parseDirective'])
|
||||
]),
|
||||
'directive-name' => new RegexParser('/^[a-z0-9\_]+/i'),
|
||||
|
||||
'params' => new GreedyMultiParser(new ConcParser(['param', 'opt-space'], function ($param, $space) {
|
||||
return $param;
|
||||
}), 0, null),
|
||||
'param' => new LazyAltParser(['literal', 'param-name']),
|
||||
'param-name' => new RegexParser('/^[^\s\r\n\{\}\;\"\']+/i', function ($match) {
|
||||
return new Param($match);
|
||||
}),
|
||||
'literal' => new LazyAltParser([
|
||||
new RegexParser('/^"([^"]*)"/', function ($match0, $match1) {
|
||||
return new Literal($match1);
|
||||
}),
|
||||
new RegexParser("/^'([^']*)'/", function ($match0, $match1) {
|
||||
return new Literal($match1);
|
||||
})
|
||||
]),
|
||||
|
||||
'semicolon' => new StringParser(';', function () {
|
||||
return null;
|
||||
}),
|
||||
'space' => new GreedyStarParser('whitespace/comment', function () {
|
||||
return null;
|
||||
}),
|
||||
'whitespace/comment' => new LazyAltParser(['whitespace', 'comment'], function () {
|
||||
return null;
|
||||
}),
|
||||
'comment' => new RegexParser("/^#+([^\r\n]*)/", function () {
|
||||
return null;
|
||||
}),
|
||||
'whitespace' => new RegexParser("/^[ \t\r\n]+/"),
|
||||
'opt-space' => new RegexParser("/^[ \t\r\n]?/"),
|
||||
'eol' => new LazyAltParser([new StringParser("\r"), new StringParser("\n")], function () {
|
||||
return null;
|
||||
})
|
||||
], function (array $nodes = []) {
|
||||
return new RootNode($nodes);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses config file
|
||||
* @param string $filename
|
||||
* @return mixed
|
||||
* @throws ParseFailureException
|
||||
*/
|
||||
public function parseFile(string $filename) : RootNode
|
||||
{
|
||||
$this->content = null;
|
||||
$this->filename = $filename;
|
||||
|
||||
return $this->parse(file_get_contents($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses string
|
||||
* @param string $string
|
||||
* @return mixed
|
||||
* @throws ParseFailureException
|
||||
*/
|
||||
public function parse($string) : RootNode
|
||||
{
|
||||
$this->content = $string;
|
||||
$this->filename = null;
|
||||
|
||||
return parent::parse($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses section entries
|
||||
* @param string $section Section name
|
||||
* @param null $space0 Ignored
|
||||
* @param Param[] $params Params collection
|
||||
* @param null $open Ignored
|
||||
* @param null $space1 Ignored
|
||||
* @param Directive[] $directives Directives collection
|
||||
* @return Context
|
||||
* @throws GrammarException
|
||||
* @throws UnrecognizedContextException
|
||||
*/
|
||||
protected function parseSection($section, $space0, $params, $open, $space1, $directives) : Context
|
||||
{
|
||||
switch ($section) {
|
||||
case 'server':
|
||||
return new Server($directives);
|
||||
|
||||
case 'http':
|
||||
return new Http($directives);
|
||||
|
||||
case 'location':
|
||||
$modifier = null;
|
||||
if (sizeof($params) == 2) {
|
||||
list($modifier, $location) = $params;
|
||||
} elseif (sizeof($params) == 1) {
|
||||
$location = $params[0];
|
||||
} else {
|
||||
throw new GrammarException(
|
||||
sprintf(
|
||||
"Location context missing in %s",
|
||||
$this->filename ? var_export($this->filename, true) : var_export($this->content, true)
|
||||
)
|
||||
);
|
||||
}
|
||||
return new Location($location, $modifier, $directives);
|
||||
|
||||
case 'events':
|
||||
return new Events($directives);
|
||||
|
||||
case 'upstream':
|
||||
list($upstream) = $params;
|
||||
return new Upstream($upstream, $directives);
|
||||
}
|
||||
|
||||
throw new UnrecognizedContextException(
|
||||
sprintf(
|
||||
"Unrecognized context: {$section} found in %s",
|
||||
$this->filename ? var_export($this->filename, true) : var_export($this->content, true)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses directive
|
||||
* @param string $name
|
||||
* @param null $space
|
||||
* @param array $params
|
||||
* @return Directive
|
||||
*/
|
||||
protected function parseDirective(string $name, $space = null, $params = []) : Directive
|
||||
{
|
||||
return new Directive($name, is_null($params) ? [] : $params);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user