mirror of
https://github.com/standardebooks/web.git
synced 2025-07-06 23:00:28 -04:00
Add Composer autoloading functions and PHPStan for testing
This commit is contained in:
parent
e198c4db65
commit
f5d7d4e02a
1518 changed files with 169063 additions and 30 deletions
12
README.md
12
README.md
|
@ -43,6 +43,18 @@ You’ll also need to ensure the following:
|
|||
|
||||
The website pulls all ebook information from what is contained in `/standardebooks.org/www/ebooks/`. It does not inspect `/standardebooks.org/ebooks/`. Therefore it is possible for one or the other to hold different catalogs if they become out of sync.
|
||||
|
||||
# Testing
|
||||
|
||||
This repository includes [PHPStan](https://github.com/phpstan/phpstan) to statically analyze the codebase.
|
||||
|
||||
To run PHPStan, execute:
|
||||
|
||||
```shell
|
||||
$> <REPO-ROOT>/vendor/bin/phpstan analyse -c <REPO-ROOT>/config/phpstan/phpstan.neon
|
||||
```
|
||||
|
||||
If run successfully, it should output `[OK] No errors`.
|
||||
|
||||
# Contributing
|
||||
|
||||
Before submitting design contributions, please discuss them with the Standard Ebooks lead. While we encourage discussion and contributions, we can’t guarantee that unsoliticed design contributions will be accepted. You can open an issue to discuss potential design contributions with us before you begin.
|
||||
|
|
9
composer.json
Normal file
9
composer.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^0.11.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {"": "lib/"},
|
||||
"files": ["lib/Constants.php", "lib/CoreFunctions.php"]
|
||||
}
|
||||
}
|
1105
composer.lock
generated
Normal file
1105
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,6 @@
|
|||
<?
|
||||
// Auto-included by Composer in composer.json to satisfy PHPStan
|
||||
|
||||
const EBOOKS_PER_PAGE = 12;
|
||||
const SORT_NEWEST = 'newest';
|
||||
const SORT_AUTHOR_ALPHA = 'author-alpha';
|
||||
|
|
31
lib/Core.php
31
lib/Core.php
|
@ -3,35 +3,8 @@ mb_internal_encoding('UTF-8');
|
|||
mb_http_output('UTF-8');
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
require_once('Constants.php');
|
||||
|
||||
// Convenience alias of var_dump.
|
||||
function vd($var){
|
||||
var_dump($var);
|
||||
}
|
||||
|
||||
// var_dump($var) then die().
|
||||
function vdd($var){
|
||||
var_dump($var);
|
||||
die();
|
||||
}
|
||||
|
||||
// var_dump into a string.
|
||||
function vds($var){
|
||||
ob_start();
|
||||
var_dump($var);
|
||||
$str = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $str;
|
||||
}
|
||||
|
||||
spl_autoload_register(function($class){
|
||||
try{
|
||||
include($class . '.php');
|
||||
}
|
||||
catch(\Exception $ex){
|
||||
}
|
||||
});
|
||||
// Composer auto-loads the lib/ directory in composer.json
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// Custom error handler to output more details about the specific Apache request that caused an exception.
|
||||
set_exception_handler(function($ex){
|
||||
|
|
24
lib/CoreFunctions.php
Normal file
24
lib/CoreFunctions.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?
|
||||
// Auto-included by Composer in composer.json
|
||||
// These functions are broken out of Core.php to satisfy PHPStan
|
||||
|
||||
// Convenience alias of var_dump.
|
||||
function vd($var){
|
||||
var_dump($var);
|
||||
}
|
||||
|
||||
// var_dump($var) then die().
|
||||
function vdd($var){
|
||||
var_dump($var);
|
||||
die();
|
||||
}
|
||||
|
||||
// var_dump into a string.
|
||||
function vds($var){
|
||||
ob_start();
|
||||
var_dump($var);
|
||||
$str = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $str;
|
||||
}
|
||||
?>
|
7
vendor/autoload.php
vendored
Normal file
7
vendor/autoload.php
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit49e401a41abff8a9005dcbd044d35c5f::getLoader();
|
1
vendor/bin/php-parse
vendored
Symbolic link
1
vendor/bin/php-parse
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../nikic/php-parser/bin/php-parse
|
1
vendor/bin/phpstan
vendored
Symbolic link
1
vendor/bin/phpstan
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../phpstan/phpstan/bin/phpstan
|
445
vendor/composer/ClassLoader.php
vendored
Normal file
445
vendor/composer/ClassLoader.php
vendored
Normal file
|
@ -0,0 +1,445 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see http://www.php-fig.org/psr/psr-0/
|
||||
* @see http://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
// PSR-4
|
||||
private $prefixLengthsPsr4 = array();
|
||||
private $prefixDirsPsr4 = array();
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
private $prefixesPsr0 = array();
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
private $useIncludePath = false;
|
||||
private $classMap = array();
|
||||
private $classMapAuthoritative = false;
|
||||
private $missingClasses = array();
|
||||
private $apcuPrefix;
|
||||
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classMap Class to filename map
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return bool|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath.'\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
include $file;
|
||||
}
|
56
vendor/composer/LICENSE
vendored
Normal file
56
vendor/composer/LICENSE
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: Composer
|
||||
Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be>
|
||||
Source: https://github.com/composer/composer
|
||||
|
||||
Files: *
|
||||
Copyright: 2016, Nils Adermann <naderman@naderman.de>
|
||||
2016, Jordi Boggiano <j.boggiano@seld.be>
|
||||
License: Expat
|
||||
|
||||
Files: src/Composer/Util/TlsHelper.php
|
||||
Copyright: 2016, Nils Adermann <naderman@naderman.de>
|
||||
2016, Jordi Boggiano <j.boggiano@seld.be>
|
||||
2013, Evan Coury <me@evancoury.com>
|
||||
License: Expat and BSD-2-Clause
|
||||
|
||||
License: BSD-2-Clause
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
.
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
License: Expat
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
103
vendor/composer/autoload_classmap.php
vendored
Normal file
103
vendor/composer/autoload_classmap.php
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Nette\\ArgumentOutOfRangeException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Bridges\\DITracy\\ContainerPanel' => $vendorDir . '/nette/di/src/Bridges/DITracy/ContainerPanel.php',
|
||||
'Nette\\Bridges\\Framework\\TracyBridge' => $vendorDir . '/nette/bootstrap/src/Bridges/Framework/TracyBridge.php',
|
||||
'Nette\\Configurator' => $vendorDir . '/nette/bootstrap/src/Bootstrap/Configurator.php',
|
||||
'Nette\\DI\\Compiler' => $vendorDir . '/nette/di/src/DI/Compiler.php',
|
||||
'Nette\\DI\\CompilerExtension' => $vendorDir . '/nette/di/src/DI/CompilerExtension.php',
|
||||
'Nette\\DI\\Config\\Adapters\\IniAdapter' => $vendorDir . '/nette/di/src/DI/Config/Adapters/IniAdapter.php',
|
||||
'Nette\\DI\\Config\\Adapters\\NeonAdapter' => $vendorDir . '/nette/di/src/DI/Config/Adapters/NeonAdapter.php',
|
||||
'Nette\\DI\\Config\\Adapters\\PhpAdapter' => $vendorDir . '/nette/di/src/DI/Config/Adapters/PhpAdapter.php',
|
||||
'Nette\\DI\\Config\\Helpers' => $vendorDir . '/nette/di/src/DI/Config/Helpers.php',
|
||||
'Nette\\DI\\Config\\IAdapter' => $vendorDir . '/nette/di/src/DI/Config/IAdapter.php',
|
||||
'Nette\\DI\\Config\\Loader' => $vendorDir . '/nette/di/src/DI/Config/Loader.php',
|
||||
'Nette\\DI\\Container' => $vendorDir . '/nette/di/src/DI/Container.php',
|
||||
'Nette\\DI\\ContainerBuilder' => $vendorDir . '/nette/di/src/DI/ContainerBuilder.php',
|
||||
'Nette\\DI\\ContainerLoader' => $vendorDir . '/nette/di/src/DI/ContainerLoader.php',
|
||||
'Nette\\DI\\DependencyChecker' => $vendorDir . '/nette/di/src/DI/DependencyChecker.php',
|
||||
'Nette\\DI\\Extensions\\ConstantsExtension' => $vendorDir . '/nette/di/src/DI/Extensions/ConstantsExtension.php',
|
||||
'Nette\\DI\\Extensions\\DIExtension' => $vendorDir . '/nette/di/src/DI/Extensions/DIExtension.php',
|
||||
'Nette\\DI\\Extensions\\DecoratorExtension' => $vendorDir . '/nette/di/src/DI/Extensions/DecoratorExtension.php',
|
||||
'Nette\\DI\\Extensions\\ExtensionsExtension' => $vendorDir . '/nette/di/src/DI/Extensions/ExtensionsExtension.php',
|
||||
'Nette\\DI\\Extensions\\InjectExtension' => $vendorDir . '/nette/di/src/DI/Extensions/InjectExtension.php',
|
||||
'Nette\\DI\\Extensions\\PhpExtension' => $vendorDir . '/nette/di/src/DI/Extensions/PhpExtension.php',
|
||||
'Nette\\DI\\Helpers' => $vendorDir . '/nette/di/src/DI/Helpers.php',
|
||||
'Nette\\DI\\MissingServiceException' => $vendorDir . '/nette/di/src/DI/exceptions.php',
|
||||
'Nette\\DI\\PhpGenerator' => $vendorDir . '/nette/di/src/DI/PhpGenerator.php',
|
||||
'Nette\\DI\\PhpReflection' => $vendorDir . '/nette/di/src/DI/PhpReflection.php',
|
||||
'Nette\\DI\\ServiceCreationException' => $vendorDir . '/nette/di/src/DI/exceptions.php',
|
||||
'Nette\\DI\\ServiceDefinition' => $vendorDir . '/nette/di/src/DI/ServiceDefinition.php',
|
||||
'Nette\\DI\\Statement' => $vendorDir . '/nette/di/src/DI/Statement.php',
|
||||
'Nette\\DeprecatedException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\DirectoryNotFoundException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\FileNotFoundException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\IOException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\InvalidArgumentException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\InvalidStateException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Iterators\\CachingIterator' => $vendorDir . '/nette/utils/src/Iterators/CachingIterator.php',
|
||||
'Nette\\Iterators\\Mapper' => $vendorDir . '/nette/utils/src/Iterators/Mapper.php',
|
||||
'Nette\\LegacyObject' => $vendorDir . '/nette/utils/src/Utils/LegacyObject.php',
|
||||
'Nette\\Loaders\\RobotLoader' => $vendorDir . '/nette/robot-loader/src/RobotLoader/RobotLoader.php',
|
||||
'Nette\\Localization\\ITranslator' => $vendorDir . '/nette/utils/src/Utils/ITranslator.php',
|
||||
'Nette\\MemberAccessException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Neon\\Decoder' => $vendorDir . '/nette/neon/src/Neon/Decoder.php',
|
||||
'Nette\\Neon\\Encoder' => $vendorDir . '/nette/neon/src/Neon/Encoder.php',
|
||||
'Nette\\Neon\\Entity' => $vendorDir . '/nette/neon/src/Neon/Entity.php',
|
||||
'Nette\\Neon\\Exception' => $vendorDir . '/nette/neon/src/Neon/Exception.php',
|
||||
'Nette\\Neon\\Neon' => $vendorDir . '/nette/neon/src/Neon/Neon.php',
|
||||
'Nette\\NotImplementedException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\NotSupportedException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\OutOfRangeException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\PhpGenerator\\ClassType' => $vendorDir . '/nette/php-generator/src/PhpGenerator/ClassType.php',
|
||||
'Nette\\PhpGenerator\\Closure' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Closure.php',
|
||||
'Nette\\PhpGenerator\\Constant' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Constant.php',
|
||||
'Nette\\PhpGenerator\\Factory' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Factory.php',
|
||||
'Nette\\PhpGenerator\\GlobalFunction' => $vendorDir . '/nette/php-generator/src/PhpGenerator/GlobalFunction.php',
|
||||
'Nette\\PhpGenerator\\Helpers' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Helpers.php',
|
||||
'Nette\\PhpGenerator\\Method' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Method.php',
|
||||
'Nette\\PhpGenerator\\Parameter' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Parameter.php',
|
||||
'Nette\\PhpGenerator\\PhpFile' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PhpFile.php',
|
||||
'Nette\\PhpGenerator\\PhpLiteral' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PhpLiteral.php',
|
||||
'Nette\\PhpGenerator\\PhpNamespace' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PhpNamespace.php',
|
||||
'Nette\\PhpGenerator\\Printer' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Printer.php',
|
||||
'Nette\\PhpGenerator\\Property' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Property.php',
|
||||
'Nette\\PhpGenerator\\PsrPrinter' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PsrPrinter.php',
|
||||
'Nette\\PhpGenerator\\Traits\\CommentAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/CommentAware.php',
|
||||
'Nette\\PhpGenerator\\Traits\\FunctionLike' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/FunctionLike.php',
|
||||
'Nette\\PhpGenerator\\Traits\\NameAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/NameAware.php',
|
||||
'Nette\\PhpGenerator\\Traits\\VisibilityAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/VisibilityAware.php',
|
||||
'Nette\\SmartObject' => $vendorDir . '/nette/utils/src/Utils/SmartObject.php',
|
||||
'Nette\\StaticClass' => $vendorDir . '/nette/utils/src/Utils/StaticClass.php',
|
||||
'Nette\\StaticClassException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\UnexpectedValueException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\ArrayHash' => $vendorDir . '/nette/utils/src/Utils/ArrayHash.php',
|
||||
'Nette\\Utils\\ArrayList' => $vendorDir . '/nette/utils/src/Utils/ArrayList.php',
|
||||
'Nette\\Utils\\Arrays' => $vendorDir . '/nette/utils/src/Utils/Arrays.php',
|
||||
'Nette\\Utils\\AssertionException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\Callback' => $vendorDir . '/nette/utils/src/Utils/Callback.php',
|
||||
'Nette\\Utils\\DateTime' => $vendorDir . '/nette/utils/src/Utils/DateTime.php',
|
||||
'Nette\\Utils\\FileSystem' => $vendorDir . '/nette/utils/src/Utils/FileSystem.php',
|
||||
'Nette\\Utils\\Finder' => $vendorDir . '/nette/finder/src/Utils/Finder.php',
|
||||
'Nette\\Utils\\Html' => $vendorDir . '/nette/utils/src/Utils/Html.php',
|
||||
'Nette\\Utils\\IHtmlString' => $vendorDir . '/nette/utils/src/Utils/IHtmlString.php',
|
||||
'Nette\\Utils\\Image' => $vendorDir . '/nette/utils/src/Utils/Image.php',
|
||||
'Nette\\Utils\\ImageException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\Json' => $vendorDir . '/nette/utils/src/Utils/Json.php',
|
||||
'Nette\\Utils\\JsonException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\ObjectHelpers' => $vendorDir . '/nette/utils/src/Utils/ObjectHelpers.php',
|
||||
'Nette\\Utils\\ObjectMixin' => $vendorDir . '/nette/utils/src/Utils/ObjectMixin.php',
|
||||
'Nette\\Utils\\Paginator' => $vendorDir . '/nette/utils/src/Utils/Paginator.php',
|
||||
'Nette\\Utils\\Random' => $vendorDir . '/nette/utils/src/Utils/Random.php',
|
||||
'Nette\\Utils\\Reflection' => $vendorDir . '/nette/utils/src/Utils/Reflection.php',
|
||||
'Nette\\Utils\\RegexpException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\Strings' => $vendorDir . '/nette/utils/src/Utils/Strings.php',
|
||||
'Nette\\Utils\\UnknownImageFileException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\Validators' => $vendorDir . '/nette/utils/src/Utils/Validators.php',
|
||||
);
|
13
vendor/composer/autoload_files.php
vendored
Normal file
13
vendor/composer/autoload_files.php
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'a12da592622097d2b593a430e32e13fd' => $vendorDir . '/nette/utils/src/loader.php',
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'782b605f6bb82f1cd229995fb6f0c6bf' => $baseDir . '/lib/Constants.php',
|
||||
'7f0f1b28d901698044d9d248797ab78a' => $baseDir . '/lib/CoreFunctions.php',
|
||||
);
|
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
21
vendor/composer/autoload_psr4.php
vendored
Normal file
21
vendor/composer/autoload_psr4.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
||||
'Symfony\\Contracts\\' => array($vendorDir . '/symfony/contracts'),
|
||||
'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
|
||||
'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
|
||||
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
|
||||
'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
|
||||
'PackageVersions\\' => array($vendorDir . '/ocramius/package-versions/src/PackageVersions'),
|
||||
'PHPStan\\PhpDocParser\\' => array($vendorDir . '/phpstan/phpdoc-parser/src'),
|
||||
'PHPStan\\' => array($vendorDir . '/phpstan/phpstan/src', $vendorDir . '/phpstan/phpstan/build/PHPStan'),
|
||||
'Jean85\\' => array($vendorDir . '/jean85/pretty-package-versions/src'),
|
||||
'Composer\\XdebugHandler\\' => array($vendorDir . '/composer/xdebug-handler/src'),
|
||||
'' => array($baseDir . '/lib'),
|
||||
);
|
70
vendor/composer/autoload_real.php
vendored
Normal file
70
vendor/composer/autoload_real.php
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit49e401a41abff8a9005dcbd044d35c5f
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit49e401a41abff8a9005dcbd044d35c5f', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit49e401a41abff8a9005dcbd044d35c5f', 'loadClassLoader'));
|
||||
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||
if ($useStaticLoader) {
|
||||
require_once __DIR__ . '/autoload_static.php';
|
||||
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit49e401a41abff8a9005dcbd044d35c5f::getInitializer($loader));
|
||||
} else {
|
||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->set($namespace, $path);
|
||||
}
|
||||
|
||||
$map = require __DIR__ . '/autoload_psr4.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->setPsr4($namespace, $path);
|
||||
}
|
||||
|
||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||
if ($classMap) {
|
||||
$loader->addClassMap($classMap);
|
||||
}
|
||||
}
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
if ($useStaticLoader) {
|
||||
$includeFiles = Composer\Autoload\ComposerStaticInit49e401a41abff8a9005dcbd044d35c5f::$files;
|
||||
} else {
|
||||
$includeFiles = require __DIR__ . '/autoload_files.php';
|
||||
}
|
||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||
composerRequire49e401a41abff8a9005dcbd044d35c5f($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
function composerRequire49e401a41abff8a9005dcbd044d35c5f($fileIdentifier, $file)
|
||||
{
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
require $file;
|
||||
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
}
|
||||
}
|
201
vendor/composer/autoload_static.php
vendored
Normal file
201
vendor/composer/autoload_static.php
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit49e401a41abff8a9005dcbd044d35c5f
|
||||
{
|
||||
public static $files = array (
|
||||
'a12da592622097d2b593a430e32e13fd' => __DIR__ . '/..' . '/nette/utils/src/loader.php',
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'782b605f6bb82f1cd229995fb6f0c6bf' => __DIR__ . '/../..' . '/lib/Constants.php',
|
||||
'7f0f1b28d901698044d9d248797ab78a' => __DIR__ . '/../..' . '/lib/CoreFunctions.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'S' =>
|
||||
array (
|
||||
'Symfony\\Polyfill\\Mbstring\\' => 26,
|
||||
'Symfony\\Contracts\\' => 18,
|
||||
'Symfony\\Component\\Finder\\' => 25,
|
||||
'Symfony\\Component\\Console\\' => 26,
|
||||
),
|
||||
'P' =>
|
||||
array (
|
||||
'Psr\\Log\\' => 8,
|
||||
'PhpParser\\' => 10,
|
||||
'PackageVersions\\' => 16,
|
||||
'PHPStan\\PhpDocParser\\' => 21,
|
||||
'PHPStan\\' => 8,
|
||||
),
|
||||
'J' =>
|
||||
array (
|
||||
'Jean85\\' => 7,
|
||||
),
|
||||
'C' =>
|
||||
array (
|
||||
'Composer\\XdebugHandler\\' => 23,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Symfony\\Polyfill\\Mbstring\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
|
||||
),
|
||||
'Symfony\\Contracts\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/contracts',
|
||||
),
|
||||
'Symfony\\Component\\Finder\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/finder',
|
||||
),
|
||||
'Symfony\\Component\\Console\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/console',
|
||||
),
|
||||
'Psr\\Log\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
|
||||
),
|
||||
'PhpParser\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser',
|
||||
),
|
||||
'PackageVersions\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/ocramius/package-versions/src/PackageVersions',
|
||||
),
|
||||
'PHPStan\\PhpDocParser\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src',
|
||||
),
|
||||
'PHPStan\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/phpstan/phpstan/src',
|
||||
1 => __DIR__ . '/..' . '/phpstan/phpstan/build/PHPStan',
|
||||
),
|
||||
'Jean85\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/jean85/pretty-package-versions/src',
|
||||
),
|
||||
'Composer\\XdebugHandler\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/composer/xdebug-handler/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static $fallbackDirsPsr4 = array (
|
||||
0 => __DIR__ . '/../..' . '/lib',
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Nette\\ArgumentOutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Bridges\\DITracy\\ContainerPanel' => __DIR__ . '/..' . '/nette/di/src/Bridges/DITracy/ContainerPanel.php',
|
||||
'Nette\\Bridges\\Framework\\TracyBridge' => __DIR__ . '/..' . '/nette/bootstrap/src/Bridges/Framework/TracyBridge.php',
|
||||
'Nette\\Configurator' => __DIR__ . '/..' . '/nette/bootstrap/src/Bootstrap/Configurator.php',
|
||||
'Nette\\DI\\Compiler' => __DIR__ . '/..' . '/nette/di/src/DI/Compiler.php',
|
||||
'Nette\\DI\\CompilerExtension' => __DIR__ . '/..' . '/nette/di/src/DI/CompilerExtension.php',
|
||||
'Nette\\DI\\Config\\Adapters\\IniAdapter' => __DIR__ . '/..' . '/nette/di/src/DI/Config/Adapters/IniAdapter.php',
|
||||
'Nette\\DI\\Config\\Adapters\\NeonAdapter' => __DIR__ . '/..' . '/nette/di/src/DI/Config/Adapters/NeonAdapter.php',
|
||||
'Nette\\DI\\Config\\Adapters\\PhpAdapter' => __DIR__ . '/..' . '/nette/di/src/DI/Config/Adapters/PhpAdapter.php',
|
||||
'Nette\\DI\\Config\\Helpers' => __DIR__ . '/..' . '/nette/di/src/DI/Config/Helpers.php',
|
||||
'Nette\\DI\\Config\\IAdapter' => __DIR__ . '/..' . '/nette/di/src/DI/Config/IAdapter.php',
|
||||
'Nette\\DI\\Config\\Loader' => __DIR__ . '/..' . '/nette/di/src/DI/Config/Loader.php',
|
||||
'Nette\\DI\\Container' => __DIR__ . '/..' . '/nette/di/src/DI/Container.php',
|
||||
'Nette\\DI\\ContainerBuilder' => __DIR__ . '/..' . '/nette/di/src/DI/ContainerBuilder.php',
|
||||
'Nette\\DI\\ContainerLoader' => __DIR__ . '/..' . '/nette/di/src/DI/ContainerLoader.php',
|
||||
'Nette\\DI\\DependencyChecker' => __DIR__ . '/..' . '/nette/di/src/DI/DependencyChecker.php',
|
||||
'Nette\\DI\\Extensions\\ConstantsExtension' => __DIR__ . '/..' . '/nette/di/src/DI/Extensions/ConstantsExtension.php',
|
||||
'Nette\\DI\\Extensions\\DIExtension' => __DIR__ . '/..' . '/nette/di/src/DI/Extensions/DIExtension.php',
|
||||
'Nette\\DI\\Extensions\\DecoratorExtension' => __DIR__ . '/..' . '/nette/di/src/DI/Extensions/DecoratorExtension.php',
|
||||
'Nette\\DI\\Extensions\\ExtensionsExtension' => __DIR__ . '/..' . '/nette/di/src/DI/Extensions/ExtensionsExtension.php',
|
||||
'Nette\\DI\\Extensions\\InjectExtension' => __DIR__ . '/..' . '/nette/di/src/DI/Extensions/InjectExtension.php',
|
||||
'Nette\\DI\\Extensions\\PhpExtension' => __DIR__ . '/..' . '/nette/di/src/DI/Extensions/PhpExtension.php',
|
||||
'Nette\\DI\\Helpers' => __DIR__ . '/..' . '/nette/di/src/DI/Helpers.php',
|
||||
'Nette\\DI\\MissingServiceException' => __DIR__ . '/..' . '/nette/di/src/DI/exceptions.php',
|
||||
'Nette\\DI\\PhpGenerator' => __DIR__ . '/..' . '/nette/di/src/DI/PhpGenerator.php',
|
||||
'Nette\\DI\\PhpReflection' => __DIR__ . '/..' . '/nette/di/src/DI/PhpReflection.php',
|
||||
'Nette\\DI\\ServiceCreationException' => __DIR__ . '/..' . '/nette/di/src/DI/exceptions.php',
|
||||
'Nette\\DI\\ServiceDefinition' => __DIR__ . '/..' . '/nette/di/src/DI/ServiceDefinition.php',
|
||||
'Nette\\DI\\Statement' => __DIR__ . '/..' . '/nette/di/src/DI/Statement.php',
|
||||
'Nette\\DeprecatedException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\DirectoryNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\FileNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\IOException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\InvalidArgumentException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\InvalidStateException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Iterators\\CachingIterator' => __DIR__ . '/..' . '/nette/utils/src/Iterators/CachingIterator.php',
|
||||
'Nette\\Iterators\\Mapper' => __DIR__ . '/..' . '/nette/utils/src/Iterators/Mapper.php',
|
||||
'Nette\\LegacyObject' => __DIR__ . '/..' . '/nette/utils/src/Utils/LegacyObject.php',
|
||||
'Nette\\Loaders\\RobotLoader' => __DIR__ . '/..' . '/nette/robot-loader/src/RobotLoader/RobotLoader.php',
|
||||
'Nette\\Localization\\ITranslator' => __DIR__ . '/..' . '/nette/utils/src/Utils/ITranslator.php',
|
||||
'Nette\\MemberAccessException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Neon\\Decoder' => __DIR__ . '/..' . '/nette/neon/src/Neon/Decoder.php',
|
||||
'Nette\\Neon\\Encoder' => __DIR__ . '/..' . '/nette/neon/src/Neon/Encoder.php',
|
||||
'Nette\\Neon\\Entity' => __DIR__ . '/..' . '/nette/neon/src/Neon/Entity.php',
|
||||
'Nette\\Neon\\Exception' => __DIR__ . '/..' . '/nette/neon/src/Neon/Exception.php',
|
||||
'Nette\\Neon\\Neon' => __DIR__ . '/..' . '/nette/neon/src/Neon/Neon.php',
|
||||
'Nette\\NotImplementedException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\NotSupportedException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\OutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\PhpGenerator\\ClassType' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/ClassType.php',
|
||||
'Nette\\PhpGenerator\\Closure' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Closure.php',
|
||||
'Nette\\PhpGenerator\\Constant' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Constant.php',
|
||||
'Nette\\PhpGenerator\\Factory' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Factory.php',
|
||||
'Nette\\PhpGenerator\\GlobalFunction' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/GlobalFunction.php',
|
||||
'Nette\\PhpGenerator\\Helpers' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Helpers.php',
|
||||
'Nette\\PhpGenerator\\Method' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Method.php',
|
||||
'Nette\\PhpGenerator\\Parameter' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Parameter.php',
|
||||
'Nette\\PhpGenerator\\PhpFile' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PhpFile.php',
|
||||
'Nette\\PhpGenerator\\PhpLiteral' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PhpLiteral.php',
|
||||
'Nette\\PhpGenerator\\PhpNamespace' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PhpNamespace.php',
|
||||
'Nette\\PhpGenerator\\Printer' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Printer.php',
|
||||
'Nette\\PhpGenerator\\Property' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Property.php',
|
||||
'Nette\\PhpGenerator\\PsrPrinter' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PsrPrinter.php',
|
||||
'Nette\\PhpGenerator\\Traits\\CommentAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/CommentAware.php',
|
||||
'Nette\\PhpGenerator\\Traits\\FunctionLike' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/FunctionLike.php',
|
||||
'Nette\\PhpGenerator\\Traits\\NameAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/NameAware.php',
|
||||
'Nette\\PhpGenerator\\Traits\\VisibilityAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/VisibilityAware.php',
|
||||
'Nette\\SmartObject' => __DIR__ . '/..' . '/nette/utils/src/Utils/SmartObject.php',
|
||||
'Nette\\StaticClass' => __DIR__ . '/..' . '/nette/utils/src/Utils/StaticClass.php',
|
||||
'Nette\\StaticClassException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\UnexpectedValueException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\ArrayHash' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayHash.php',
|
||||
'Nette\\Utils\\ArrayList' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayList.php',
|
||||
'Nette\\Utils\\Arrays' => __DIR__ . '/..' . '/nette/utils/src/Utils/Arrays.php',
|
||||
'Nette\\Utils\\AssertionException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\Callback' => __DIR__ . '/..' . '/nette/utils/src/Utils/Callback.php',
|
||||
'Nette\\Utils\\DateTime' => __DIR__ . '/..' . '/nette/utils/src/Utils/DateTime.php',
|
||||
'Nette\\Utils\\FileSystem' => __DIR__ . '/..' . '/nette/utils/src/Utils/FileSystem.php',
|
||||
'Nette\\Utils\\Finder' => __DIR__ . '/..' . '/nette/finder/src/Utils/Finder.php',
|
||||
'Nette\\Utils\\Html' => __DIR__ . '/..' . '/nette/utils/src/Utils/Html.php',
|
||||
'Nette\\Utils\\IHtmlString' => __DIR__ . '/..' . '/nette/utils/src/Utils/IHtmlString.php',
|
||||
'Nette\\Utils\\Image' => __DIR__ . '/..' . '/nette/utils/src/Utils/Image.php',
|
||||
'Nette\\Utils\\ImageException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\Json' => __DIR__ . '/..' . '/nette/utils/src/Utils/Json.php',
|
||||
'Nette\\Utils\\JsonException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\ObjectHelpers' => __DIR__ . '/..' . '/nette/utils/src/Utils/ObjectHelpers.php',
|
||||
'Nette\\Utils\\ObjectMixin' => __DIR__ . '/..' . '/nette/utils/src/Utils/ObjectMixin.php',
|
||||
'Nette\\Utils\\Paginator' => __DIR__ . '/..' . '/nette/utils/src/Utils/Paginator.php',
|
||||
'Nette\\Utils\\Random' => __DIR__ . '/..' . '/nette/utils/src/Utils/Random.php',
|
||||
'Nette\\Utils\\Reflection' => __DIR__ . '/..' . '/nette/utils/src/Utils/Reflection.php',
|
||||
'Nette\\Utils\\RegexpException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\Strings' => __DIR__ . '/..' . '/nette/utils/src/Utils/Strings.php',
|
||||
'Nette\\Utils\\UnknownImageFileException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
|
||||
'Nette\\Utils\\Validators' => __DIR__ . '/..' . '/nette/utils/src/Utils/Validators.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit49e401a41abff8a9005dcbd044d35c5f::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit49e401a41abff8a9005dcbd044d35c5f::$prefixDirsPsr4;
|
||||
$loader->fallbackDirsPsr4 = ComposerStaticInit49e401a41abff8a9005dcbd044d35c5f::$fallbackDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit49e401a41abff8a9005dcbd044d35c5f::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
1125
vendor/composer/installed.json
vendored
Normal file
1125
vendor/composer/installed.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
55
vendor/composer/xdebug-handler/CHANGELOG.md
vendored
Normal file
55
vendor/composer/xdebug-handler/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
## [Unreleased]
|
||||
|
||||
## [1.3.2] - 2019-28-01
|
||||
* Fixed: exit call being blocked by uopz extension, resulting in application code running twice.
|
||||
|
||||
## [1.3.1] - 2018-11-29
|
||||
* Fixed: fail restart if `passthru` has been disabled in `disable_functions`.
|
||||
* Fixed: fail restart if an ini file cannot be opened, otherwise settings will be missing.
|
||||
|
||||
## [1.3.0] - 2018-08-31
|
||||
* Added: `setPersistent` method to use environment variables for the restart.
|
||||
* Fixed: improved debugging by writing output to stderr.
|
||||
* Fixed: no restart when `php_ini_scanned_files` is not functional and is needed.
|
||||
|
||||
## [1.2.1] - 2018-08-23
|
||||
* Fixed: fatal error with apc, when using `apc.mmap_file_mask`.
|
||||
|
||||
## [1.2.0] - 2018-08-16
|
||||
* Added: debug information using `XDEBUG_HANDLER_DEBUG`.
|
||||
* Added: fluent interface for setters.
|
||||
* Added: `PhpConfig` helper class for calling PHP sub-processes.
|
||||
* Added: `PHPRC` original value to restart stettings, for use in a restarted process.
|
||||
* Changed: internal procedure to disable ini-scanning, using `-n` command-line option.
|
||||
* Fixed: replaced `escapeshellarg` usage to avoid locale problems.
|
||||
* Fixed: improved color-option handling to respect double-dash delimiter.
|
||||
* Fixed: color-option handling regression from main script changes.
|
||||
* Fixed: improved handling when checking main script.
|
||||
* Fixed: handling for standard input, that never actually did anything.
|
||||
* Fixed: fatal error when ctype extension is not available.
|
||||
|
||||
## [1.1.0] - 2018-04-11
|
||||
* Added: `getRestartSettings` method for calling PHP processes in a restarted process.
|
||||
* Added: API definition and @internal class annotations.
|
||||
* Added: protected `requiresRestart` method for extending classes.
|
||||
* Added: `setMainScript` method for applications that change the working directory.
|
||||
* Changed: private `tmpIni` variable to protected for extending classes.
|
||||
* Fixed: environment variables not available in $_SERVER when restored in the restart.
|
||||
* Fixed: relative path problems caused by Phar::interceptFileFuncs.
|
||||
* Fixed: incorrect handling when script file cannot be found.
|
||||
|
||||
## [1.0.0] - 2018-03-08
|
||||
* Added: PSR3 logging for optional status output.
|
||||
* Added: existing ini settings are merged to catch command-line overrides.
|
||||
* Added: code, tests and other artefacts to decouple from Composer.
|
||||
* Break: the following class was renamed:
|
||||
- `Composer\XdebugHandler` -> `Composer\XdebugHandler\XdebugHandler`
|
||||
|
||||
[Unreleased]: https://github.com/composer/xdebug-handler/compare/1.3.2...HEAD
|
||||
[1.3.2]: https://github.com/composer/xdebug-handler/compare/1.3.1...1.3.2
|
||||
[1.3.1]: https://github.com/composer/xdebug-handler/compare/1.3.0...1.3.1
|
||||
[1.3.0]: https://github.com/composer/xdebug-handler/compare/1.2.1...1.3.0
|
||||
[1.2.1]: https://github.com/composer/xdebug-handler/compare/1.2.0...1.2.1
|
||||
[1.2.0]: https://github.com/composer/xdebug-handler/compare/1.1.0...1.2.0
|
||||
[1.1.0]: https://github.com/composer/xdebug-handler/compare/1.0.0...1.1.0
|
||||
[1.0.0]: https://github.com/composer/xdebug-handler/compare/d66f0d15cb57...1.0.0
|
21
vendor/composer/xdebug-handler/LICENSE
vendored
Normal file
21
vendor/composer/xdebug-handler/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 Composer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
288
vendor/composer/xdebug-handler/README.md
vendored
Normal file
288
vendor/composer/xdebug-handler/README.md
vendored
Normal file
|
@ -0,0 +1,288 @@
|
|||
# composer/xdebug-handler
|
||||
|
||||
[](https://packagist.org/packages/composer/xdebug-handler)
|
||||
[](https://travis-ci.org/composer/xdebug-handler)
|
||||
[](https://ci.appveyor.com/project/Seldaek/xdebug-handler)
|
||||

|
||||

|
||||
|
||||
Restart a CLI process without loading the xdebug extension.
|
||||
|
||||
Originally written as part of [composer/composer](https://github.com/composer/composer),
|
||||
now extracted and made available as a stand-alone library.
|
||||
|
||||
## Installation
|
||||
|
||||
Install the latest version with:
|
||||
|
||||
```bash
|
||||
$ composer require composer/xdebug-handler
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
* PHP 5.3.2 minimum, although functionality is disabled below PHP 5.4.0. Using the latest PHP version is highly recommended.
|
||||
|
||||
## Basic Usage
|
||||
```php
|
||||
use Composer\XdebugHandler\XdebugHandler;
|
||||
|
||||
$xdebug = new XdebugHandler('myapp');
|
||||
$xdebug->check();
|
||||
unset($xdebug);
|
||||
```
|
||||
|
||||
The constructor takes two parameters:
|
||||
|
||||
#### _$envPrefix_
|
||||
This is used to create distinct environment variables and is upper-cased and prepended to default base values. The above example enables the use of:
|
||||
|
||||
- `MYAPP_ALLOW_XDEBUG=1` to override automatic restart and allow xdebug
|
||||
- `MYAPP_ORIGINAL_INIS` to obtain ini file locations in a restarted process
|
||||
|
||||
#### _$colorOption_
|
||||
This optional value is added to the restart command-line and is needed to force color output in a piped child process. Only long-options are supported, for example `--ansi` or `--colors=always` etc.
|
||||
|
||||
If the original command-line contains an argument that pattern matches this value (for example `--no-ansi`, `--colors=never`) then _$colorOption_ is ignored.
|
||||
|
||||
If the pattern match ends with `=auto` (for example `--colors=auto`), the argument is replaced by _$colorOption_. Otherwise it is added at either the end of the command-line, or preceding the first double-dash `--` delimiter.
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
* [How it works](#how-it-works)
|
||||
* [Limitations](#limitations)
|
||||
* [Helper methods](#helper-methods)
|
||||
* [Setter methods](#setter-methods)
|
||||
* [Process configuration](#process-configuration)
|
||||
* [Troubleshooting](#troubleshooting)
|
||||
* [Extending the library](#extending-the-library)
|
||||
|
||||
### How it works
|
||||
|
||||
A temporary ini file is created from the loaded (and scanned) ini files, with any references to the xdebug extension commented out. Current ini settings are merged, so that most ini settings made on the command-line or by the application are included (see [Limitations](#limitations))
|
||||
|
||||
* `MYAPP_ALLOW_XDEBUG` is set with internal data to flag and use in the restart.
|
||||
* The command-line and environment are [configured](#process-configuration) for the restart.
|
||||
* The application is restarted in a new process using `passthru`.
|
||||
* The restart settings are stored in the environment.
|
||||
* `MYAPP_ALLOW_XDEBUG` is unset.
|
||||
* The application runs and exits.
|
||||
* The main process exits with the exit code from the restarted process.
|
||||
|
||||
### Limitations
|
||||
There are a few things to be aware of when running inside a restarted process.
|
||||
|
||||
* Extensions set on the command-line will not be loaded.
|
||||
* Ini file locations will be reported as per the restart - see [getAllIniFiles()](#getallinifiles).
|
||||
* Php sub-processes may be loaded with xdebug enabled - see [Process configuration](#process-configuration).
|
||||
|
||||
### Helper methods
|
||||
These static methods provide information from the current process, regardless of whether it has been restarted or not.
|
||||
|
||||
#### _getAllIniFiles()_
|
||||
Returns an array of the original ini file locations. Use this instead of calling `php_ini_loaded_file` and `php_ini_scanned_files`, which will report the wrong values in a restarted process.
|
||||
|
||||
```php
|
||||
use Composer\XdebugHandler\XdebugHandler;
|
||||
|
||||
$files = XdebugHandler::getAllIniFiles();
|
||||
|
||||
# $files[0] always exists, it could be an empty string
|
||||
$loadedIni = array_shift($files);
|
||||
$scannedInis = $files;
|
||||
```
|
||||
|
||||
These locations are also available in the `MYAPP_ORIGINAL_INIS` environment variable. This is a path-separated string comprising the location returned from `php_ini_loaded_file`, which could be empty, followed by locations parsed from calling `php_ini_scanned_files`.
|
||||
|
||||
#### _getRestartSettings()_
|
||||
Returns an array of settings that can be used with PHP [sub-processes](#sub-processes), or null if the process was not restarted.
|
||||
|
||||
```php
|
||||
use Composer\XdebugHandler\XdebugHandler;
|
||||
|
||||
$settings = XdebugHandler::getRestartSettings();
|
||||
/**
|
||||
* $settings: array (if the current process was restarted,
|
||||
* or called with the settings from a previous restart), or null
|
||||
*
|
||||
* 'tmpIni' => the temporary ini file used in the restart (string)
|
||||
* 'scannedInis' => if there were any scanned inis (bool)
|
||||
* 'scanDir' => the original PHP_INI_SCAN_DIR value (false|string)
|
||||
* 'phprc' => the original PHPRC value (false|string)
|
||||
* 'inis' => the original inis from getAllIniFiles (array)
|
||||
* 'skipped' => the skipped version from getSkippedVersion (string)
|
||||
*/
|
||||
```
|
||||
|
||||
#### _getSkippedVersion()_
|
||||
Returns the xdebug version string that was skipped by the restart, or an empty value if there was no restart (or xdebug is still loaded, perhaps by an extending class restarting for a reason other than removing xdebug).
|
||||
|
||||
```php
|
||||
use Composer\XdebugHandler\XdebugHandler;
|
||||
|
||||
$version = XdebugHandler::getSkippedVersion();
|
||||
# $version: '2.6.0' (for example), or an empty string
|
||||
```
|
||||
|
||||
### Setter methods
|
||||
These methods implement a fluent interface and must be called before the main `check()` method.
|
||||
|
||||
#### _setLogger($logger)_
|
||||
Enables the output of status messages to an external PSR3 logger. All messages are reported with either `DEBUG` or `WARNING` log levels. For example (showing the level and message):
|
||||
|
||||
```
|
||||
// Restart overridden
|
||||
DEBUG Checking MYAPP_ALLOW_XDEBUG
|
||||
DEBUG The xdebug extension is loaded (2.5.0)
|
||||
DEBUG No restart (MYAPP_ALLOW_XDEBUG=1)
|
||||
|
||||
// Failed restart
|
||||
DEBUG Checking MYAPP_ALLOW_XDEBUG
|
||||
DEBUG The xdebug extension is loaded (2.5.0)
|
||||
WARNING No restart (Unable to create temp ini file at: ...)
|
||||
```
|
||||
|
||||
Status messages can also be output with `XDEBUG_HANDLER_DEBUG`. See [Troubleshooting](#troubleshooting).
|
||||
|
||||
#### _setMainScript($script)_
|
||||
Sets the location of the main script to run in the restart. This is only needed in more esoteric use-cases, or if the `argv[0]` location is inaccessible. The script name `--` is supported for standard input.
|
||||
|
||||
#### _setPersistent()_
|
||||
Configures the restart using [persistent settings](#persistent-settings), so that xdebug is not loaded in any sub-process.
|
||||
|
||||
Use this method if your application invokes one or more PHP sub-process and the xdebug extension is not needed. This avoids the overhead of implementing specific [sub-process](#sub-processes) strategies.
|
||||
|
||||
Alternatively, this method can be used to set up a default _xdebug-free_ environment which can be changed if a sub-process requires xdebug, then restored afterwards:
|
||||
|
||||
```php
|
||||
function SubProcessWithXdebug()
|
||||
{
|
||||
$phpConfig = new Composer\XdebugHandler\PhpConfig();
|
||||
|
||||
# Set the environment to the original configuration
|
||||
$phpConfig->useOriginal();
|
||||
|
||||
# run the process with xdebug loaded
|
||||
...
|
||||
|
||||
# Restore xdebug-free environment
|
||||
$phpConfig->usePersistent();
|
||||
}
|
||||
```
|
||||
|
||||
### Process configuration
|
||||
The library offers two strategies to invoke a new PHP process without loading xdebug, using either _standard_ or _persistent_ settings. Note that this is only important if the application calls a PHP sub-process.
|
||||
|
||||
#### Standard settings
|
||||
Uses command-line options to remove xdebug from the new process only.
|
||||
|
||||
* The -n option is added to the command-line. This tells PHP not to scan for additional inis.
|
||||
* The temporary ini is added to the command-line with the -c option.
|
||||
|
||||
>_If the new process calls a PHP sub-process, xdebug will be loaded in that sub-process (unless it implements xdebug-handler, in which case there will be another restart)._
|
||||
|
||||
This is the default strategy used in the restart.
|
||||
|
||||
#### Persistent settings
|
||||
Uses environment variables to remove xdebug from the new process and persist these settings to any sub-process.
|
||||
|
||||
* `PHP_INI_SCAN_DIR` is set to an empty string. This tells PHP not to scan for additional inis.
|
||||
* `PHPRC` is set to the temporary ini.
|
||||
|
||||
>_If the new process calls a PHP sub-process, xdebug will not be loaded in that sub-process._
|
||||
|
||||
This strategy can be used in the restart by calling [setPersistent()](#setpersistent).
|
||||
|
||||
#### Sub-processes
|
||||
The `PhpConfig` helper class makes it easy to invoke a PHP sub-process (with or without xdebug loaded), regardless of whether there has been a restart.
|
||||
|
||||
Each of its methods returns an array of PHP options (to add to the command-line) and sets up the environment for the required strategy. The [getRestartSettings()](#getrestartsettings) method is used internally.
|
||||
|
||||
* `useOriginal()` - xdebug will be loaded in the new process.
|
||||
* `useStandard()` - xdebug will **not** be loaded in the new process - see [standard settings](#standard-settings).
|
||||
* `userPersistent()` - xdebug will **not** be loaded in the new process - see [persistent settings](#persistent-settings)
|
||||
|
||||
If there was no restart, an empty options array is returned and the environment is not changed.
|
||||
|
||||
```php
|
||||
use Composer\XdebugHandler\PhpConfig;
|
||||
|
||||
$config = new PhpConfig;
|
||||
|
||||
$options = $config->useOriginal();
|
||||
# $options: empty array
|
||||
# environment: PHPRC and PHP_INI_SCAN_DIR set to original values
|
||||
|
||||
$options = $config->useStandard();
|
||||
# $options: [-n, -c, tmpIni]
|
||||
# environment: PHPRC and PHP_INI_SCAN_DIR set to original values
|
||||
|
||||
$options = $config->usePersistent();
|
||||
# $options: empty array
|
||||
# environment: PHPRC=tmpIni, PHP_INI_SCAN_DIR=''
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
The following environment settings can be used to troubleshoot unexpected behavior:
|
||||
|
||||
* `XDEBUG_HANDLER_DEBUG=1` Outputs status messages to `STDERR`, if it is defined, irrespective of any PSR3 logger. Each message is prefixed `xdebug-handler[pid]`, where pid is the process identifier.
|
||||
|
||||
* `XDEBUG_HANDLER_DEBUG=2` As above, but additionally saves the temporary ini file and reports its location in a status message.
|
||||
|
||||
### Extending the library
|
||||
The API is defined by classes and their accessible elements that are not annotated as @internal. The main class has two protected methods that can be overridden to provide additional functionality:
|
||||
|
||||
#### _requiresRestart($isLoaded)_
|
||||
By default the process will restart if xdebug is loaded. Extending this method allows an application to decide, by returning a boolean (or equivalent) value. It is only called if `MYAPP_ALLOW_XDEBUG` is empty, so it will not be called in the restarted process (where this variable contains internal data), or if the restart has been overridden.
|
||||
|
||||
Note that the [setMainScript()](#setmainscriptscript) and [setPersistent()](#setpersistent) setters can be used here, if required.
|
||||
|
||||
#### _restart($command)_
|
||||
An application can extend this to modify the temporary ini file, its location given in the `tmpIni` property. New settings can be safely appended to the end of the data, which is `PHP_EOL` terminated.
|
||||
|
||||
Note that the `$command` parameter is the escaped command-line string that will be used for the new process and must be treated accordingly.
|
||||
|
||||
Remember to finish with `parent::restart($command)`.
|
||||
|
||||
#### Example
|
||||
This example demonstrates two ways to extend basic functionality:
|
||||
|
||||
* To avoid the overhead of spinning up a new process, the restart is skipped if a simple help command is requested.
|
||||
|
||||
* The application needs write-access to phar files, so it will force a restart if `phar.readonly` is set (regardless of whether xdebug is loaded) and change this value in the temporary ini file.
|
||||
|
||||
```php
|
||||
use Composer\XdebugHandler\XdebugHandler;
|
||||
use MyApp\Command;
|
||||
|
||||
class MyRestarter extends XdebugHandler
|
||||
{
|
||||
private $required;
|
||||
|
||||
protected function requiresRestart($isLoaded)
|
||||
{
|
||||
if (Command::isHelp()) {
|
||||
# No need to disable xdebug for this
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->required = (bool) ini_get('phar.readonly');
|
||||
return $isLoaded || $this->required;
|
||||
}
|
||||
|
||||
protected function restart($command)
|
||||
{
|
||||
if ($this->required) {
|
||||
# Add required ini setting to tmpIni
|
||||
$content = file_get_contents($this->tmpIni);
|
||||
$content .= 'phar.readonly=0'.PHP_EOL;
|
||||
file_put_contents($this->tmpIni, $content);
|
||||
}
|
||||
|
||||
parent::restart($command);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
composer/xdebug-handler is licensed under the MIT License, see the LICENSE file for details.
|
40
vendor/composer/xdebug-handler/composer.json
vendored
Normal file
40
vendor/composer/xdebug-handler/composer.json
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"name": "composer/xdebug-handler",
|
||||
"description": "Restarts a process without xdebug.",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"xdebug",
|
||||
"performance"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "John Stevenson",
|
||||
"email": "john-stevenson@blueyonder.co.uk"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.org/composer",
|
||||
"issues": "https://github.com/composer/xdebug-handler/issues"
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.2 || ^7.0",
|
||||
"psr/log": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Composer\\XdebugHandler\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Composer\\XdebugHandler\\": "tests"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit"
|
||||
}
|
||||
}
|
73
vendor/composer/xdebug-handler/src/PhpConfig.php
vendored
Normal file
73
vendor/composer/xdebug-handler/src/PhpConfig.php
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of composer/xdebug-handler.
|
||||
*
|
||||
* (c) Composer <https://github.com/composer>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\XdebugHandler;
|
||||
|
||||
/**
|
||||
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
|
||||
*/
|
||||
class PhpConfig
|
||||
{
|
||||
/**
|
||||
* Use the original PHP configuration
|
||||
*
|
||||
* @return array PHP cli options
|
||||
*/
|
||||
public function useOriginal()
|
||||
{
|
||||
$this->getDataAndReset();
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use standard restart settings
|
||||
*
|
||||
* @return array PHP cli options
|
||||
*/
|
||||
public function useStandard()
|
||||
{
|
||||
if ($data = $this->getDataAndReset()) {
|
||||
return array('-n', '-c', $data['tmpIni']);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use environment variables to persist settings
|
||||
*
|
||||
* @return array PHP cli options
|
||||
*/
|
||||
public function usePersistent()
|
||||
{
|
||||
if ($data = $this->getDataAndReset()) {
|
||||
Process::setEnv('PHPRC', $data['tmpIni']);
|
||||
Process::setEnv('PHP_INI_SCAN_DIR', '');
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns restart data if available and resets the environment
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function getDataAndReset()
|
||||
{
|
||||
if ($data = XdebugHandler::getRestartSettings()) {
|
||||
Process::setEnv('PHPRC', $data['phprc']);
|
||||
Process::setEnv('PHP_INI_SCAN_DIR', $data['scanDir']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
160
vendor/composer/xdebug-handler/src/Process.php
vendored
Normal file
160
vendor/composer/xdebug-handler/src/Process.php
vendored
Normal file
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of composer/xdebug-handler.
|
||||
*
|
||||
* (c) Composer <https://github.com/composer>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\XdebugHandler;
|
||||
|
||||
/**
|
||||
* Provides utility functions to prepare a child process command-line and set
|
||||
* environment variables in that process.
|
||||
*
|
||||
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
|
||||
* @internal
|
||||
*/
|
||||
class Process
|
||||
{
|
||||
/**
|
||||
* Returns an array of parameters, including a color option if required
|
||||
*
|
||||
* A color option is needed because child process output is piped.
|
||||
*
|
||||
* @param array $args The script parameters
|
||||
* @param string $colorOption The long option to force color output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function addColorOption(array $args, $colorOption)
|
||||
{
|
||||
if (!$colorOption
|
||||
|| in_array($colorOption, $args)
|
||||
|| !preg_match('/^--([a-z]+$)|(^--[a-z]+=)/', $colorOption, $matches)) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
if (isset($matches[2])) {
|
||||
// Handle --color(s)= options
|
||||
if (false !== ($index = array_search($matches[2].'auto', $args))) {
|
||||
$args[$index] = $colorOption;
|
||||
return $args;
|
||||
} elseif (preg_grep('/^'.$matches[2].'/', $args)) {
|
||||
return $args;
|
||||
}
|
||||
} elseif (in_array('--no-'.$matches[1], $args)) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
if (false !== ($index = array_search('--', $args))) {
|
||||
// Position option before double-dash delimiter
|
||||
array_splice($args, $index, 0, $colorOption);
|
||||
} else {
|
||||
$args[] = $colorOption;
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes a string to be used as a shell argument.
|
||||
*
|
||||
* From https://github.com/johnstevenson/winbox-args
|
||||
* MIT Licensed (c) John Stevenson <john-stevenson@blueyonder.co.uk>
|
||||
*
|
||||
* @param string $arg The argument to be escaped
|
||||
* @param bool $meta Additionally escape cmd.exe meta characters
|
||||
* @param bool $module The argument is the module to invoke
|
||||
*
|
||||
* @return string The escaped argument
|
||||
*/
|
||||
public static function escape($arg, $meta = true, $module = false)
|
||||
{
|
||||
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
return "'".str_replace("'", "'\\''", $arg)."'";
|
||||
}
|
||||
|
||||
$quote = strpbrk($arg, " \t") !== false || $arg === '';
|
||||
|
||||
$arg = preg_replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes);
|
||||
|
||||
if ($meta) {
|
||||
$meta = $dquotes || preg_match('/%[^%]+%/', $arg);
|
||||
|
||||
if (!$meta) {
|
||||
$quote = $quote || strpbrk($arg, '^&|<>()') !== false;
|
||||
} elseif ($module && !$dquotes && $quote) {
|
||||
$meta = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($quote) {
|
||||
$arg = '"'.preg_replace('/(\\\\*)$/', '$1$1', $arg).'"';
|
||||
}
|
||||
|
||||
if ($meta) {
|
||||
$arg = preg_replace('/(["^&|<>()%])/', '^$1', $arg);
|
||||
}
|
||||
|
||||
return $arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the output stream supports colors
|
||||
*
|
||||
* This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
|
||||
* terminals via named pipes, so we can only check the environment.
|
||||
*
|
||||
* @param mixed $output A valid CLI output stream
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function supportsColor($output)
|
||||
{
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
return (function_exists('sapi_windows_vt100_support')
|
||||
&& sapi_windows_vt100_support($output))
|
||||
|| false !== getenv('ANSICON')
|
||||
|| 'ON' === getenv('ConEmuANSI')
|
||||
|| 'xterm' === getenv('TERM');
|
||||
}
|
||||
|
||||
if (function_exists('stream_isatty')) {
|
||||
return stream_isatty($output);
|
||||
} elseif (function_exists('posix_isatty')) {
|
||||
return posix_isatty($output);
|
||||
}
|
||||
|
||||
$stat = fstat($output);
|
||||
// Check if formatted mode is S_IFCHR
|
||||
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes putenv environment changes available in $_SERVER
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|false $value A false value unsets the variable
|
||||
*
|
||||
* @return bool Whether the environment variable was set
|
||||
*/
|
||||
public static function setEnv($name, $value = false)
|
||||
{
|
||||
$unset = false === $value;
|
||||
|
||||
if (!putenv($unset ? $name : $name.'='.$value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($unset) {
|
||||
unset($_SERVER[$name]);
|
||||
} else {
|
||||
$_SERVER[$name] = $value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
163
vendor/composer/xdebug-handler/src/Status.php
vendored
Normal file
163
vendor/composer/xdebug-handler/src/Status.php
vendored
Normal file
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of composer/xdebug-handler.
|
||||
*
|
||||
* (c) Composer <https://github.com/composer>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\XdebugHandler;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
|
||||
* @internal
|
||||
*/
|
||||
class Status
|
||||
{
|
||||
const ENV_RESTART = 'XDEBUG_HANDLER_RESTART';
|
||||
const CHECK = 'Check';
|
||||
const ERROR = 'Error';
|
||||
const INFO = 'Info';
|
||||
const NORESTART = 'NoRestart';
|
||||
const RESTART = 'Restart';
|
||||
const RESTARTING = 'Restarting';
|
||||
const RESTARTED = 'Restarted';
|
||||
|
||||
private $debug;
|
||||
private $envAllowXdebug;
|
||||
private $loaded;
|
||||
private $logger;
|
||||
private $time;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $envAllowXdebug Prefixed _ALLOW_XDEBUG name
|
||||
* @param bool $debug Whether debug output is required
|
||||
*/
|
||||
public function __construct($envAllowXdebug, $debug)
|
||||
{
|
||||
$start = getenv(self::ENV_RESTART);
|
||||
Process::setEnv(self::ENV_RESTART);
|
||||
$this->time = $start ? round((microtime(true) - $start) * 1000) : 0;
|
||||
|
||||
$this->envAllowXdebug = $envAllowXdebug;
|
||||
$this->debug = $debug && defined('STDERR');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function setLogger(LoggerInterface $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a handler method to report a message
|
||||
*
|
||||
* @param string $op The handler constant
|
||||
* @param null|string $data Data required by the handler
|
||||
*/
|
||||
public function report($op, $data)
|
||||
{
|
||||
if ($this->logger || $this->debug) {
|
||||
call_user_func(array($this, 'report'.$op), $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a status message
|
||||
*
|
||||
* @param string $text
|
||||
* @param string $level
|
||||
*/
|
||||
private function output($text, $level = null)
|
||||
{
|
||||
if ($this->logger) {
|
||||
$this->logger->log($level ?: LogLevel::DEBUG, $text);
|
||||
}
|
||||
|
||||
if ($this->debug) {
|
||||
fwrite(STDERR, sprintf('xdebug-handler[%d] %s', getmypid(), $text.PHP_EOL));
|
||||
}
|
||||
}
|
||||
|
||||
private function reportCheck($loaded)
|
||||
{
|
||||
$this->loaded = $loaded;
|
||||
$this->output('Checking '.$this->envAllowXdebug);
|
||||
}
|
||||
|
||||
private function reportError($error)
|
||||
{
|
||||
$this->output(sprintf('No restart (%s)', $error), LogLevel::WARNING);
|
||||
}
|
||||
|
||||
private function reportInfo($info)
|
||||
{
|
||||
$this->output($info);
|
||||
}
|
||||
|
||||
private function reportNoRestart()
|
||||
{
|
||||
$this->output($this->getLoadedMessage());
|
||||
|
||||
if ($this->loaded) {
|
||||
$text = sprintf('No restart (%s)', $this->getEnvAllow());
|
||||
if (!getenv($this->envAllowXdebug)) {
|
||||
$text .= ' Allowed by application';
|
||||
}
|
||||
$this->output($text);
|
||||
}
|
||||
}
|
||||
|
||||
private function reportRestart()
|
||||
{
|
||||
$this->output($this->getLoadedMessage());
|
||||
Process::setEnv(self::ENV_RESTART, (string) microtime(true));
|
||||
}
|
||||
|
||||
private function reportRestarted()
|
||||
{
|
||||
$loaded = $this->getLoadedMessage();
|
||||
$text = sprintf('Restarted (%d ms). %s', $this->time, $loaded);
|
||||
$level = $this->loaded ? LogLevel::WARNING : null;
|
||||
$this->output($text, $level);
|
||||
}
|
||||
|
||||
private function reportRestarting($command)
|
||||
{
|
||||
$text = sprintf('Process restarting (%s)', $this->getEnvAllow());
|
||||
$this->output($text);
|
||||
$text = 'Running '.$command;
|
||||
$this->output($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the _ALLOW_XDEBUG environment variable as name=value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getEnvAllow()
|
||||
{
|
||||
return $this->envAllowXdebug.'='.getenv($this->envAllowXdebug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the xdebug status and version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getLoadedMessage()
|
||||
{
|
||||
$loaded = $this->loaded ? sprintf('loaded (%s)', $this->loaded) : 'not loaded';
|
||||
return 'The xdebug extension is '.$loaded;
|
||||
}
|
||||
}
|
565
vendor/composer/xdebug-handler/src/XdebugHandler.php
vendored
Normal file
565
vendor/composer/xdebug-handler/src/XdebugHandler.php
vendored
Normal file
|
@ -0,0 +1,565 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of composer/xdebug-handler.
|
||||
*
|
||||
* (c) Composer <https://github.com/composer>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\XdebugHandler;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
|
||||
*/
|
||||
class XdebugHandler
|
||||
{
|
||||
const SUFFIX_ALLOW = '_ALLOW_XDEBUG';
|
||||
const SUFFIX_INIS = '_ORIGINAL_INIS';
|
||||
const RESTART_ID = 'internal';
|
||||
const RESTART_SETTINGS = 'XDEBUG_HANDLER_SETTINGS';
|
||||
const DEBUG = 'XDEBUG_HANDLER_DEBUG';
|
||||
|
||||
/** @var string|null */
|
||||
protected $tmpIni;
|
||||
|
||||
private static $inRestart;
|
||||
private static $name;
|
||||
private static $skipped;
|
||||
|
||||
private $cli;
|
||||
private $colorOption;
|
||||
private $debug;
|
||||
private $envAllowXdebug;
|
||||
private $envOriginalInis;
|
||||
private $loaded;
|
||||
private $persistent;
|
||||
private $script;
|
||||
/** @var Status|null */
|
||||
private $statusWriter;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* The $envPrefix is used to create distinct environment variables. It is
|
||||
* uppercased and prepended to the default base values. For example 'myapp'
|
||||
* would result in MYAPP_ALLOW_XDEBUG and MYAPP_ORIGINAL_INIS.
|
||||
*
|
||||
* @param string $envPrefix Value used in environment variables
|
||||
* @param string $colorOption Command-line long option to force color output
|
||||
* @throws \RuntimeException If a parameter is invalid
|
||||
*/
|
||||
public function __construct($envPrefix, $colorOption = '')
|
||||
{
|
||||
if (!is_string($envPrefix) || empty($envPrefix) || !is_string($colorOption)) {
|
||||
throw new \RuntimeException('Invalid constructor parameter');
|
||||
}
|
||||
|
||||
self::$name = strtoupper($envPrefix);
|
||||
$this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
|
||||
$this->envOriginalInis = self::$name.self::SUFFIX_INIS;
|
||||
|
||||
$this->colorOption = $colorOption;
|
||||
|
||||
if (extension_loaded('xdebug')) {
|
||||
$ext = new \ReflectionExtension('xdebug');
|
||||
$this->loaded = $ext->getVersion() ?: 'unknown';
|
||||
}
|
||||
|
||||
if ($this->cli = PHP_SAPI === 'cli') {
|
||||
$this->debug = getenv(self::DEBUG);
|
||||
}
|
||||
|
||||
$this->statusWriter = new Status($this->envAllowXdebug, (bool) $this->debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates status message output to a PSR3 logger
|
||||
*
|
||||
* @param LoggerInterface $logger
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setLogger(LoggerInterface $logger)
|
||||
{
|
||||
$this->statusWriter->setLogger($logger);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the main script location if it cannot be called from argv
|
||||
*
|
||||
* @param string $script
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMainScript($script)
|
||||
{
|
||||
$this->script = $script;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist the settings to keep xdebug out of sub-processes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPersistent()
|
||||
{
|
||||
$this->persistent = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if xdebug is loaded and the process needs to be restarted
|
||||
*
|
||||
* This behaviour can be disabled by setting the MYAPP_ALLOW_XDEBUG
|
||||
* environment variable to 1. This variable is used internally so that
|
||||
* the restarted process is created only once.
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
$this->notify(Status::CHECK, $this->loaded);
|
||||
$envArgs = explode('|', (string) getenv($this->envAllowXdebug));
|
||||
|
||||
if (empty($envArgs[0]) && $this->requiresRestart((bool) $this->loaded)) {
|
||||
// Restart required
|
||||
$this->notify(Status::RESTART);
|
||||
|
||||
if ($this->prepareRestart()) {
|
||||
$command = $this->getCommand();
|
||||
$this->notify(Status::RESTARTING, $command);
|
||||
$this->restart($command);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (self::RESTART_ID === $envArgs[0] && count($envArgs) === 5) {
|
||||
// Restarting, so unset environment variable and use saved values
|
||||
$this->notify(Status::RESTARTED);
|
||||
|
||||
Process::setEnv($this->envAllowXdebug);
|
||||
self::$inRestart = true;
|
||||
|
||||
if (!$this->loaded) {
|
||||
// Skipped version is only set if xdebug is not loaded
|
||||
self::$skipped = $envArgs[1];
|
||||
}
|
||||
|
||||
// Put restart settings in the environment
|
||||
$this->setEnvRestartSettings($envArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->notify(Status::NORESTART);
|
||||
|
||||
if ($settings = self::getRestartSettings()) {
|
||||
// Called with existing settings, so sync our settings
|
||||
$this->syncSettings($settings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of php.ini locations with at least one entry
|
||||
*
|
||||
* The equivalent of calling php_ini_loaded_file then php_ini_scanned_files.
|
||||
* The loaded ini location is the first entry and may be empty.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getAllIniFiles()
|
||||
{
|
||||
if (!empty(self::$name)) {
|
||||
$env = getenv(self::$name.self::SUFFIX_INIS);
|
||||
|
||||
if (false !== $env) {
|
||||
return explode(PATH_SEPARATOR, $env);
|
||||
}
|
||||
}
|
||||
|
||||
$paths = array((string) php_ini_loaded_file());
|
||||
|
||||
if ($scanned = php_ini_scanned_files()) {
|
||||
$paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of restart settings or null
|
||||
*
|
||||
* Settings will be available if the current process was restarted, or
|
||||
* called with the settings from an existing restart.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public static function getRestartSettings()
|
||||
{
|
||||
$envArgs = explode('|', (string) getenv(self::RESTART_SETTINGS));
|
||||
|
||||
if (count($envArgs) !== 6
|
||||
|| (!self::$inRestart && php_ini_loaded_file() !== $envArgs[0])) {
|
||||
return;
|
||||
}
|
||||
|
||||
return array(
|
||||
'tmpIni' => $envArgs[0],
|
||||
'scannedInis' => (bool) $envArgs[1],
|
||||
'scanDir' => '*' === $envArgs[2] ? false : $envArgs[2],
|
||||
'phprc' => '*' === $envArgs[3] ? false : $envArgs[3],
|
||||
'inis' => explode(PATH_SEPARATOR, $envArgs[4]),
|
||||
'skipped' => $envArgs[5],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the xdebug version that triggered a successful restart
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getSkippedVersion()
|
||||
{
|
||||
return (string) self::$skipped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if xdebug is loaded, or as directed by an extending class
|
||||
*
|
||||
* @param bool $isLoaded Whether xdebug is loaded
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function requiresRestart($isLoaded)
|
||||
{
|
||||
return $isLoaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows an extending class to access the tmpIni
|
||||
*
|
||||
* @param string $command
|
||||
*/
|
||||
protected function restart($command)
|
||||
{
|
||||
$this->doRestart($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the restarted command then deletes the tmp ini
|
||||
*
|
||||
* @param string $command
|
||||
*/
|
||||
private function doRestart($command)
|
||||
{
|
||||
passthru($command, $exitCode);
|
||||
$this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
|
||||
|
||||
if ($this->debug === '2') {
|
||||
$this->notify(Status::INFO, 'Temp ini saved: '.$this->tmpIni);
|
||||
} else {
|
||||
@unlink($this->tmpIni);
|
||||
}
|
||||
|
||||
exit($exitCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if everything was written for the restart
|
||||
*
|
||||
* If any of the following fails (however unlikely) we must return false to
|
||||
* stop potential recursion:
|
||||
* - tmp ini file creation
|
||||
* - environment variable creation
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function prepareRestart()
|
||||
{
|
||||
$error = '';
|
||||
$iniFiles = self::getAllIniFiles();
|
||||
$scannedInis = count($iniFiles) > 1;
|
||||
$tmpDir = sys_get_temp_dir();
|
||||
|
||||
if (!$this->cli) {
|
||||
$error = 'Unsupported SAPI: '.PHP_SAPI;
|
||||
} elseif (!defined('PHP_BINARY')) {
|
||||
$error = 'PHP version is too old: '.PHP_VERSION;
|
||||
} elseif (!$this->checkConfiguration($info)) {
|
||||
$error = $info;
|
||||
} elseif (!$this->checkScanDirConfig()) {
|
||||
$error = 'PHP version does not report scanned inis: '.PHP_VERSION;
|
||||
} elseif (!$this->checkMainScript()) {
|
||||
$error = 'Unable to access main script: '.$this->script;
|
||||
} elseif (!$this->writeTmpIni($iniFiles, $tmpDir, $error)) {
|
||||
$error = $error ?: 'Unable to create temp ini file at: '.$tmpDir;
|
||||
} elseif (!$this->setEnvironment($scannedInis, $iniFiles)) {
|
||||
$error = 'Unable to set environment variables';
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
$this->notify(Status::ERROR, $error);
|
||||
}
|
||||
|
||||
return empty($error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the tmp ini file was written
|
||||
*
|
||||
* @param array $iniFiles All ini files used in the current process
|
||||
* @param string $tmpDir The system temporary directory
|
||||
* @param string $error Set by method if ini file cannot be read
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function writeTmpIni(array $iniFiles, $tmpDir, &$error)
|
||||
{
|
||||
if (!$this->tmpIni = @tempnam($tmpDir, '')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// $iniFiles has at least one item and it may be empty
|
||||
if (empty($iniFiles[0])) {
|
||||
array_shift($iniFiles);
|
||||
}
|
||||
|
||||
$content = '';
|
||||
$regex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
|
||||
|
||||
foreach ($iniFiles as $file) {
|
||||
// Check for inaccessible ini files
|
||||
if (!$data = @file_get_contents($file)) {
|
||||
$error = 'Unable to read ini: '.$file;
|
||||
return false;
|
||||
}
|
||||
$content .= preg_replace($regex, ';$1', $data).PHP_EOL;
|
||||
}
|
||||
|
||||
// Merge loaded settings into our ini content, if it is valid
|
||||
if ($config = parse_ini_string($content)) {
|
||||
$loaded = ini_get_all(null, false);
|
||||
$content .= $this->mergeLoadedConfig($loaded, $config);
|
||||
}
|
||||
|
||||
// Work-around for https://bugs.php.net/bug.php?id=75932
|
||||
$content .= 'opcache.enable_cli=0'.PHP_EOL;
|
||||
|
||||
return @file_put_contents($this->tmpIni, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the restart command line
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getCommand()
|
||||
{
|
||||
$php = array(PHP_BINARY);
|
||||
$args = array_slice($_SERVER['argv'], 1);
|
||||
|
||||
if (!$this->persistent) {
|
||||
// Use command-line options
|
||||
array_push($php, '-n', '-c', $this->tmpIni);
|
||||
}
|
||||
|
||||
if (defined('STDOUT') && Process::supportsColor(STDOUT)) {
|
||||
$args = Process::addColorOption($args, $this->colorOption);
|
||||
}
|
||||
|
||||
$args = array_merge($php, array($this->script), $args);
|
||||
|
||||
$cmd = Process::escape(array_shift($args), true, true);
|
||||
foreach ($args as $arg) {
|
||||
$cmd .= ' '.Process::escape($arg);
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the restart environment variables were set
|
||||
*
|
||||
* No need to update $_SERVER since this is set in the restarted process.
|
||||
*
|
||||
* @param bool $scannedInis Whether there were scanned ini files
|
||||
* @param array $iniFiles All ini files used in the current process
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function setEnvironment($scannedInis, array $iniFiles)
|
||||
{
|
||||
$scanDir = getenv('PHP_INI_SCAN_DIR');
|
||||
$phprc = getenv('PHPRC');
|
||||
|
||||
// Make original inis available to restarted process
|
||||
if (!putenv($this->envOriginalInis.'='.implode(PATH_SEPARATOR, $iniFiles))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->persistent) {
|
||||
// Use the environment to persist the settings
|
||||
if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$this->tmpIni)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Flag restarted process and save values for it to use
|
||||
$envArgs = array(
|
||||
self::RESTART_ID,
|
||||
$this->loaded,
|
||||
(int) $scannedInis,
|
||||
false === $scanDir ? '*' : $scanDir,
|
||||
false === $phprc ? '*' : $phprc,
|
||||
);
|
||||
|
||||
return putenv($this->envAllowXdebug.'='.implode('|', $envArgs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs status messages
|
||||
*
|
||||
* @param string $op Status handler constant
|
||||
* @param null|string $data Optional data
|
||||
*/
|
||||
private function notify($op, $data = null)
|
||||
{
|
||||
$this->statusWriter->report($op, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default, changed and command-line ini settings
|
||||
*
|
||||
* @param array $loadedConfig All current ini settings
|
||||
* @param array $iniConfig Settings from user ini files
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function mergeLoadedConfig(array $loadedConfig, array $iniConfig)
|
||||
{
|
||||
$content = '';
|
||||
|
||||
foreach ($loadedConfig as $name => $value) {
|
||||
// Value will either be null, string or array (HHVM only)
|
||||
if (!is_string($value)
|
||||
|| strpos($name, 'xdebug') === 0
|
||||
|| $name === 'apc.mmap_file_mask') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
|
||||
// Double-quote escape each value
|
||||
$content .= $name.'="'.addcslashes($value, '\\"').'"'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the script name can be used
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function checkMainScript()
|
||||
{
|
||||
if (null !== $this->script) {
|
||||
// Allow an application to set -- for standard input
|
||||
return file_exists($this->script) || '--' === $this->script;
|
||||
}
|
||||
|
||||
if (file_exists($this->script = $_SERVER['argv'][0])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use a backtrace to resolve Phar and chdir issues
|
||||
$options = PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : false;
|
||||
$trace = debug_backtrace($options);
|
||||
|
||||
if (($main = end($trace)) && isset($main['file'])) {
|
||||
return file_exists($this->script = $main['file']);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds restart settings to the environment
|
||||
*
|
||||
* @param string $envArgs
|
||||
*/
|
||||
private function setEnvRestartSettings($envArgs)
|
||||
{
|
||||
$settings = array(
|
||||
php_ini_loaded_file(),
|
||||
$envArgs[2],
|
||||
$envArgs[3],
|
||||
$envArgs[4],
|
||||
getenv($this->envOriginalInis),
|
||||
self::$skipped,
|
||||
);
|
||||
|
||||
Process::setEnv(self::RESTART_SETTINGS, implode('|', $settings));
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs settings and the environment if called with existing settings
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
private function syncSettings(array $settings)
|
||||
{
|
||||
if (false === getenv($this->envOriginalInis)) {
|
||||
// Called by another app, so make original inis available
|
||||
Process::setEnv($this->envOriginalInis, implode(PATH_SEPARATOR, $settings['inis']));
|
||||
}
|
||||
|
||||
self::$skipped = $settings['skipped'];
|
||||
$this->notify(Status::INFO, 'Process called with existing restart settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are scanned inis and PHP is able to report them
|
||||
*
|
||||
* php_ini_scanned_files will fail when PHP_CONFIG_FILE_SCAN_DIR is empty.
|
||||
* Fixed in 7.1.13 and 7.2.1
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function checkScanDirConfig()
|
||||
{
|
||||
return !(getenv('PHP_INI_SCAN_DIR')
|
||||
&& !PHP_CONFIG_FILE_SCAN_DIR
|
||||
&& (PHP_VERSION_ID < 70113
|
||||
|| PHP_VERSION_ID === 70200));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are no known configuration issues
|
||||
*
|
||||
* @param string $info Set by method
|
||||
*/
|
||||
private function checkConfiguration(&$info)
|
||||
{
|
||||
if (false !== strpos(ini_get('disable_functions'), 'passthru')) {
|
||||
$info = 'passthru function is disabled';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extension_loaded('uopz')) {
|
||||
// uopz works at opcode level and disables exit calls
|
||||
if (function_exists('uopz_allow_exit')) {
|
||||
@uopz_allow_exit(true);
|
||||
} else {
|
||||
$info = 'uopz extension is not compatible';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
43
vendor/jean85/pretty-package-versions/composer.json
vendored
Normal file
43
vendor/jean85/pretty-package-versions/composer.json
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "jean85/pretty-package-versions",
|
||||
"description": "A wrapper for ocramius/package-versions to get pretty versions strings",
|
||||
"type": "library",
|
||||
"require": {
|
||||
"php": "^7.0",
|
||||
"ocramius/package-versions": "^1.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alessandro Lai",
|
||||
"email": "alessandro.lai85@gmail.com"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Jean85/pretty-package-versions/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"package",
|
||||
"versions",
|
||||
"composer",
|
||||
"release"
|
||||
],
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Jean85\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests"
|
||||
}
|
||||
}
|
||||
}
|
15
vendor/jean85/pretty-package-versions/src/PrettyVersions.php
vendored
Normal file
15
vendor/jean85/pretty-package-versions/src/PrettyVersions.php
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Jean85;
|
||||
|
||||
use PackageVersions\Versions;
|
||||
|
||||
class PrettyVersions
|
||||
{
|
||||
const SHORT_COMMIT_LENGTH = 7;
|
||||
|
||||
public static function getVersion(string $packageName): Version
|
||||
{
|
||||
return new Version($packageName, Versions::getVersion($packageName));
|
||||
}
|
||||
}
|
78
vendor/jean85/pretty-package-versions/src/Version.php
vendored
Normal file
78
vendor/jean85/pretty-package-versions/src/Version.php
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace Jean85;
|
||||
|
||||
class Version
|
||||
{
|
||||
const SHORT_COMMIT_LENGTH = 7;
|
||||
|
||||
/** @var string */
|
||||
private $packageName;
|
||||
|
||||
/** @var string */
|
||||
private $shortVersion;
|
||||
|
||||
/** @var string */
|
||||
private $commitHash;
|
||||
|
||||
/** @var bool */
|
||||
private $versionIsTagged;
|
||||
|
||||
/**
|
||||
* Version constructor.
|
||||
* @param string $packageName
|
||||
* @param string $version
|
||||
*/
|
||||
public function __construct(string $packageName, string $version)
|
||||
{
|
||||
$this->packageName = $packageName;
|
||||
$splittedVersion = explode('@', $version);
|
||||
$this->shortVersion = $splittedVersion[0];
|
||||
$this->commitHash = $splittedVersion[1];
|
||||
$this->versionIsTagged = preg_match('/[^v\d\.]/', $this->getShortVersion()) === 0;
|
||||
}
|
||||
|
||||
public function getPrettyVersion(): string
|
||||
{
|
||||
if ($this->versionIsTagged) {
|
||||
return $this->getShortVersion();
|
||||
}
|
||||
|
||||
return $this->getVersionWithShortCommit();
|
||||
}
|
||||
|
||||
public function getFullVersion(): string
|
||||
{
|
||||
return $this->getShortVersion() . '@' . $this->getCommitHash();
|
||||
}
|
||||
|
||||
public function getVersionWithShortCommit(): string
|
||||
{
|
||||
return $this->getShortVersion() . '@' . $this->getShortCommitHash();
|
||||
}
|
||||
|
||||
public function getPackageName(): string
|
||||
{
|
||||
return $this->packageName;
|
||||
}
|
||||
|
||||
public function getShortVersion(): string
|
||||
{
|
||||
return $this->shortVersion;
|
||||
}
|
||||
|
||||
public function getCommitHash(): string
|
||||
{
|
||||
return $this->commitHash;
|
||||
}
|
||||
|
||||
public function getShortCommitHash(): string
|
||||
{
|
||||
return substr($this->commitHash, 0, self::SHORT_COMMIT_LENGTH);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getPrettyVersion();
|
||||
}
|
||||
}
|
52
vendor/nette/bootstrap/composer.json
vendored
Normal file
52
vendor/nette/bootstrap/composer.json
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"name": "nette/bootstrap",
|
||||
"description": "🅱 Nette Bootstrap: the simple way to configure and bootstrap your Nette application.",
|
||||
"keywords": ["nette", "configurator", "bootstrapping"],
|
||||
"homepage": "https://nette.org",
|
||||
"license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Grudl",
|
||||
"homepage": "https://davidgrudl.com"
|
||||
},
|
||||
{
|
||||
"name": "Nette Community",
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"nette/di": "~2.4.7",
|
||||
"nette/utils": "~2.4"
|
||||
},
|
||||
"suggest": {
|
||||
"nette/robot-loader": "to use Configurator::createRobotLoader()",
|
||||
"tracy/tracy": "to use Configurator::enableTracy()"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/application": "~2.3",
|
||||
"nette/caching": "~2.3",
|
||||
"nette/database": "~2.3",
|
||||
"nette/forms": "~2.3",
|
||||
"nette/http": "~2.4.0",
|
||||
"nette/mail": "~2.3",
|
||||
"nette/robot-loader": "^2.4.2 || ^3.0",
|
||||
"nette/safe-stream": "~2.2",
|
||||
"nette/security": "~2.3",
|
||||
"nette/tester": "~2.0",
|
||||
"latte/latte": "~2.2",
|
||||
"tracy/tracy": "^2.4.1"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["src/"]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
}
|
||||
}
|
||||
}
|
27
vendor/nette/bootstrap/contributing.md
vendored
Normal file
27
vendor/nette/bootstrap/contributing.md
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
How to contribute & use the issue tracker
|
||||
=========================================
|
||||
|
||||
The issue tracker is the preferred channel for bug reports, features requests
|
||||
and submitting pull requests, but please respect the following restrictions:
|
||||
|
||||
* Please **do not** use the issue tracker for personal support requests (use
|
||||
[Nette forum](https://forum.nette.org) or [Stack Overflow](http://stackoverflow.com)).
|
||||
|
||||
* Please **do not** derail or troll issues. Keep the discussion on topic and
|
||||
respect the opinions of others.
|
||||
|
||||
* Use the GitHub **issue search** — check if the issue has already been
|
||||
reported.
|
||||
|
||||
A good **bug report** shouldn't leave others needing to chase you up for more
|
||||
information. Please try to be as detailed as possible in your report.
|
||||
|
||||
**Feature requests** are welcome. But take a moment to find out whether your idea
|
||||
fits with the scope and aims of the project. It's up to *you* to make a strong
|
||||
case to convince the project's developers of the merits of this feature.
|
||||
|
||||
Nette welcomes **pull requests**. If you'd like to contribute, please take a moment
|
||||
to [read the guidelines](https://nette.org/en/contributing) in order to make
|
||||
the contribution process easy and effective for everyone involved.
|
||||
|
||||
Thanks!
|
60
vendor/nette/bootstrap/license.md
vendored
Normal file
60
vendor/nette/bootstrap/license.md
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
Licenses
|
||||
========
|
||||
|
||||
Good news! You may use Nette Framework under the terms of either
|
||||
the New BSD License or the GNU General Public License (GPL) version 2 or 3.
|
||||
|
||||
The BSD License is recommended for most projects. It is easy to understand and it
|
||||
places almost no restrictions on what you can do with the framework. If the GPL
|
||||
fits better to your project, you can use the framework under this license.
|
||||
|
||||
You don't have to notify anyone which license you are using. You can freely
|
||||
use Nette Framework in commercial projects as long as the copyright header
|
||||
remains intact.
|
||||
|
||||
Please be advised that the name "Nette Framework" is a protected trademark and its
|
||||
usage has some limitations. So please do not use word "Nette" in the name of your
|
||||
project or top-level domain, and choose a name that stands on its own merits.
|
||||
If your stuff is good, it will not take long to establish a reputation for yourselves.
|
||||
|
||||
|
||||
New BSD License
|
||||
---------------
|
||||
|
||||
Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "Nette Framework" nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as is" and
|
||||
any express or implied warranties, including, but not limited to, the implied
|
||||
warranties of merchantability and fitness for a particular purpose are
|
||||
disclaimed. In no event shall the copyright owner or contributors be liable for
|
||||
any direct, indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or services;
|
||||
loss of use, data, or profits; or business interruption) however caused and on
|
||||
any theory of liability, whether in contract, strict liability, or tort
|
||||
(including negligence or otherwise) arising in any way out of the use of this
|
||||
software, even if advised of the possibility of such damage.
|
||||
|
||||
|
||||
GNU General Public License
|
||||
--------------------------
|
||||
|
||||
GPL licenses are very very long, so instead of including them here we offer
|
||||
you URLs with full text:
|
||||
|
||||
- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
|
||||
- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
|
61
vendor/nette/bootstrap/readme.md
vendored
Normal file
61
vendor/nette/bootstrap/readme.md
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
Nette Bootstrap
|
||||
===============
|
||||
|
||||
[](https://packagist.org/packages/nette/bootstrap)
|
||||
[](https://travis-ci.org/nette/bootstrap)
|
||||
[](https://coveralls.io/github/nette/bootstrap?branch=master)
|
||||
[](https://github.com/nette/bootstrap/releases)
|
||||
[](https://github.com/nette/bootstrap/blob/master/license.md)
|
||||
|
||||
File `bootstrap.php` loads Nette Framework and all libraries that we depend on:
|
||||
|
||||
```php
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
```
|
||||
|
||||
Class `Configurator` creates so called DI container and handles application initialization.
|
||||
|
||||
```php
|
||||
$configurator = new Nette\Configurator;
|
||||
```
|
||||
|
||||
Activates Tracy in strict mode:
|
||||
|
||||
```php
|
||||
//$configurator->setDebugMode(true);
|
||||
$configurator->enableTracy(__DIR__ . '/../log');
|
||||
```
|
||||
|
||||
Setup directory for temporary files
|
||||
|
||||
```php
|
||||
$configurator->setTempDirectory(__DIR__ . '/../temp');
|
||||
```
|
||||
|
||||
Activate [autoloading](https://doc.nette.org/en/auto-loading#toc-nette-loaders-robotloader), that will automatically load all the files with our classes:
|
||||
|
||||
```php
|
||||
$configurator->createRobotLoader()
|
||||
->addDirectory(__DIR__)
|
||||
->addDirectory(__DIR__ . '/../vendor/others')
|
||||
->register();
|
||||
```
|
||||
|
||||
And according to the configuration files it generates a DI container. Everything else depends on it.
|
||||
|
||||
We will return this DI Container as a result of calling `app/boostrap.php`
|
||||
|
||||
```php
|
||||
$configurator->addConfig(__DIR__ . '/config/config.neon');
|
||||
$configurator->addConfig(__DIR__ . '/config/config.local.neon');
|
||||
return $configurator->createContainer();
|
||||
```
|
||||
|
||||
and we will store it as local variable in `www/index.php` and run the application:
|
||||
|
||||
```php
|
||||
$container = require __DIR__ . '/../app/bootstrap.php';
|
||||
$container->getService('application')->run();
|
||||
```
|
||||
|
||||
That's it.
|
395
vendor/nette/bootstrap/src/Bootstrap/Configurator.php
vendored
Normal file
395
vendor/nette/bootstrap/src/Bootstrap/Configurator.php
vendored
Normal file
|
@ -0,0 +1,395 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette;
|
||||
|
||||
use Nette;
|
||||
use Nette\DI;
|
||||
use Tracy;
|
||||
|
||||
|
||||
/**
|
||||
* Initial system DI container generator.
|
||||
*/
|
||||
class Configurator
|
||||
{
|
||||
use SmartObject;
|
||||
|
||||
const AUTO = true,
|
||||
NONE = false;
|
||||
|
||||
const COOKIE_SECRET = 'nette-debug';
|
||||
|
||||
/** @var callable[] function (Configurator $sender, DI\Compiler $compiler); Occurs after the compiler is created */
|
||||
public $onCompile;
|
||||
|
||||
/** @var array */
|
||||
public $defaultExtensions = [
|
||||
'php' => Nette\DI\Extensions\PhpExtension::class,
|
||||
'constants' => Nette\DI\Extensions\ConstantsExtension::class,
|
||||
'extensions' => Nette\DI\Extensions\ExtensionsExtension::class,
|
||||
'application' => [Nette\Bridges\ApplicationDI\ApplicationExtension::class, ['%debugMode%', ['%appDir%'], '%tempDir%/cache']],
|
||||
'decorator' => Nette\DI\Extensions\DecoratorExtension::class,
|
||||
'cache' => [Nette\Bridges\CacheDI\CacheExtension::class, ['%tempDir%']],
|
||||
'database' => [Nette\Bridges\DatabaseDI\DatabaseExtension::class, ['%debugMode%']],
|
||||
'di' => [Nette\DI\Extensions\DIExtension::class, ['%debugMode%']],
|
||||
'forms' => Nette\Bridges\FormsDI\FormsExtension::class,
|
||||
'http' => [Nette\Bridges\HttpDI\HttpExtension::class, ['%consoleMode%']],
|
||||
'latte' => [Nette\Bridges\ApplicationDI\LatteExtension::class, ['%tempDir%/cache/latte', '%debugMode%']],
|
||||
'mail' => Nette\Bridges\MailDI\MailExtension::class,
|
||||
'routing' => [Nette\Bridges\ApplicationDI\RoutingExtension::class, ['%debugMode%']],
|
||||
'security' => [Nette\Bridges\SecurityDI\SecurityExtension::class, ['%debugMode%']],
|
||||
'session' => [Nette\Bridges\HttpDI\SessionExtension::class, ['%debugMode%', '%consoleMode%']],
|
||||
'tracy' => [Tracy\Bridges\Nette\TracyExtension::class, ['%debugMode%', '%consoleMode%']],
|
||||
'inject' => Nette\DI\Extensions\InjectExtension::class,
|
||||
];
|
||||
|
||||
/** @var string[] of classes which shouldn't be autowired */
|
||||
public $autowireExcludedClasses = [
|
||||
'stdClass',
|
||||
];
|
||||
|
||||
/** @var array */
|
||||
protected $parameters;
|
||||
|
||||
/** @var array */
|
||||
protected $dynamicParameters = [];
|
||||
|
||||
/** @var array */
|
||||
protected $services = [];
|
||||
|
||||
/** @var array [file|array, section] */
|
||||
protected $files = [];
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->parameters = $this->getDefaultParameters();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set parameter %debugMode%.
|
||||
* @param bool|string|array $value
|
||||
* @return static
|
||||
*/
|
||||
public function setDebugMode($value)
|
||||
{
|
||||
if (is_string($value) || is_array($value)) {
|
||||
$value = static::detectDebugMode($value);
|
||||
} elseif (!is_bool($value)) {
|
||||
throw new Nette\InvalidArgumentException(sprintf('Value must be either a string, array, or boolean, %s given.', gettype($value)));
|
||||
}
|
||||
$this->parameters['debugMode'] = $value;
|
||||
$this->parameters['productionMode'] = !$this->parameters['debugMode']; // compatibility
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDebugMode()
|
||||
{
|
||||
return $this->parameters['debugMode'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets path to temporary directory.
|
||||
* @param string $path
|
||||
* @return static
|
||||
*/
|
||||
public function setTempDirectory($path)
|
||||
{
|
||||
$this->parameters['tempDir'] = $path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the default timezone.
|
||||
* @param string $timezone
|
||||
* @return static
|
||||
*/
|
||||
public function setTimeZone($timezone)
|
||||
{
|
||||
date_default_timezone_set($timezone);
|
||||
@ini_set('date.timezone', $timezone); // @ - function may be disabled
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds new parameters. The %params% will be expanded.
|
||||
* @return static
|
||||
*/
|
||||
public function addParameters(array $params)
|
||||
{
|
||||
$this->parameters = DI\Config\Helpers::merge($params, $this->parameters);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds new dynamic parameters.
|
||||
* @return static
|
||||
*/
|
||||
public function addDynamicParameters(array $params)
|
||||
{
|
||||
$this->dynamicParameters = $params + $this->dynamicParameters;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add instances of services.
|
||||
* @return static
|
||||
*/
|
||||
public function addServices(array $services)
|
||||
{
|
||||
$this->services = $services + $this->services;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaultParameters()
|
||||
{
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$last = end($trace);
|
||||
$debugMode = static::detectDebugMode();
|
||||
return [
|
||||
'appDir' => isset($trace[1]['file']) ? dirname($trace[1]['file']) : null,
|
||||
'wwwDir' => isset($last['file']) ? dirname($last['file']) : null,
|
||||
'debugMode' => $debugMode,
|
||||
'productionMode' => !$debugMode,
|
||||
'consoleMode' => PHP_SAPI === 'cli',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $logDirectory
|
||||
* @param string $email
|
||||
* @return void
|
||||
*/
|
||||
public function enableTracy($logDirectory = null, $email = null)
|
||||
{
|
||||
$this->enableDebugger($logDirectory, $email);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alias for enableTracy()
|
||||
* @param string $logDirectory
|
||||
* @param string $email
|
||||
* @return void
|
||||
*/
|
||||
public function enableDebugger($logDirectory = null, $email = null)
|
||||
{
|
||||
Tracy\Debugger::$strictMode = true;
|
||||
Tracy\Debugger::enable(!$this->parameters['debugMode'], $logDirectory, $email);
|
||||
Nette\Bridges\Framework\TracyBridge::initialize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Nette\Loaders\RobotLoader
|
||||
* @throws Nette\NotSupportedException if RobotLoader is not available
|
||||
*/
|
||||
public function createRobotLoader()
|
||||
{
|
||||
if (!class_exists(Nette\Loaders\RobotLoader::class)) {
|
||||
throw new Nette\NotSupportedException('RobotLoader not found, do you have `nette/robot-loader` package installed?');
|
||||
}
|
||||
|
||||
$loader = new Nette\Loaders\RobotLoader;
|
||||
$loader->setTempDirectory($this->getCacheDirectory() . '/Nette.RobotLoader');
|
||||
$loader->setAutoRefresh($this->parameters['debugMode']);
|
||||
return $loader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds configuration file.
|
||||
* @param string|array $file
|
||||
* @return static
|
||||
*/
|
||||
public function addConfig($file)
|
||||
{
|
||||
$section = func_num_args() > 1 ? func_get_arg(1) : null;
|
||||
if ($section !== null) {
|
||||
trigger_error('Sections in config file are deprecated.', E_USER_DEPRECATED);
|
||||
}
|
||||
$this->files[] = [$file, $section === self::AUTO ? ($this->parameters['debugMode'] ? 'development' : 'production') : $section];
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns system DI container.
|
||||
* @return DI\Container
|
||||
*/
|
||||
public function createContainer()
|
||||
{
|
||||
$class = $this->loadContainer();
|
||||
$container = new $class($this->dynamicParameters);
|
||||
foreach ($this->services as $name => $service) {
|
||||
$container->addService($name, $service);
|
||||
}
|
||||
$container->initialize();
|
||||
if (class_exists(Nette\Environment::class)) {
|
||||
Nette\Environment::setContext($container); // back compatibility
|
||||
}
|
||||
return $container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads system DI container class and returns its name.
|
||||
* @return string
|
||||
*/
|
||||
public function loadContainer()
|
||||
{
|
||||
$loader = new DI\ContainerLoader(
|
||||
$this->getCacheDirectory() . '/Nette.Configurator',
|
||||
$this->parameters['debugMode']
|
||||
);
|
||||
$class = $loader->load(
|
||||
[$this, 'generateContainer'],
|
||||
[$this->parameters, array_keys($this->dynamicParameters), $this->files, PHP_VERSION_ID - PHP_RELEASE_VERSION]
|
||||
);
|
||||
return $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
public function generateContainer(DI\Compiler $compiler)
|
||||
{
|
||||
$compiler->addConfig(['parameters' => $this->parameters]);
|
||||
$compiler->setDynamicParameterNames(array_keys($this->dynamicParameters));
|
||||
|
||||
$loader = $this->createLoader();
|
||||
$fileInfo = [];
|
||||
foreach ($this->files as $info) {
|
||||
if (is_scalar($info[0])) {
|
||||
$fileInfo[] = "// source: $info[0] $info[1]";
|
||||
$info[0] = $loader->load($info[0], $info[1]);
|
||||
}
|
||||
$compiler->addConfig($this->fixCompatibility($info[0]));
|
||||
}
|
||||
$compiler->addDependencies($loader->getDependencies());
|
||||
|
||||
$builder = $compiler->getContainerBuilder();
|
||||
$builder->addExcludedClasses($this->autowireExcludedClasses);
|
||||
|
||||
foreach ($this->defaultExtensions as $name => $extension) {
|
||||
list($class, $args) = is_string($extension) ? [$extension, []] : $extension;
|
||||
if (class_exists($class)) {
|
||||
$args = DI\Helpers::expand($args, $this->parameters, true);
|
||||
$compiler->addExtension($name, (new \ReflectionClass($class))->newInstanceArgs($args));
|
||||
}
|
||||
}
|
||||
|
||||
$this->onCompile($this, $compiler);
|
||||
|
||||
$classes = $compiler->compile();
|
||||
return implode("\n", $fileInfo) . "\n\n" . $classes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return DI\Config\Loader
|
||||
*/
|
||||
protected function createLoader()
|
||||
{
|
||||
return new DI\Config\Loader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheDirectory()
|
||||
{
|
||||
if (empty($this->parameters['tempDir'])) {
|
||||
throw new Nette\InvalidStateException('Set path to temporary directory using setTempDirectory().');
|
||||
}
|
||||
$dir = $this->parameters['tempDir'] . '/cache';
|
||||
Nette\Utils\FileSystem::createDir($dir);
|
||||
return $dir;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Back compatibility with < v2.3
|
||||
* @return array
|
||||
*/
|
||||
protected function fixCompatibility($config)
|
||||
{
|
||||
if (isset($config['nette']['security']['frames'])) {
|
||||
$config['nette']['http']['frames'] = $config['nette']['security']['frames'];
|
||||
unset($config['nette']['security']['frames']);
|
||||
}
|
||||
foreach (['application', 'cache', 'database', 'di' => 'container', 'forms', 'http',
|
||||
'latte', 'mail' => 'mailer', 'routing', 'security', 'session', 'tracy' => 'debugger', ] as $new => $old) {
|
||||
if (isset($config['nette'][$old])) {
|
||||
$new = is_int($new) ? $old : $new;
|
||||
if (isset($config[$new])) {
|
||||
throw new Nette\DeprecatedException("You can use (deprecated) section 'nette.$old' or new section '$new', but not both of them.");
|
||||
} else {
|
||||
trigger_error("Configuration section 'nette.$old' is deprecated, use section '$new' (without 'nette')", E_USER_DEPRECATED);
|
||||
}
|
||||
$config[$new] = $config['nette'][$old];
|
||||
unset($config['nette'][$old]);
|
||||
}
|
||||
}
|
||||
if (isset($config['nette']['xhtml'])) {
|
||||
trigger_error("Configuration option 'nette.xhtml' is deprecated, use section 'latte.xhtml' instead.", E_USER_DEPRECATED);
|
||||
$config['latte']['xhtml'] = $config['nette']['xhtml'];
|
||||
unset($config['nette']['xhtml']);
|
||||
}
|
||||
|
||||
if (empty($config['nette'])) {
|
||||
unset($config['nette']);
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
/********************* tools ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Detects debug mode by IP addresses or computer names whitelist detection.
|
||||
* @param string|array $list
|
||||
* @return bool
|
||||
*/
|
||||
public static function detectDebugMode($list = null)
|
||||
{
|
||||
$addr = isset($_SERVER['REMOTE_ADDR'])
|
||||
? $_SERVER['REMOTE_ADDR']
|
||||
: php_uname('n');
|
||||
$secret = isset($_COOKIE[self::COOKIE_SECRET]) && is_string($_COOKIE[self::COOKIE_SECRET])
|
||||
? $_COOKIE[self::COOKIE_SECRET]
|
||||
: null;
|
||||
$list = is_string($list)
|
||||
? preg_split('#[,\s]+#', $list)
|
||||
: (array) $list;
|
||||
if (!isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !isset($_SERVER['HTTP_FORWARDED'])) {
|
||||
$list[] = '127.0.0.1';
|
||||
$list[] = '::1';
|
||||
}
|
||||
return in_array($addr, $list, true) || in_array("$secret@$addr", $list, true);
|
||||
}
|
||||
}
|
74
vendor/nette/bootstrap/src/Bridges/Framework/TracyBridge.php
vendored
Normal file
74
vendor/nette/bootstrap/src/Bridges/Framework/TracyBridge.php
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\Bridges\Framework;
|
||||
|
||||
use Latte;
|
||||
use Nette;
|
||||
use Nette\Framework;
|
||||
use Tracy;
|
||||
use Tracy\BlueScreen;
|
||||
use Tracy\Helpers;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes Tracy.
|
||||
*/
|
||||
class TracyBridge
|
||||
{
|
||||
use Nette\StaticClass;
|
||||
|
||||
public static function initialize()
|
||||
{
|
||||
$blueScreen = Tracy\Debugger::getBlueScreen();
|
||||
|
||||
if (class_exists(Nette\Framework::class)) {
|
||||
$version = Framework::VERSION . (Framework::REVISION ? ' (' . Framework::REVISION . ')' : '');
|
||||
Tracy\Debugger::getBar()->getPanel('Tracy:info')->data['Nette Framework'] = $version;
|
||||
$blueScreen->info[] = "Nette Framework $version";
|
||||
}
|
||||
|
||||
if (class_exists(Tracy\Bridges\Nette\Bridge::class)) {
|
||||
Tracy\Bridges\Nette\Bridge::initialize();
|
||||
return;
|
||||
}
|
||||
|
||||
$blueScreen->addPanel(function ($e) {
|
||||
if ($e instanceof Latte\CompileException) {
|
||||
return [
|
||||
'tab' => 'Template',
|
||||
'panel' => (preg_match('#\n|\?#', $e->sourceName)
|
||||
? ''
|
||||
: '<p>'
|
||||
. (@is_file($e->sourceName) // @ - may trigger error
|
||||
? '<b>File:</b> ' . Helpers::editorLink($e->sourceName, $e->sourceLine)
|
||||
: '<b>' . htmlspecialchars($e->sourceName . ($e->sourceLine ? ':' . $e->sourceLine : '')) . '</b>')
|
||||
. '</p>')
|
||||
. '<pre class=code><div>'
|
||||
. BlueScreen::highlightLine(htmlspecialchars($e->sourceCode, ENT_IGNORE, 'UTF-8'), $e->sourceLine)
|
||||
. '</div></pre>',
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
$blueScreen->addPanel(function ($e) {
|
||||
if (
|
||||
$e instanceof Nette\Neon\Exception
|
||||
&& preg_match('#line (\d+)#', $e->getMessage(), $m)
|
||||
&& ($trace = Helpers::findTrace($e->getTrace(), 'Nette\Neon\Decoder::decode'))
|
||||
) {
|
||||
return [
|
||||
'tab' => 'NEON',
|
||||
'panel' => ($trace2 = Helpers::findTrace($e->getTrace(), 'Nette\DI\Config\Adapters\NeonAdapter::load'))
|
||||
? '<p><b>File:</b> ' . Helpers::editorLink($trace2['args'][0], $m[1]) . '</p>'
|
||||
. BlueScreen::highlightFile($trace2['args'][0], $m[1])
|
||||
: BlueScreen::highlightPhp($trace['args'][0], $m[1]),
|
||||
];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
5
vendor/nette/di/.phpstorm.meta.php
vendored
Normal file
5
vendor/nette/di/.phpstorm.meta.php
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace PHPSTORM_META;
|
||||
|
||||
override(\Nette\DI\Container::getByType(0), map(['' => '@']));
|
41
vendor/nette/di/composer.json
vendored
Normal file
41
vendor/nette/di/composer.json
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "nette/di",
|
||||
"description": "💎 Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.",
|
||||
"keywords": ["nette", "di", "dic", "ioc", "factory", "compiled", "static"],
|
||||
"homepage": "https://nette.org",
|
||||
"license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Grudl",
|
||||
"homepage": "https://davidgrudl.com"
|
||||
},
|
||||
{
|
||||
"name": "Nette Community",
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"ext-tokenizer": "*",
|
||||
"nette/neon": "^2.3.3 || ~3.0.0",
|
||||
"nette/php-generator": "^2.6.1 || ^3.0.0",
|
||||
"nette/utils": "^2.5.0 || ~3.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "^2.0",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2",
|
||||
"nette/bootstrap": "<2.4"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["src/"]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/nette/di/contributing.md
vendored
Normal file
33
vendor/nette/di/contributing.md
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
How to contribute & use the issue tracker
|
||||
=========================================
|
||||
|
||||
Nette welcomes your contributions. There are several ways to help out:
|
||||
|
||||
* Create an issue on GitHub, if you have found a bug
|
||||
* Write test cases for open bug issues
|
||||
* Write fixes for open bug/feature issues, preferably with test cases included
|
||||
* Contribute to the [documentation](https://nette.org/en/writing)
|
||||
|
||||
Issues
|
||||
------
|
||||
|
||||
Please **do not use the issue tracker to ask questions**. We will be happy to help you
|
||||
on [Nette forum](https://forum.nette.org) or chat with us on [Gitter](https://gitter.im/nette/nette).
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more
|
||||
information. Please try to be as detailed as possible in your report.
|
||||
|
||||
**Feature requests** are welcome. But take a moment to find out whether your idea
|
||||
fits with the scope and aims of the project. It's up to *you* to make a strong
|
||||
case to convince the project's developers of the merits of this feature.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
If you'd like to contribute, please take a moment to read [the contributing guide](https://nette.org/en/contributing).
|
||||
|
||||
The best way to propose a feature is to discuss your ideas on [Nette forum](https://forum.nette.org) before implementing them.
|
||||
|
||||
Please do not fix whitespace, format code, or make a purely cosmetic patch.
|
||||
|
||||
Thanks! :heart:
|
60
vendor/nette/di/license.md
vendored
Normal file
60
vendor/nette/di/license.md
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
Licenses
|
||||
========
|
||||
|
||||
Good news! You may use Nette Framework under the terms of either
|
||||
the New BSD License or the GNU General Public License (GPL) version 2 or 3.
|
||||
|
||||
The BSD License is recommended for most projects. It is easy to understand and it
|
||||
places almost no restrictions on what you can do with the framework. If the GPL
|
||||
fits better to your project, you can use the framework under this license.
|
||||
|
||||
You don't have to notify anyone which license you are using. You can freely
|
||||
use Nette Framework in commercial projects as long as the copyright header
|
||||
remains intact.
|
||||
|
||||
Please be advised that the name "Nette Framework" is a protected trademark and its
|
||||
usage has some limitations. So please do not use word "Nette" in the name of your
|
||||
project or top-level domain, and choose a name that stands on its own merits.
|
||||
If your stuff is good, it will not take long to establish a reputation for yourselves.
|
||||
|
||||
|
||||
New BSD License
|
||||
---------------
|
||||
|
||||
Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "Nette Framework" nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as is" and
|
||||
any express or implied warranties, including, but not limited to, the implied
|
||||
warranties of merchantability and fitness for a particular purpose are
|
||||
disclaimed. In no event shall the copyright owner or contributors be liable for
|
||||
any direct, indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or services;
|
||||
loss of use, data, or profits; or business interruption) however caused and on
|
||||
any theory of liability, whether in contract, strict liability, or tort
|
||||
(including negligence or otherwise) arising in any way out of the use of this
|
||||
software, even if advised of the possibility of such damage.
|
||||
|
||||
|
||||
GNU General Public License
|
||||
--------------------------
|
||||
|
||||
GPL licenses are very very long, so instead of including them here we offer
|
||||
you URLs with full text:
|
||||
|
||||
- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
|
||||
- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
|
330
vendor/nette/di/readme.md
vendored
Normal file
330
vendor/nette/di/readme.md
vendored
Normal file
|
@ -0,0 +1,330 @@
|
|||
Nette Dependency Injection (DI)
|
||||
===============================
|
||||
|
||||
[](https://packagist.org/packages/nette/di)
|
||||
[](https://travis-ci.org/nette/di)
|
||||
[](https://coveralls.io/github/nette/di?branch=master)
|
||||
[](https://github.com/nette/di/releases)
|
||||
[](https://github.com/nette/di/blob/master/license.md)
|
||||
|
||||
Purpose of the Dependecy Injection (DI) is to free classes from the responsibility for obtaining objects that they need for its operation (these objects are called **services**). To pass them these services on their instantiation instead.
|
||||
|
||||
Nette DI is one of the most interesting part of framework. It is compiled DI container, extremely fast and easy to configure.
|
||||
|
||||
Let's have an application for sending newsletters. The code is maximally simplified and is available on the [GitHub](https://github.com/dg/di-example).
|
||||
|
||||
We have the object representing email:
|
||||
|
||||
```php
|
||||
class Mail
|
||||
{
|
||||
public $subject;
|
||||
public $message;
|
||||
}
|
||||
```
|
||||
|
||||
An object which can send emails:
|
||||
|
||||
```php
|
||||
interface Mailer
|
||||
{
|
||||
function send(Mail $mail, $to);
|
||||
}
|
||||
```
|
||||
|
||||
A support for logging:
|
||||
|
||||
```php
|
||||
interface Logger
|
||||
{
|
||||
function log($message);
|
||||
}
|
||||
```
|
||||
|
||||
And finally, a class that provides sending newsletters:
|
||||
|
||||
```php
|
||||
class NewsletterManager
|
||||
{
|
||||
private $mailer;
|
||||
private $logger;
|
||||
|
||||
function __construct(Mailer $mailer, Logger $logger)
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
function distribute(array $recipients)
|
||||
{
|
||||
$mail = new Mail;
|
||||
...
|
||||
foreach ($recipients as $recipient) {
|
||||
$this->mailer->send($mail, $recipient);
|
||||
}
|
||||
$this->logger->log(...);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The code respects Dependency Injection, ie. **each object uses only variables which we had passed into it.**
|
||||
|
||||
Also, we have a ability to implement own `Logger` or `Mailer`, like this:
|
||||
|
||||
```php
|
||||
class SendMailMailer implements Mailer
|
||||
{
|
||||
function send(Mail $mail, $to)
|
||||
{
|
||||
mail($to, $mail->subject, $mail->message);
|
||||
}
|
||||
}
|
||||
|
||||
class FileLogger implements Logger
|
||||
{
|
||||
private $file;
|
||||
|
||||
function __construct($file)
|
||||
{
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
function log($message)
|
||||
{
|
||||
file_put_contents($this->file, $message . "\n", FILE_APPEND);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**DI container is the supreme architect** which can create individual objects (in the terminology DI called services) and assemble and configure them exactly according to our needs.
|
||||
|
||||
Container for our application might look like this:
|
||||
|
||||
```php
|
||||
class Container
|
||||
{
|
||||
private $logger;
|
||||
private $mailer;
|
||||
|
||||
function getLogger()
|
||||
{
|
||||
if (!$this->logger) {
|
||||
$this->logger = new FileLogger('log.txt');
|
||||
}
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
function getMailer()
|
||||
{
|
||||
if (!$this->mailer) {
|
||||
$this->mailer = new SendMailMailer;
|
||||
}
|
||||
return $this->mailer;
|
||||
}
|
||||
|
||||
function createNewsletterManager()
|
||||
{
|
||||
return new NewsletterManager($this->getMailer(), $this->getLogger());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The implementation looks like this because:
|
||||
- the individual services are created only on demand (lazy loading)
|
||||
- doubly called `createNewsletterManager` will use the same logger and mailer instances
|
||||
|
||||
Let's instantiate `Container`, let it create manager and we can start spamming users with newsletters :-)
|
||||
|
||||
```php
|
||||
$container = new Container;
|
||||
$manager = $container->createNewsletterManager();
|
||||
$manager->distribute(...);
|
||||
```
|
||||
|
||||
Significant to Dependency Injection is that no class depends on the container. Thus it can be easily replaced with another one. For example with the container generated by Nette DI.
|
||||
|
||||
Nette DI
|
||||
----------
|
||||
|
||||
Nette DI is the generator of containers. We instruct it (usually) with configuration files. This is configuration that leads to generate nearly the same class as the class `Container` above:
|
||||
|
||||
```neon
|
||||
services:
|
||||
- FileLogger( log.txt )
|
||||
- SendMailMailer
|
||||
- NewsletterManager
|
||||
```
|
||||
|
||||
The big advantage is the shortness of configuration.
|
||||
|
||||
Nette DI actually generates PHP code of container. Therefore it is extremely fast. Developer can see the code, so he knows exactly what it is doing. He can even trace it.
|
||||
|
||||
Usage of Nette DI is very easy. In first, install it using Composer:
|
||||
|
||||
```
|
||||
composer require nette/di
|
||||
```
|
||||
|
||||
Save the (above) configuration to the file `config.neon` and let's create a container:
|
||||
|
||||
```php
|
||||
$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp');
|
||||
$class = $loader->load(function($compiler) {
|
||||
$compiler->loadConfig(__DIR__ . '/config.neon');
|
||||
});
|
||||
$container = new $class;
|
||||
```
|
||||
|
||||
and then use container to create object `NewsletterManager` and we can send e-mails:
|
||||
|
||||
```php
|
||||
$manager = $container->getByType(NewsletterManager::class);
|
||||
$manager->distribute(['john@example.com', ...]);
|
||||
```
|
||||
|
||||
The container will be generated only once and the code is stored in cache (in directory `__DIR__ . '/temp'`). Therefore the loading of configuration file is placed in the closure in `$loader->load()`, so it is called only once.
|
||||
|
||||
During development it is useful to activate auto-refresh mode which automatically regenerate the container when any class or configuration file is changed. Just in the constructor `ContainerLoader` append `true` as the second argument:
|
||||
|
||||
```php
|
||||
$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp', true);
|
||||
```
|
||||
|
||||
|
||||
Services
|
||||
--------
|
||||
|
||||
Services are registered in the DI container and their dependencies are automatically passed.
|
||||
|
||||
```neon
|
||||
services:
|
||||
manager: NewsletterManager
|
||||
```
|
||||
|
||||
All dependencies declared in the constructor of this service will be automatically passed. Constructor passing is the preferred way of dependency injection for services.
|
||||
|
||||
If we want to pass dependencies by the setter, we can add the `setup` section to the service definition:
|
||||
|
||||
```neon
|
||||
services:
|
||||
manager:
|
||||
factory: NewsletterManager
|
||||
setup:
|
||||
- setAnotherService
|
||||
```
|
||||
|
||||
Class of the service:
|
||||
|
||||
```php
|
||||
class NewsletterManager
|
||||
{
|
||||
private $anotherService;
|
||||
|
||||
public function setAnotherService(AnotherService $service)
|
||||
{
|
||||
$this->anotherService = $service;
|
||||
}
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
We can also add the `inject: yes` directive. This directive will enable automatic call of `inject*` methods and passing dependencies to public variables with `@inject` annotations:
|
||||
|
||||
```neon
|
||||
services:
|
||||
foo:
|
||||
factory: FooClass
|
||||
inject: yes
|
||||
```
|
||||
|
||||
Dependency `Service1` will be passed by calling the `inject*` method, dependency `Service2` will be assigned to the `$service2` variable:
|
||||
|
||||
```php
|
||||
class FooClass
|
||||
{
|
||||
private $service1;
|
||||
|
||||
// 1) inject* method:
|
||||
|
||||
public function injectService1(Service1 $service)
|
||||
{
|
||||
$this->service1 = $service1;
|
||||
}
|
||||
|
||||
// 2) Assign to the variable with the @inject annotation:
|
||||
|
||||
/** @inject @var Service2 */
|
||||
public $service2;
|
||||
}
|
||||
```
|
||||
|
||||
However, this method is not ideal, because the variable must be declared as public and there is no way how you can ensure that the passed object will be of the given type. We also lose the ability to handle the assigned dependency in our code and we violate the principles of encapsulation.
|
||||
|
||||
|
||||
|
||||
Factories
|
||||
---------
|
||||
|
||||
We can use factories generated from an interface. The interface must declare the returning type in the `@return` annotation of the method. Nette will generate a proper implementation of the interface.
|
||||
|
||||
The interface must have exactly one method named `create`. Our factory interface could be declared in the following way:
|
||||
|
||||
```php
|
||||
interface IBarFactory
|
||||
{
|
||||
/**
|
||||
* @return Bar
|
||||
*/
|
||||
public function create();
|
||||
}
|
||||
```
|
||||
|
||||
The `create` method will instantiate an `Bar` with the following definition:
|
||||
|
||||
```php
|
||||
class Bar
|
||||
{
|
||||
private $logger;
|
||||
|
||||
public function __construct(Logger $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The factory will be registered in the `config.neon` file:
|
||||
|
||||
```neon
|
||||
services:
|
||||
- IBarFactory
|
||||
```
|
||||
|
||||
Nette will check if the declared service is an interface. If yes, it will also generate the corresponding implementation of the factory. The definition can be also written in a more verbose form:
|
||||
|
||||
```neon
|
||||
services:
|
||||
barFactory:
|
||||
implement: IBarFactory
|
||||
```
|
||||
|
||||
This full definition allows us to declare additional configuration of the object using the `arguments` and `setup` sections, similarly as for all other services.
|
||||
|
||||
In our code, we only have to obtain the factory instance and call the `create` method:
|
||||
|
||||
```php
|
||||
class Foo
|
||||
{
|
||||
private $barFactory;
|
||||
|
||||
function __construct(IBarFactory $barFactory)
|
||||
{
|
||||
$this->barFactory = $barFactory;
|
||||
}
|
||||
|
||||
function bar()
|
||||
{
|
||||
$bar = $this->barFactory->create();
|
||||
}
|
||||
}
|
||||
```
|
85
vendor/nette/di/src/Bridges/DITracy/ContainerPanel.php
vendored
Normal file
85
vendor/nette/di/src/Bridges/DITracy/ContainerPanel.php
vendored
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\Bridges\DITracy;
|
||||
|
||||
use Nette;
|
||||
use Nette\DI\Container;
|
||||
use Tracy;
|
||||
|
||||
|
||||
/**
|
||||
* Dependency injection container panel for Debugger Bar.
|
||||
*/
|
||||
class ContainerPanel implements Tracy\IBarPanel
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @var int */
|
||||
public static $compilationTime;
|
||||
|
||||
/** @var Nette\DI\Container */
|
||||
private $container;
|
||||
|
||||
/** @var int|null */
|
||||
private $elapsedTime;
|
||||
|
||||
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->elapsedTime = self::$compilationTime ? microtime(true) - self::$compilationTime : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders tab.
|
||||
* @return string
|
||||
*/
|
||||
public function getTab()
|
||||
{
|
||||
ob_start(function () {});
|
||||
$elapsedTime = $this->elapsedTime;
|
||||
require __DIR__ . '/templates/ContainerPanel.tab.phtml';
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders panel.
|
||||
* @return string
|
||||
*/
|
||||
public function getPanel()
|
||||
{
|
||||
$container = $this->container;
|
||||
$registry = $this->getContainerProperty('registry');
|
||||
$file = (new \ReflectionClass($container))->getFileName();
|
||||
$tags = [];
|
||||
$meta = $this->getContainerProperty('meta');
|
||||
$services = $meta[Container::SERVICES];
|
||||
ksort($services);
|
||||
if (isset($meta[Container::TAGS])) {
|
||||
foreach ($meta[Container::TAGS] as $tag => $tmp) {
|
||||
foreach ($tmp as $service => $val) {
|
||||
$tags[$service][$tag] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ob_start(function () {});
|
||||
require __DIR__ . '/templates/ContainerPanel.panel.phtml';
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
|
||||
private function getContainerProperty($name)
|
||||
{
|
||||
$prop = (new \ReflectionClass(Nette\DI\Container::class))->getProperty($name);
|
||||
$prop->setAccessible(true);
|
||||
return $prop->getValue($this->container);
|
||||
}
|
||||
}
|
70
vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.panel.phtml
vendored
Normal file
70
vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.panel.phtml
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace Nette\Bridges\DITracy;
|
||||
|
||||
use Nette;
|
||||
use Tracy\Dumper;
|
||||
use Tracy\Helpers;
|
||||
|
||||
?>
|
||||
<style class="tracy-debug">
|
||||
#tracy-debug .nette-ContainerPanel table {
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#tracy-debug .nette-ContainerPanel .created {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#tracy-debug .nette-ContainerPanel .yes {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1><?= get_class($container) ?></h1>
|
||||
|
||||
<div class="tracy-inner nette-ContainerPanel">
|
||||
<div class="tracy-inner-container">
|
||||
<h2>Services</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Autowired</th>
|
||||
<th>Service</th>
|
||||
<th>Tags</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($services as $name => $type): ?>
|
||||
<?php $autowired = !empty($meta[Nette\DI\Container::TYPES][$type][true]) && in_array($name, $meta[Nette\DI\Container::TYPES][$type][true], true) ?>
|
||||
<tr>
|
||||
<td class="<?= isset($registry[$name]) ? 'created' : '' ?>"><?= htmlspecialchars($name) ?></td>
|
||||
<td class="<?= $autowired ? 'yes' : '' ?>"><?= $autowired ? 'yes' : 'no' ?></td>
|
||||
<td>
|
||||
<?php if (isset($registry[$name]) && !$registry[$name] instanceof Nette\DI\Container): ?>
|
||||
<?= Dumper::toHtml($registry[$name], [Dumper::COLLAPSE => true, Dumper::LIVE => true]); ?>
|
||||
<?php elseif (isset($registry[$name])): ?>
|
||||
<code><?= get_class($registry[$name]) ?></code>
|
||||
<?php elseif (is_string($type)): ?>
|
||||
<code><?= htmlspecialchars($type) ?></code>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
<td><?php if (isset($tags[$name])) { echo Dumper::toHtml($tags[$name], [Dumper::COLLAPSE => true]); } ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Parameters</h2>
|
||||
|
||||
<div class="nette-ContainerPanel-parameters">
|
||||
<?= Dumper::toHtml($container->parameters); ?>
|
||||
</div>
|
||||
|
||||
<p>Source: <?= Helpers::editorLink($file) ?></p>
|
||||
</div>
|
||||
</div>
|
10
vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.tab.phtml
vendored
Normal file
10
vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.tab.phtml
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Nette\Bridges\DITracy;
|
||||
|
||||
|
||||
?>
|
||||
<span title="Dependency Injection Container">
|
||||
<svg viewBox="0 0 2048 2048"><path fill="#ae7c21" d="m1675 690.55v-125c0-36-4-60-13-71-9-12-26-18-52-18s-43 6-52 17c-8 11-12 36-12 72v910.62c0 37 4 61 12 72 9 11 26 17 52 17s44-6 52-17c9-12 13-36 13-72v-207h243v165c0 86-4 148-12 187-8 38-21 70-39 96-20 28-45 48-77 59-31 11-87 16-170 16-96 0-161-5-196-16-34-11-63-31-86-59-21-26-36-59-45-97-9-39-14-101-14-186v-826.62c0-85 4-147 13-185s25-71 46-97c23-29 54-49 92-60s102-17 189-17c75 0 130 6 164 17s61 30 81 59c19 26 33 59 41 99 8 39 12 101 12 185v84zm-524 1086.6h-254v-1514.6h254zm-1025 0v-1514.6h316c127 0 212 27 257 81 44 53 66 159 66 316v721.62c0 157-22 263-66 317-44 53-130 80-257 80zm388-314v-884.62c0-35-4-58-13-70-9-11-26-17-53-17h-66v1058.6h66c26 0 44-6 53-17 9-12 14-35 14-70z"/>
|
||||
</svg><span class="tracy-label"><?= $elapsedTime ? sprintf('%0.1f ms', $elapsedTime * 1000) : '' ?></span>
|
||||
</span>
|
507
vendor/nette/di/src/DI/Compiler.php
vendored
Normal file
507
vendor/nette/di/src/DI/Compiler.php
vendored
Normal file
|
@ -0,0 +1,507 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
use Nette\Utils\Validators;
|
||||
|
||||
|
||||
/**
|
||||
* DI container compiler.
|
||||
*/
|
||||
class Compiler
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @var CompilerExtension[] */
|
||||
private $extensions = [];
|
||||
|
||||
/** @var ContainerBuilder */
|
||||
private $builder;
|
||||
|
||||
/** @var array */
|
||||
private $config = [];
|
||||
|
||||
/** @var DependencyChecker */
|
||||
private $dependencies;
|
||||
|
||||
/** @var string */
|
||||
private $className = 'Container';
|
||||
|
||||
/** @var string[] */
|
||||
private $dynamicParams = [];
|
||||
|
||||
/** @var array reserved section names */
|
||||
private static $reserved = ['services' => 1, 'parameters' => 1];
|
||||
|
||||
|
||||
public function __construct(ContainerBuilder $builder = null)
|
||||
{
|
||||
$this->builder = $builder ?: new ContainerBuilder;
|
||||
$this->dependencies = new DependencyChecker;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add custom configurator extension.
|
||||
* @param string|null
|
||||
* @return static
|
||||
*/
|
||||
public function addExtension($name, CompilerExtension $extension)
|
||||
{
|
||||
if ($name === null) {
|
||||
$name = '_' . count($this->extensions);
|
||||
} elseif (isset($this->extensions[$name]) || isset(self::$reserved[$name])) {
|
||||
throw new Nette\InvalidArgumentException("Name '$name' is already used or reserved.");
|
||||
}
|
||||
$this->extensions[$name] = $extension->setCompiler($this, $name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getExtensions($type = null)
|
||||
{
|
||||
return $type
|
||||
? array_filter($this->extensions, function ($item) use ($type) { return $item instanceof $type; })
|
||||
: $this->extensions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return ContainerBuilder
|
||||
*/
|
||||
public function getContainerBuilder()
|
||||
{
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setClassName($className)
|
||||
{
|
||||
$this->className = $className;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds new configuration.
|
||||
* @return static
|
||||
*/
|
||||
public function addConfig(array $config)
|
||||
{
|
||||
$this->config = Config\Helpers::merge($config, $this->config);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds new configuration from file.
|
||||
* @return static
|
||||
*/
|
||||
public function loadConfig($file)
|
||||
{
|
||||
$loader = new Config\Loader;
|
||||
$this->addConfig($loader->load($file));
|
||||
$this->dependencies->add($loader->getDependencies());
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns configuration.
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the names of dynamic parameters.
|
||||
* @return static
|
||||
*/
|
||||
public function setDynamicParameterNames(array $names)
|
||||
{
|
||||
$this->dynamicParams = $names;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds dependencies to the list.
|
||||
* @param array of ReflectionClass|\ReflectionFunctionAbstract|string
|
||||
* @return static
|
||||
*/
|
||||
public function addDependencies(array $deps)
|
||||
{
|
||||
$this->dependencies->add(array_filter($deps));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exports dependencies.
|
||||
* @return array
|
||||
*/
|
||||
public function exportDependencies()
|
||||
{
|
||||
return $this->dependencies->export();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function compile()
|
||||
{
|
||||
if (func_num_args()) {
|
||||
trigger_error(__METHOD__ . ' arguments are deprecated, use Compiler::addConfig() and Compiler::setClassName().', E_USER_DEPRECATED);
|
||||
$this->config = func_get_arg(0) ?: $this->config;
|
||||
$this->className = @func_get_arg(1) ?: $this->className;
|
||||
}
|
||||
$this->processParameters();
|
||||
$this->processExtensions();
|
||||
$this->processServices();
|
||||
$classes = $this->generateCode();
|
||||
return implode("\n\n\n", $classes);
|
||||
}
|
||||
|
||||
|
||||
/** @internal */
|
||||
public function processParameters()
|
||||
{
|
||||
$params = isset($this->config['parameters']) ? $this->config['parameters'] : [];
|
||||
foreach ($this->dynamicParams as $key) {
|
||||
$params[$key] = array_key_exists($key, $params)
|
||||
? ContainerBuilder::literal('isset($this->parameters[?]) \? $this->parameters[?] : ?', [$key, $key, $params[$key]])
|
||||
: ContainerBuilder::literal('$this->parameters[?]', [$key]);
|
||||
}
|
||||
$this->builder->parameters = Helpers::expand($params, $params, true);
|
||||
}
|
||||
|
||||
|
||||
/** @internal */
|
||||
public function processExtensions()
|
||||
{
|
||||
$this->config = Helpers::expand(array_diff_key($this->config, self::$reserved), $this->builder->parameters)
|
||||
+ array_intersect_key($this->config, self::$reserved);
|
||||
|
||||
foreach ($first = $this->getExtensions(Extensions\ExtensionsExtension::class) as $name => $extension) {
|
||||
$extension->setConfig(isset($this->config[$name]) ? $this->config[$name] : []);
|
||||
$extension->loadConfiguration();
|
||||
}
|
||||
|
||||
$last = $this->getExtensions(Extensions\InjectExtension::class);
|
||||
$this->extensions = array_merge(array_diff_key($this->extensions, $last), $last);
|
||||
|
||||
$extensions = array_diff_key($this->extensions, $first);
|
||||
foreach (array_intersect_key($extensions, $this->config) as $name => $extension) {
|
||||
$extension->setConfig($this->config[$name] ?: []);
|
||||
}
|
||||
|
||||
foreach ($extensions as $extension) {
|
||||
$extension->loadConfiguration();
|
||||
}
|
||||
|
||||
if ($extra = array_diff_key($this->extensions, $extensions, $first)) {
|
||||
$extra = implode("', '", array_keys($extra));
|
||||
throw new Nette\DeprecatedException("Extensions '$extra' were added while container was being compiled.");
|
||||
|
||||
} elseif ($extra = key(array_diff_key($this->config, self::$reserved, $this->extensions))) {
|
||||
$hint = Nette\Utils\ObjectHelpers::getSuggestion(array_keys(self::$reserved + $this->extensions), $extra);
|
||||
throw new Nette\InvalidStateException(
|
||||
"Found section '$extra' in configuration, but corresponding extension is missing"
|
||||
. ($hint ? ", did you mean '$hint'?" : '.')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @internal */
|
||||
public function processServices()
|
||||
{
|
||||
if (isset($this->config['services'])) {
|
||||
self::loadDefinitions($this->builder, $this->config['services']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @internal */
|
||||
public function generateCode()
|
||||
{
|
||||
if (func_num_args()) {
|
||||
trigger_error(__METHOD__ . ' arguments are deprecated, use Compiler::setClassName().', E_USER_DEPRECATED);
|
||||
$this->className = func_get_arg(0) ?: $this->className;
|
||||
}
|
||||
|
||||
$this->builder->prepareClassList();
|
||||
|
||||
foreach ($this->extensions as $extension) {
|
||||
$extension->beforeCompile();
|
||||
$this->dependencies->add([(new \ReflectionClass($extension))->getFileName()]);
|
||||
}
|
||||
|
||||
$generator = new PhpGenerator($this->builder);
|
||||
$classes = $generator->generate($this->className);
|
||||
$classes[0]->addMethod('initialize');
|
||||
$this->dependencies->add($this->builder->getDependencies());
|
||||
|
||||
foreach ($this->extensions as $extension) {
|
||||
$extension->afterCompile($classes[0]);
|
||||
}
|
||||
return $classes;
|
||||
}
|
||||
|
||||
|
||||
/********************* tools ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Adds service definitions from configuration.
|
||||
* @return void
|
||||
*/
|
||||
public static function loadDefinitions(ContainerBuilder $builder, array $services, $namespace = null)
|
||||
{
|
||||
$depths = [];
|
||||
$sort = false;
|
||||
foreach ($services as $name => $def) {
|
||||
$path = [];
|
||||
while (Config\Helpers::isInheriting($def)) {
|
||||
$sort = true;
|
||||
$path[] = $def;
|
||||
$def = isset($services[$def[Config\Helpers::EXTENDS_KEY]]) ? $services[$def[Config\Helpers::EXTENDS_KEY]] : [];
|
||||
if (in_array($def, $path, true)) {
|
||||
throw new ServiceCreationException("Circular reference detected for service '$name'.");
|
||||
}
|
||||
}
|
||||
$depths[$name] = count($path) + preg_match('#^@[\w\\\\]+\z#', $name);
|
||||
}
|
||||
if ($sort) {
|
||||
@array_multisort($depths, $services); // @ may trigger E_NOTICE: Object of class Nette\DI\Statement could not be converted to int
|
||||
}
|
||||
|
||||
foreach ($services as $name => $def) {
|
||||
if (is_int($name)) {
|
||||
$counter = 1;
|
||||
do {
|
||||
$name = (string) $counter++;
|
||||
} while ($builder->hasDefinition($name));
|
||||
} elseif (preg_match('#^@[\w\\\\]+\z#', $name)) {
|
||||
$name = $builder->getByType(substr($name, 1), true);
|
||||
} elseif ($namespace) {
|
||||
$name = $namespace . '.' . $name;
|
||||
}
|
||||
|
||||
if ($def === false) {
|
||||
$builder->removeDefinition($name);
|
||||
continue;
|
||||
}
|
||||
if ($namespace) {
|
||||
$def = Helpers::prefixServiceName($def, $namespace);
|
||||
}
|
||||
|
||||
$params = $builder->parameters;
|
||||
if (is_array($def) && isset($def['parameters'])) {
|
||||
foreach ((array) $def['parameters'] as $k => $v) {
|
||||
$v = explode(' ', is_int($k) ? $v : $k);
|
||||
$params[end($v)] = $builder::literal('$' . end($v));
|
||||
}
|
||||
}
|
||||
$def = Helpers::expand($def, $params);
|
||||
|
||||
if (is_array($def) && !empty($def['alteration']) && !$builder->hasDefinition($name)) {
|
||||
throw new ServiceCreationException("Service '$name': missing original definition for alteration.");
|
||||
}
|
||||
|
||||
if (($parent = Config\Helpers::takeParent($def)) && $parent !== $name) {
|
||||
if ($parent !== Config\Helpers::OVERWRITE) {
|
||||
trigger_error("Section inheritance $name < $parent is deprecated.", E_USER_DEPRECATED);
|
||||
}
|
||||
$builder->removeDefinition($name);
|
||||
$definition = $builder->addDefinition(
|
||||
$name,
|
||||
$parent === Config\Helpers::OVERWRITE ? null : clone $builder->getDefinition($parent)
|
||||
);
|
||||
} elseif ($builder->hasDefinition($name)) {
|
||||
$definition = $builder->getDefinition($name);
|
||||
} else {
|
||||
$definition = $builder->addDefinition($name);
|
||||
}
|
||||
|
||||
try {
|
||||
static::loadDefinition($definition, $def);
|
||||
} catch (\Exception $e) {
|
||||
throw new ServiceCreationException("Service '$name': " . $e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses single service definition from configuration.
|
||||
* @return void
|
||||
*/
|
||||
public static function loadDefinition(ServiceDefinition $definition, $config)
|
||||
{
|
||||
if ($config === null) {
|
||||
return;
|
||||
|
||||
} elseif (is_string($config) && interface_exists($config)) {
|
||||
$config = ['class' => null, 'implement' => $config];
|
||||
|
||||
} elseif ($config instanceof Statement && is_string($config->getEntity()) && interface_exists($config->getEntity())) {
|
||||
$config = ['class' => null, 'implement' => $config->getEntity(), 'factory' => array_shift($config->arguments)];
|
||||
|
||||
} elseif (!is_array($config) || isset($config[0], $config[1])) {
|
||||
$config = ['class' => null, 'factory' => $config];
|
||||
}
|
||||
|
||||
if (array_key_exists('create', $config)) {
|
||||
trigger_error("Key 'create' is deprecated, use 'factory' or 'type' in configuration.", E_USER_DEPRECATED);
|
||||
$config['factory'] = $config['create'];
|
||||
unset($config['create']);
|
||||
}
|
||||
|
||||
$known = ['type', 'class', 'factory', 'arguments', 'setup', 'autowired', 'dynamic', 'imported', 'inject', 'parameters', 'implement', 'run', 'tags', 'alteration'];
|
||||
if ($error = array_diff(array_keys($config), $known)) {
|
||||
$hints = array_filter(array_map(function ($error) use ($known) {
|
||||
return Nette\Utils\ObjectHelpers::getSuggestion($known, $error);
|
||||
}, $error));
|
||||
$hint = $hints ? ", did you mean '" . implode("', '", $hints) . "'?" : '.';
|
||||
throw new Nette\InvalidStateException(sprintf("Unknown key '%s' in definition of service$hint", implode("', '", $error)));
|
||||
}
|
||||
|
||||
$config = Helpers::filterArguments($config);
|
||||
|
||||
if (array_key_exists('class', $config) || array_key_exists('factory', $config)) {
|
||||
$definition->setType(null);
|
||||
$definition->setFactory(null);
|
||||
}
|
||||
|
||||
if (array_key_exists('type', $config)) {
|
||||
Validators::assertField($config, 'type', 'string|null');
|
||||
$definition->setType($config['type']);
|
||||
if (array_key_exists('class', $config)) {
|
||||
throw new Nette\InvalidStateException("Unexpected 'class' when 'type' is used.");
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('class', $config)) {
|
||||
Validators::assertField($config, 'class', 'string|Nette\DI\Statement|null');
|
||||
if (!$config['class'] instanceof Statement) {
|
||||
$definition->setType($config['class']);
|
||||
}
|
||||
$definition->setFactory($config['class']);
|
||||
}
|
||||
|
||||
if (array_key_exists('factory', $config)) {
|
||||
Validators::assertField($config, 'factory', 'callable|Nette\DI\Statement|null');
|
||||
$definition->setFactory($config['factory']);
|
||||
}
|
||||
|
||||
if (array_key_exists('arguments', $config)) {
|
||||
Validators::assertField($config, 'arguments', 'array');
|
||||
$arguments = $config['arguments'];
|
||||
if (!Config\Helpers::takeParent($arguments) && !Nette\Utils\Arrays::isList($arguments) && $definition->getFactory()) {
|
||||
$arguments += $definition->getFactory()->arguments;
|
||||
}
|
||||
$definition->setArguments($arguments);
|
||||
}
|
||||
|
||||
if (isset($config['setup'])) {
|
||||
if (Config\Helpers::takeParent($config['setup'])) {
|
||||
$definition->setSetup([]);
|
||||
}
|
||||
Validators::assertField($config, 'setup', 'list');
|
||||
foreach ($config['setup'] as $id => $setup) {
|
||||
Validators::assert($setup, 'callable|Nette\DI\Statement|array:1', "setup item #$id");
|
||||
if (is_array($setup)) {
|
||||
$setup = new Statement(key($setup), array_values($setup));
|
||||
}
|
||||
$definition->addSetup($setup);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($config['parameters'])) {
|
||||
Validators::assertField($config, 'parameters', 'array');
|
||||
$definition->setParameters($config['parameters']);
|
||||
}
|
||||
|
||||
if (isset($config['implement'])) {
|
||||
Validators::assertField($config, 'implement', 'string');
|
||||
$definition->setImplement($config['implement']);
|
||||
$definition->setAutowired(true);
|
||||
}
|
||||
|
||||
if (isset($config['autowired'])) {
|
||||
Validators::assertField($config, 'autowired', 'bool|string|array');
|
||||
$definition->setAutowired($config['autowired']);
|
||||
}
|
||||
|
||||
if (isset($config['imported'])) {
|
||||
$config['dynamic'] = $config['imported'];
|
||||
}
|
||||
|
||||
if (isset($config['dynamic'])) {
|
||||
Validators::assertField($config, 'dynamic', 'bool');
|
||||
$definition->setDynamic($config['dynamic']);
|
||||
}
|
||||
|
||||
if (isset($config['inject'])) {
|
||||
Validators::assertField($config, 'inject', 'bool');
|
||||
$definition->addTag(Extensions\InjectExtension::TAG_INJECT, $config['inject']);
|
||||
}
|
||||
|
||||
if (isset($config['run'])) {
|
||||
trigger_error("Option 'run' is deprecated, use 'run' as tag.", E_USER_DEPRECATED);
|
||||
$config['tags']['run'] = (bool) $config['run'];
|
||||
}
|
||||
|
||||
if (isset($config['tags'])) {
|
||||
Validators::assertField($config, 'tags', 'array');
|
||||
if (Config\Helpers::takeParent($config['tags'])) {
|
||||
$definition->setTags([]);
|
||||
}
|
||||
foreach ($config['tags'] as $tag => $attrs) {
|
||||
if (is_int($tag) && is_string($attrs)) {
|
||||
$definition->addTag($attrs);
|
||||
} else {
|
||||
$definition->addTag($tag, $attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public static function filterArguments(array $args)
|
||||
{
|
||||
return Helpers::filterArguments($args);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public static function parseServices(ContainerBuilder $builder, array $config, $namespace = null)
|
||||
{
|
||||
self::loadDefinitions($builder, isset($config['services']) ? $config['services'] : [], $namespace);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public static function parseService(ServiceDefinition $definition, $config)
|
||||
{
|
||||
self::loadDefinition($definition, $config);
|
||||
}
|
||||
}
|
143
vendor/nette/di/src/DI/CompilerExtension.php
vendored
Normal file
143
vendor/nette/di/src/DI/CompilerExtension.php
vendored
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Configurator compiling extension.
|
||||
*/
|
||||
abstract class CompilerExtension
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @var Compiler */
|
||||
protected $compiler;
|
||||
|
||||
/** @var string */
|
||||
protected $name;
|
||||
|
||||
/** @var array */
|
||||
protected $config = [];
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setCompiler(Compiler $compiler, $name)
|
||||
{
|
||||
$this->compiler = $compiler;
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setConfig(array $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns extension configuration.
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
if (func_num_args()) { // deprecated
|
||||
return Config\Helpers::merge($this->config, $this->getContainerBuilder()->expand(func_get_arg(0)));
|
||||
}
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether $config contains only $expected items and returns combined array.
|
||||
* @return array
|
||||
* @throws Nette\InvalidStateException
|
||||
*/
|
||||
public function validateConfig(array $expected, array $config = null, $name = null)
|
||||
{
|
||||
if (func_num_args() === 1) {
|
||||
return $this->config = $this->validateConfig($expected, $this->config);
|
||||
}
|
||||
if ($extra = array_diff_key((array) $config, $expected)) {
|
||||
$name = $name ?: $this->name;
|
||||
$hint = Nette\Utils\ObjectHelpers::getSuggestion(array_keys($expected), key($extra));
|
||||
$extra = $hint ? key($extra) : implode("', '{$name} › ", array_keys($extra));
|
||||
throw new Nette\InvalidStateException("Unknown configuration option '{$name} › {$extra}'" . ($hint ? ", did you mean '{$name} › {$hint}'?" : '.'));
|
||||
}
|
||||
return Config\Helpers::merge($config, $expected);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return ContainerBuilder
|
||||
*/
|
||||
public function getContainerBuilder()
|
||||
{
|
||||
return $this->compiler->getContainerBuilder();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads configuration from file.
|
||||
* @param string file name
|
||||
* @return array
|
||||
*/
|
||||
public function loadFromFile($file)
|
||||
{
|
||||
$loader = new Config\Loader;
|
||||
$res = $loader->load($file);
|
||||
$this->compiler->addDependencies($loader->getDependencies());
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepend extension name to identifier or service name.
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function prefix($id)
|
||||
{
|
||||
return substr_replace($id, $this->name . '.', substr($id, 0, 1) === '@' ? 1 : 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes configuration data. Intended to be overridden by descendant.
|
||||
* @return void
|
||||
*/
|
||||
public function loadConfiguration()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adjusts DI container before is compiled to PHP class. Intended to be overridden by descendant.
|
||||
* @return void
|
||||
*/
|
||||
public function beforeCompile()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adjusts DI container compiled to PHP class. Intended to be overridden by descendant.
|
||||
* @return void
|
||||
*/
|
||||
public function afterCompile(Nette\PhpGenerator\ClassType $class)
|
||||
{
|
||||
}
|
||||
}
|
151
vendor/nette/di/src/DI/Config/Adapters/IniAdapter.php
vendored
Normal file
151
vendor/nette/di/src/DI/Config/Adapters/IniAdapter.php
vendored
Normal file
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Config\Adapters;
|
||||
|
||||
use Nette;
|
||||
use Nette\DI\Config\Helpers;
|
||||
|
||||
|
||||
/**
|
||||
* Reading and generating INI files.
|
||||
*/
|
||||
class IniAdapter implements Nette\DI\Config\IAdapter
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @internal */
|
||||
const INHERITING_SEPARATOR = '<', // child < parent
|
||||
KEY_SEPARATOR = '.', // key nesting key1.key2.key3
|
||||
ESCAPED_KEY_SEPARATOR = '..',
|
||||
RAW_SECTION = '!';
|
||||
|
||||
|
||||
/**
|
||||
* Reads configuration from INI file.
|
||||
* @param string file name
|
||||
* @return array
|
||||
* @throws Nette\InvalidStateException
|
||||
*/
|
||||
public function load($file)
|
||||
{
|
||||
$ini = @parse_ini_file($file, true); // @ escalated to exception
|
||||
if ($ini === false) {
|
||||
$error = error_get_last();
|
||||
throw new Nette\InvalidStateException("parse_ini_file(): $error[message]");
|
||||
}
|
||||
return $this->process($ini);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws Nette\InvalidStateException
|
||||
*/
|
||||
public function process(array $arr)
|
||||
{
|
||||
$data = [];
|
||||
foreach ($arr as $secName => $secData) {
|
||||
if (is_array($secData)) { // is section?
|
||||
if (substr($secName, -1) === self::RAW_SECTION) {
|
||||
$secName = substr($secName, 0, -1);
|
||||
} else { // process key nesting separator (key1.key2.key3)
|
||||
$tmp = [];
|
||||
foreach ($secData as $key => $val) {
|
||||
$cursor = &$tmp;
|
||||
$key = str_replace(self::ESCAPED_KEY_SEPARATOR, "\xFF", $key);
|
||||
foreach (explode(self::KEY_SEPARATOR, $key) as $part) {
|
||||
$part = str_replace("\xFF", self::KEY_SEPARATOR, $part);
|
||||
if (!isset($cursor[$part]) || is_array($cursor[$part])) {
|
||||
$cursor = &$cursor[$part];
|
||||
} else {
|
||||
throw new Nette\InvalidStateException("Invalid key '$key' in section [$secName].");
|
||||
}
|
||||
}
|
||||
$cursor = $val;
|
||||
}
|
||||
$secData = $tmp;
|
||||
}
|
||||
|
||||
$parts = explode(self::INHERITING_SEPARATOR, $secName);
|
||||
if (count($parts) > 1) {
|
||||
$secName = trim($parts[0]);
|
||||
$secData[Helpers::EXTENDS_KEY] = trim($parts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$cursor = &$data; // nesting separator in section name
|
||||
foreach (explode(self::KEY_SEPARATOR, $secName) as $part) {
|
||||
if (!isset($cursor[$part]) || is_array($cursor[$part])) {
|
||||
$cursor = &$cursor[$part];
|
||||
} else {
|
||||
throw new Nette\InvalidStateException("Invalid section [$secName].");
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($secData) && is_array($cursor)) {
|
||||
$secData = Helpers::merge($secData, $cursor);
|
||||
}
|
||||
|
||||
$cursor = $secData;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates configuration in INI format.
|
||||
* @return string
|
||||
*/
|
||||
public function dump(array $data)
|
||||
{
|
||||
$output = [];
|
||||
foreach ($data as $name => $secData) {
|
||||
if (!is_array($secData)) {
|
||||
$output = [];
|
||||
self::build($data, $output, '');
|
||||
break;
|
||||
}
|
||||
if ($parent = Helpers::takeParent($secData)) {
|
||||
$output[] = "[$name " . self::INHERITING_SEPARATOR . " $parent]";
|
||||
} else {
|
||||
$output[] = "[$name]";
|
||||
}
|
||||
self::build($secData, $output, '');
|
||||
$output[] = '';
|
||||
}
|
||||
return "; generated by Nette\n\n" . implode(PHP_EOL, $output);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursive builds INI list.
|
||||
* @return void
|
||||
*/
|
||||
private static function build($input, &$output, $prefix)
|
||||
{
|
||||
foreach ($input as $key => $val) {
|
||||
$key = str_replace(self::KEY_SEPARATOR, self::ESCAPED_KEY_SEPARATOR, $key);
|
||||
if (is_array($val)) {
|
||||
self::build($val, $output, $prefix . $key . self::KEY_SEPARATOR);
|
||||
|
||||
} elseif (is_bool($val)) {
|
||||
$output[] = "$prefix$key = " . ($val ? 'true' : 'false');
|
||||
|
||||
} elseif (is_numeric($val)) {
|
||||
$output[] = "$prefix$key = $val";
|
||||
|
||||
} elseif (is_string($val)) {
|
||||
$output[] = "$prefix$key = \"$val\"";
|
||||
|
||||
} else {
|
||||
throw new Nette\InvalidArgumentException(sprintf("The '%s' item must be scalar or array, %s given.", $prefix . $key, gettype($val)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
139
vendor/nette/di/src/DI/Config/Adapters/NeonAdapter.php
vendored
Normal file
139
vendor/nette/di/src/DI/Config/Adapters/NeonAdapter.php
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Config\Adapters;
|
||||
|
||||
use Nette;
|
||||
use Nette\DI\Config\Helpers;
|
||||
use Nette\DI\Statement;
|
||||
use Nette\Neon;
|
||||
|
||||
|
||||
/**
|
||||
* Reading and generating NEON files.
|
||||
*/
|
||||
class NeonAdapter implements Nette\DI\Config\IAdapter
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @internal */
|
||||
const INHERITING_SEPARATOR = '<', // child < parent
|
||||
PREVENT_MERGING = '!';
|
||||
|
||||
|
||||
/**
|
||||
* Reads configuration from NEON file.
|
||||
* @param string file name
|
||||
* @return array
|
||||
*/
|
||||
public function load($file)
|
||||
{
|
||||
return $this->process((array) Neon\Neon::decode(file_get_contents($file)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws Nette\InvalidStateException
|
||||
*/
|
||||
public function process(array $arr)
|
||||
{
|
||||
$res = [];
|
||||
foreach ($arr as $key => $val) {
|
||||
if (is_string($key) && substr($key, -1) === self::PREVENT_MERGING) {
|
||||
if (!is_array($val) && $val !== null) {
|
||||
throw new Nette\InvalidStateException("Replacing operator is available only for arrays, item '$key' is not array.");
|
||||
}
|
||||
$key = substr($key, 0, -1);
|
||||
$val[Helpers::EXTENDS_KEY] = Helpers::OVERWRITE;
|
||||
|
||||
} elseif (is_string($key) && preg_match('#^(\S+)\s+' . self::INHERITING_SEPARATOR . '\s+(\S+)\z#', $key, $matches)) {
|
||||
if (!is_array($val) && $val !== null) {
|
||||
throw new Nette\InvalidStateException("Inheritance operator is available only for arrays, item '$key' is not array.");
|
||||
}
|
||||
list(, $key, $val[Helpers::EXTENDS_KEY]) = $matches;
|
||||
if (isset($res[$key])) {
|
||||
throw new Nette\InvalidStateException("Duplicated key '$key'.");
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($val)) {
|
||||
$val = $this->process($val);
|
||||
|
||||
} elseif ($val instanceof Neon\Entity) {
|
||||
if ($val->value === Neon\Neon::CHAIN) {
|
||||
$tmp = null;
|
||||
foreach ($this->process($val->attributes) as $st) {
|
||||
$tmp = new Statement(
|
||||
$tmp === null ? $st->getEntity() : [$tmp, ltrim($st->getEntity(), ':')],
|
||||
$st->arguments
|
||||
);
|
||||
}
|
||||
$val = $tmp;
|
||||
} else {
|
||||
$tmp = $this->process([$val->value]);
|
||||
$val = new Statement($tmp[0], $this->process($val->attributes));
|
||||
}
|
||||
}
|
||||
$res[$key] = $val;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates configuration in NEON format.
|
||||
* @return string
|
||||
*/
|
||||
public function dump(array $data)
|
||||
{
|
||||
$tmp = [];
|
||||
foreach ($data as $name => $secData) {
|
||||
if ($parent = Helpers::takeParent($secData)) {
|
||||
$name .= ' ' . self::INHERITING_SEPARATOR . ' ' . $parent;
|
||||
}
|
||||
$tmp[$name] = $secData;
|
||||
}
|
||||
array_walk_recursive(
|
||||
$tmp,
|
||||
function (&$val) {
|
||||
if ($val instanceof Statement) {
|
||||
$val = self::statementToEntity($val);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return "# generated by Nette\n\n" . Neon\Neon::encode($tmp, Neon\Neon::BLOCK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Neon\Entity
|
||||
*/
|
||||
private static function statementToEntity(Statement $val)
|
||||
{
|
||||
array_walk_recursive(
|
||||
$val->arguments,
|
||||
function (&$val) {
|
||||
if ($val instanceof Statement) {
|
||||
$val = self::statementToEntity($val);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (is_array($val->getEntity()) && $val->getEntity()[0] instanceof Statement) {
|
||||
return new Neon\Entity(
|
||||
Neon\Neon::CHAIN,
|
||||
[
|
||||
self::statementToEntity($val->getEntity()[0]),
|
||||
new Neon\Entity('::' . $val->getEntity()[1], $val->arguments),
|
||||
]
|
||||
);
|
||||
} else {
|
||||
return new Neon\Entity($val->getEntity(), $val->arguments);
|
||||
}
|
||||
}
|
||||
}
|
39
vendor/nette/di/src/DI/Config/Adapters/PhpAdapter.php
vendored
Normal file
39
vendor/nette/di/src/DI/Config/Adapters/PhpAdapter.php
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Config\Adapters;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Reading and generating PHP files.
|
||||
*/
|
||||
class PhpAdapter implements Nette\DI\Config\IAdapter
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/**
|
||||
* Reads configuration from PHP file.
|
||||
* @param string file name
|
||||
* @return array
|
||||
*/
|
||||
public function load($file)
|
||||
{
|
||||
return require $file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates configuration in PHP format.
|
||||
* @return string
|
||||
*/
|
||||
public function dump(array $data)
|
||||
{
|
||||
return "<?php // generated by Nette \nreturn " . Nette\PhpGenerator\Helpers::dump($data) . ';';
|
||||
}
|
||||
}
|
87
vendor/nette/di/src/DI/Config/Helpers.php
vendored
Normal file
87
vendor/nette/di/src/DI/Config/Helpers.php
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Config;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Configuration helpers.
|
||||
*/
|
||||
class Helpers
|
||||
{
|
||||
use Nette\StaticClass;
|
||||
|
||||
const
|
||||
EXTENDS_KEY = '_extends',
|
||||
OVERWRITE = true;
|
||||
|
||||
|
||||
/**
|
||||
* Merges configurations. Left has higher priority than right one.
|
||||
* @return array|string
|
||||
*/
|
||||
public static function merge($left, $right)
|
||||
{
|
||||
if (is_array($left) && is_array($right)) {
|
||||
foreach ($left as $key => $val) {
|
||||
if (is_int($key)) {
|
||||
$right[] = $val;
|
||||
} else {
|
||||
if (is_array($val) && isset($val[self::EXTENDS_KEY])) {
|
||||
if ($val[self::EXTENDS_KEY] === self::OVERWRITE) {
|
||||
unset($val[self::EXTENDS_KEY]);
|
||||
}
|
||||
} elseif (isset($right[$key])) {
|
||||
$val = static::merge($val, $right[$key]);
|
||||
}
|
||||
$right[$key] = $val;
|
||||
}
|
||||
}
|
||||
return $right;
|
||||
|
||||
} elseif ($left === null && is_array($right)) {
|
||||
return $right;
|
||||
|
||||
} else {
|
||||
return $left;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds out and removes information about the parent.
|
||||
* @return mixed
|
||||
*/
|
||||
public static function takeParent(&$data)
|
||||
{
|
||||
if (is_array($data) && isset($data[self::EXTENDS_KEY])) {
|
||||
$parent = $data[self::EXTENDS_KEY];
|
||||
unset($data[self::EXTENDS_KEY]);
|
||||
return $parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isOverwriting(&$data)
|
||||
{
|
||||
return is_array($data) && isset($data[self::EXTENDS_KEY]) && $data[self::EXTENDS_KEY] === self::OVERWRITE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInheriting(&$data)
|
||||
{
|
||||
return is_array($data) && isset($data[self::EXTENDS_KEY]) && $data[self::EXTENDS_KEY] !== self::OVERWRITE;
|
||||
}
|
||||
}
|
29
vendor/nette/di/src/DI/Config/IAdapter.php
vendored
Normal file
29
vendor/nette/di/src/DI/Config/IAdapter.php
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Config;
|
||||
|
||||
|
||||
/**
|
||||
* Adapter for reading and writing configuration files.
|
||||
*/
|
||||
interface IAdapter
|
||||
{
|
||||
|
||||
/**
|
||||
* Reads configuration from file.
|
||||
* @param string file name
|
||||
* @return array
|
||||
*/
|
||||
function load($file);
|
||||
|
||||
/**
|
||||
* Generates configuration string.
|
||||
* @return string
|
||||
*/
|
||||
function dump(array $data);
|
||||
}
|
137
vendor/nette/di/src/DI/Config/Loader.php
vendored
Normal file
137
vendor/nette/di/src/DI/Config/Loader.php
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Config;
|
||||
|
||||
use Nette;
|
||||
use Nette\Utils\Validators;
|
||||
|
||||
|
||||
/**
|
||||
* Configuration file loader.
|
||||
*/
|
||||
class Loader
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @internal */
|
||||
const INCLUDES_KEY = 'includes';
|
||||
|
||||
private $adapters = [
|
||||
'php' => Adapters\PhpAdapter::class,
|
||||
'ini' => Adapters\IniAdapter::class,
|
||||
'neon' => Adapters\NeonAdapter::class,
|
||||
];
|
||||
|
||||
private $dependencies = [];
|
||||
|
||||
private $loadedFiles = [];
|
||||
|
||||
|
||||
/**
|
||||
* Reads configuration from file.
|
||||
* @param string file name
|
||||
* @param string optional section to load
|
||||
* @return array
|
||||
*/
|
||||
public function load($file, $section = null)
|
||||
{
|
||||
if (!is_file($file) || !is_readable($file)) {
|
||||
throw new Nette\FileNotFoundException("File '$file' is missing or is not readable.");
|
||||
}
|
||||
|
||||
if (isset($this->loadedFiles[$file])) {
|
||||
throw new Nette\InvalidStateException("Recursive included file '$file'");
|
||||
}
|
||||
$this->loadedFiles[$file] = true;
|
||||
|
||||
$this->dependencies[] = $file;
|
||||
$data = $this->getAdapter($file)->load($file);
|
||||
|
||||
if ($section) {
|
||||
if (isset($data[self::INCLUDES_KEY])) {
|
||||
throw new Nette\InvalidStateException("Section 'includes' must be placed under some top section in file '$file'.");
|
||||
}
|
||||
$data = $this->getSection($data, $section, $file);
|
||||
}
|
||||
|
||||
// include child files
|
||||
$merged = [];
|
||||
if (isset($data[self::INCLUDES_KEY])) {
|
||||
Validators::assert($data[self::INCLUDES_KEY], 'list', "section 'includes' in file '$file'");
|
||||
foreach ($data[self::INCLUDES_KEY] as $include) {
|
||||
if (!preg_match('#([a-z]+:)?[/\\\\]#Ai', $include)) {
|
||||
$include = dirname($file) . '/' . $include;
|
||||
}
|
||||
$merged = Helpers::merge($this->load($include), $merged);
|
||||
}
|
||||
}
|
||||
unset($data[self::INCLUDES_KEY], $this->loadedFiles[$file]);
|
||||
|
||||
|
||||
return Helpers::merge($data, $merged);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save configuration to file.
|
||||
* @param array
|
||||
* @param string file
|
||||
* @return void
|
||||
*/
|
||||
public function save($data, $file)
|
||||
{
|
||||
if (file_put_contents($file, $this->getAdapter($file)->dump($data)) === false) {
|
||||
throw new Nette\IOException("Cannot write file '$file'.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns configuration files.
|
||||
* @return array
|
||||
*/
|
||||
public function getDependencies()
|
||||
{
|
||||
return array_unique($this->dependencies);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers adapter for given file extension.
|
||||
* @param string file extension
|
||||
* @param string|IAdapter
|
||||
* @return static
|
||||
*/
|
||||
public function addAdapter($extension, $adapter)
|
||||
{
|
||||
$this->adapters[strtolower($extension)] = $adapter;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/** @return IAdapter */
|
||||
private function getAdapter($file)
|
||||
{
|
||||
$extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
||||
if (!isset($this->adapters[$extension])) {
|
||||
throw new Nette\InvalidArgumentException("Unknown file extension '$file'.");
|
||||
}
|
||||
return is_object($this->adapters[$extension]) ? $this->adapters[$extension] : new $this->adapters[$extension];
|
||||
}
|
||||
|
||||
|
||||
private function getSection(array $data, $key, $file)
|
||||
{
|
||||
Validators::assertField($data, $key, 'array|null', "section '%' in file '$file'");
|
||||
$item = $data[$key];
|
||||
if ($parent = Helpers::takeParent($item)) {
|
||||
$item = Helpers::merge($item, $this->getSection($data, $parent, $file));
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
}
|
345
vendor/nette/di/src/DI/Container.php
vendored
Normal file
345
vendor/nette/di/src/DI/Container.php
vendored
Normal file
|
@ -0,0 +1,345 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* The dependency injection container default implementation.
|
||||
*/
|
||||
class Container
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
const TAGS = 'tags';
|
||||
|
||||
const TYPES = 'types';
|
||||
|
||||
const SERVICES = 'services';
|
||||
|
||||
const ALIASES = 'aliases';
|
||||
|
||||
/** @var array user parameters */
|
||||
public $parameters = [];
|
||||
|
||||
/** @var array[] */
|
||||
protected $meta = [];
|
||||
|
||||
/** @var object[] storage for shared objects */
|
||||
private $registry = [];
|
||||
|
||||
/** @var array circular reference detector */
|
||||
private $creating;
|
||||
|
||||
|
||||
public function __construct(array $params = [])
|
||||
{
|
||||
$this->parameters = $params + $this->parameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getParameters()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the service to the container.
|
||||
* @param string
|
||||
* @param object
|
||||
* @return static
|
||||
*/
|
||||
public function addService($name, $service)
|
||||
{
|
||||
if (!is_string($name) || !$name) {
|
||||
throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($name)));
|
||||
}
|
||||
$name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
|
||||
if (isset($this->registry[$name])) {
|
||||
throw new Nette\InvalidStateException("Service '$name' already exists.");
|
||||
|
||||
} elseif (!is_object($service)) {
|
||||
throw new Nette\InvalidArgumentException(sprintf("Service '%s' must be a object, %s given.", $name, gettype($service)));
|
||||
|
||||
} elseif (isset($this->meta[self::SERVICES][$name]) && !$service instanceof $this->meta[self::SERVICES][$name]) {
|
||||
throw new Nette\InvalidArgumentException(sprintf("Service '%s' must be instance of %s, %s given.", $name, $this->meta[self::SERVICES][$name], get_class($service)));
|
||||
}
|
||||
|
||||
$this->registry[$name] = $service;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the service from the container.
|
||||
* @param string
|
||||
* @return void
|
||||
*/
|
||||
public function removeService($name)
|
||||
{
|
||||
$name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
|
||||
unset($this->registry[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the service object by name.
|
||||
* @param string
|
||||
* @return object
|
||||
* @throws MissingServiceException
|
||||
*/
|
||||
public function getService($name)
|
||||
{
|
||||
if (!isset($this->registry[$name])) {
|
||||
if (isset($this->meta[self::ALIASES][$name])) {
|
||||
return $this->getService($this->meta[self::ALIASES][$name]);
|
||||
}
|
||||
$this->registry[$name] = $this->createService($name);
|
||||
}
|
||||
return $this->registry[$name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the service type by name.
|
||||
* @param string
|
||||
* @return string
|
||||
* @throws MissingServiceException
|
||||
*/
|
||||
public function getServiceType($name)
|
||||
{
|
||||
if (isset($this->meta[self::ALIASES][$name])) {
|
||||
return $this->getServiceType($this->meta[self::ALIASES][$name]);
|
||||
|
||||
} elseif (isset($this->meta[self::SERVICES][$name])) {
|
||||
return $this->meta[self::SERVICES][$name];
|
||||
|
||||
} else {
|
||||
throw new MissingServiceException("Service '$name' not found.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does the service exist?
|
||||
* @param string service name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasService($name)
|
||||
{
|
||||
$name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
|
||||
return isset($this->registry[$name])
|
||||
|| (method_exists($this, $method = self::getMethodName($name))
|
||||
&& (new \ReflectionMethod($this, $method))->getName() === $method);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is the service created?
|
||||
* @param string service name
|
||||
* @return bool
|
||||
*/
|
||||
public function isCreated($name)
|
||||
{
|
||||
if (!$this->hasService($name)) {
|
||||
throw new MissingServiceException("Service '$name' not found.");
|
||||
}
|
||||
$name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
|
||||
return isset($this->registry[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates new instance of the service.
|
||||
* @param string service name
|
||||
* @return object
|
||||
* @throws MissingServiceException
|
||||
*/
|
||||
public function createService($name, array $args = [])
|
||||
{
|
||||
$name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
|
||||
$method = self::getMethodName($name);
|
||||
if (isset($this->creating[$name])) {
|
||||
throw new Nette\InvalidStateException(sprintf('Circular reference detected for services: %s.', implode(', ', array_keys($this->creating))));
|
||||
|
||||
} elseif (!method_exists($this, $method) || (new \ReflectionMethod($this, $method))->getName() !== $method) {
|
||||
throw new MissingServiceException("Service '$name' not found.");
|
||||
}
|
||||
|
||||
try {
|
||||
$this->creating[$name] = true;
|
||||
$service = $this->$method(...$args);
|
||||
|
||||
} finally {
|
||||
unset($this->creating[$name]);
|
||||
}
|
||||
|
||||
if (!is_object($service)) {
|
||||
throw new Nette\UnexpectedValueException("Unable to create service '$name', value returned by method $method() is not object.");
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves service by type.
|
||||
* @param string class or interface
|
||||
* @param bool throw exception if service doesn't exist?
|
||||
* @return object|null service
|
||||
* @throws MissingServiceException
|
||||
*/
|
||||
public function getByType($type, $throw = true)
|
||||
{
|
||||
$type = Helpers::normalizeClass($type);
|
||||
if (!empty($this->meta[self::TYPES][$type][true])) {
|
||||
if (count($names = $this->meta[self::TYPES][$type][true]) === 1) {
|
||||
return $this->getService($names[0]);
|
||||
}
|
||||
natsort($names);
|
||||
throw new MissingServiceException("Multiple services of type $type found: " . implode(', ', $names) . '.');
|
||||
|
||||
} elseif ($throw) {
|
||||
throw new MissingServiceException("Service of type $type not found.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the service names of the specified type.
|
||||
* @param string
|
||||
* @return string[]
|
||||
*/
|
||||
public function findByType($type)
|
||||
{
|
||||
$type = Helpers::normalizeClass($type);
|
||||
return empty($this->meta[self::TYPES][$type])
|
||||
? []
|
||||
: array_merge(...array_values($this->meta[self::TYPES][$type]));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the service names of the specified tag.
|
||||
* @param string
|
||||
* @return array of [service name => tag attributes]
|
||||
*/
|
||||
public function findByTag($tag)
|
||||
{
|
||||
return isset($this->meta[self::TAGS][$tag]) ? $this->meta[self::TAGS][$tag] : [];
|
||||
}
|
||||
|
||||
|
||||
/********************* autowiring ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Creates new instance using autowiring.
|
||||
* @param string class
|
||||
* @param array arguments
|
||||
* @return object
|
||||
* @throws Nette\InvalidArgumentException
|
||||
*/
|
||||
public function createInstance($class, array $args = [])
|
||||
{
|
||||
$rc = new \ReflectionClass($class);
|
||||
if (!$rc->isInstantiable()) {
|
||||
throw new ServiceCreationException("Class $class is not instantiable.");
|
||||
|
||||
} elseif ($constructor = $rc->getConstructor()) {
|
||||
return $rc->newInstanceArgs(Helpers::autowireArguments($constructor, $args, $this));
|
||||
|
||||
} elseif ($args) {
|
||||
throw new ServiceCreationException("Unable to pass arguments, class $class has no constructor.");
|
||||
}
|
||||
return new $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls all methods starting with with "inject" using autowiring.
|
||||
* @param object
|
||||
* @return void
|
||||
*/
|
||||
public function callInjects($service)
|
||||
{
|
||||
Extensions\InjectExtension::callInjects($this, $service);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls method using autowiring.
|
||||
* @return mixed
|
||||
*/
|
||||
public function callMethod(callable $function, array $args = [])
|
||||
{
|
||||
return $function(...Helpers::autowireArguments(Nette\Utils\Callback::toReflection($function), $args, $this));
|
||||
}
|
||||
|
||||
|
||||
/********************* shortcuts ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Expands %placeholders%.
|
||||
* @param mixed
|
||||
* @return mixed
|
||||
* @deprecated
|
||||
*/
|
||||
public function expand($s)
|
||||
{
|
||||
return Helpers::expand($s, $this->parameters);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function &__get($name)
|
||||
{
|
||||
trigger_error(__METHOD__ . ' is deprecated; use getService().', E_USER_DEPRECATED);
|
||||
$tmp = $this->getService($name);
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function __set($name, $service)
|
||||
{
|
||||
trigger_error(__METHOD__ . ' is deprecated; use addService().', E_USER_DEPRECATED);
|
||||
$this->addService($name, $service);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function __isset($name)
|
||||
{
|
||||
trigger_error(__METHOD__ . ' is deprecated; use hasService().', E_USER_DEPRECATED);
|
||||
return $this->hasService($name);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function __unset($name)
|
||||
{
|
||||
trigger_error(__METHOD__ . ' is deprecated; use removeService().', E_USER_DEPRECATED);
|
||||
$this->removeService($name);
|
||||
}
|
||||
|
||||
|
||||
public static function getMethodName($name)
|
||||
{
|
||||
return 'createService'
|
||||
. (preg_match('#^[A-Z]#', $name) ? '__' : '')
|
||||
. str_replace('.', '__', ucfirst($name));
|
||||
}
|
||||
}
|
880
vendor/nette/di/src/DI/ContainerBuilder.php
vendored
Normal file
880
vendor/nette/di/src/DI/ContainerBuilder.php
vendored
Normal file
|
@ -0,0 +1,880 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
use Nette\PhpGenerator\Helpers as PhpHelpers;
|
||||
use Nette\Utils\Reflection;
|
||||
use Nette\Utils\Strings;
|
||||
use Nette\Utils\Validators;
|
||||
use ReflectionClass;
|
||||
|
||||
|
||||
/**
|
||||
* Container builder.
|
||||
*/
|
||||
class ContainerBuilder
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
const THIS_SERVICE = 'self',
|
||||
THIS_CONTAINER = 'container';
|
||||
|
||||
/** @var array */
|
||||
public $parameters = [];
|
||||
|
||||
/** @var ServiceDefinition[] */
|
||||
private $definitions = [];
|
||||
|
||||
/** @var array of alias => service */
|
||||
private $aliases = [];
|
||||
|
||||
/** @var array for auto-wiring */
|
||||
private $classList = [];
|
||||
|
||||
/** @var bool */
|
||||
private $classListNeedsRefresh = true;
|
||||
|
||||
/** @var string[] of classes excluded from auto-wiring */
|
||||
private $excludedClasses = [];
|
||||
|
||||
/** @var array */
|
||||
private $dependencies = [];
|
||||
|
||||
/** @var string */
|
||||
private $currentService;
|
||||
|
||||
|
||||
/**
|
||||
* Adds new service definition.
|
||||
* @param string
|
||||
* @return ServiceDefinition
|
||||
*/
|
||||
public function addDefinition($name, ServiceDefinition $definition = null)
|
||||
{
|
||||
$this->classListNeedsRefresh = true;
|
||||
if (!is_string($name) || !$name) { // builder is not ready for falsy names such as '0'
|
||||
throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($name)));
|
||||
}
|
||||
$name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
|
||||
if (isset($this->definitions[$name])) {
|
||||
throw new Nette\InvalidStateException("Service '$name' has already been added.");
|
||||
}
|
||||
if (!$definition) {
|
||||
$definition = new ServiceDefinition;
|
||||
}
|
||||
$definition->setNotifier(function () {
|
||||
$this->classListNeedsRefresh = true;
|
||||
});
|
||||
return $this->definitions[$name] = $definition;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the specified service definition.
|
||||
* @param string
|
||||
* @return void
|
||||
*/
|
||||
public function removeDefinition($name)
|
||||
{
|
||||
$this->classListNeedsRefresh = true;
|
||||
$name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
|
||||
unset($this->definitions[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the service definition.
|
||||
* @param string
|
||||
* @return ServiceDefinition
|
||||
*/
|
||||
public function getDefinition($name)
|
||||
{
|
||||
$service = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
|
||||
if (!isset($this->definitions[$service])) {
|
||||
throw new MissingServiceException("Service '$name' not found.");
|
||||
}
|
||||
return $this->definitions[$service];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets all service definitions.
|
||||
* @return ServiceDefinition[]
|
||||
*/
|
||||
public function getDefinitions()
|
||||
{
|
||||
return $this->definitions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does the service definition or alias exist?
|
||||
* @param string
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDefinition($name)
|
||||
{
|
||||
$name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
|
||||
return isset($this->definitions[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @param string
|
||||
*/
|
||||
public function addAlias($alias, $service)
|
||||
{
|
||||
if (!is_string($alias) || !$alias) { // builder is not ready for falsy names such as '0'
|
||||
throw new Nette\InvalidArgumentException(sprintf('Alias name must be a non-empty string, %s given.', gettype($alias)));
|
||||
|
||||
} elseif (!is_string($service) || !$service) { // builder is not ready for falsy names such as '0'
|
||||
throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($service)));
|
||||
|
||||
} elseif (isset($this->aliases[$alias])) {
|
||||
throw new Nette\InvalidStateException("Alias '$alias' has already been added.");
|
||||
|
||||
} elseif (isset($this->definitions[$alias])) {
|
||||
throw new Nette\InvalidStateException("Service '$alias' has already been added.");
|
||||
}
|
||||
$this->aliases[$alias] = $service;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the specified alias.
|
||||
* @return void
|
||||
*/
|
||||
public function removeAlias($alias)
|
||||
{
|
||||
unset($this->aliases[$alias]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets all service aliases.
|
||||
* @return array
|
||||
*/
|
||||
public function getAliases()
|
||||
{
|
||||
return $this->aliases;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string[]
|
||||
* @return static
|
||||
*/
|
||||
public function addExcludedClasses(array $types)
|
||||
{
|
||||
foreach ($types as $type) {
|
||||
if (class_exists($type) || interface_exists($type)) {
|
||||
$type = Helpers::normalizeClass($type);
|
||||
$this->excludedClasses += class_parents($type) + class_implements($type) + [$type => $type];
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function setClassName($name)
|
||||
{
|
||||
trigger_error(__METHOD__ . ' has been deprecated', E_USER_DEPRECATED);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function getClassName()
|
||||
{
|
||||
trigger_error(__METHOD__ . ' has been deprecated', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
|
||||
/********************* class resolving ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Resolves service name by type.
|
||||
* @param string class or interface
|
||||
* @param bool throw exception if service doesn't exist?
|
||||
* @return string|null service name or null
|
||||
* @throws ServiceCreationException
|
||||
*/
|
||||
public function getByType($type, $throw = false)
|
||||
{
|
||||
$type = Helpers::normalizeClass($type);
|
||||
|
||||
if (
|
||||
$this->currentService !== null
|
||||
&& is_a($this->definitions[$this->currentService]->getType(), $type, true)
|
||||
) {
|
||||
return $this->currentService;
|
||||
}
|
||||
|
||||
$types = $this->getClassList();
|
||||
if (empty($types[$type][true])) {
|
||||
if ($throw) {
|
||||
throw new MissingServiceException("Service of type '$type' not found.");
|
||||
}
|
||||
return;
|
||||
|
||||
} elseif (count($types[$type][true]) === 1) {
|
||||
return $types[$type][true][0];
|
||||
|
||||
} else {
|
||||
$list = $types[$type][true];
|
||||
natsort($list);
|
||||
$hint = count($list) === 2 && ($tmp = strpos($list[0], '.') xor strpos($list[1], '.'))
|
||||
? '. If you want to overwrite service ' . $list[$tmp ? 0 : 1] . ', give it proper name.'
|
||||
: '';
|
||||
throw new ServiceCreationException("Multiple services of type $type found: " . implode(', ', $list) . $hint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the service definition of the specified type.
|
||||
* @param string
|
||||
* @return ServiceDefinition
|
||||
*/
|
||||
public function getDefinitionByType($type)
|
||||
{
|
||||
return $this->getDefinition($this->getByType($type, true));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the service names and definitions of the specified type.
|
||||
* @param string
|
||||
* @return ServiceDefinition[]
|
||||
*/
|
||||
public function findByType($type)
|
||||
{
|
||||
$type = Helpers::normalizeClass($type);
|
||||
$found = [];
|
||||
$types = $this->getClassList();
|
||||
if (!empty($types[$type])) {
|
||||
foreach (array_merge(...array_values($types[$type])) as $name) {
|
||||
$found[$name] = $this->definitions[$name];
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the service objects of the specified tag.
|
||||
* @param string
|
||||
* @return array of [service name => tag attributes]
|
||||
*/
|
||||
public function findByTag($tag)
|
||||
{
|
||||
$found = [];
|
||||
foreach ($this->definitions as $name => $def) {
|
||||
if (($tmp = $def->getTag($tag)) !== null) {
|
||||
$found[$name] = $tmp;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getClassList()
|
||||
{
|
||||
if ($this->classList !== false && $this->classListNeedsRefresh) {
|
||||
$this->prepareClassList();
|
||||
$this->classListNeedsRefresh = false;
|
||||
}
|
||||
return $this->classList ?: [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates $dependencies, $classList and normalizes class names.
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
public function prepareClassList()
|
||||
{
|
||||
unset($this->definitions[self::THIS_CONTAINER]);
|
||||
$this->addDefinition(self::THIS_CONTAINER)->setType(Container::class);
|
||||
|
||||
$this->classList = false;
|
||||
|
||||
foreach ($this->definitions as $name => $def) {
|
||||
// prepare generated factories
|
||||
if ($def->getImplement()) {
|
||||
$this->resolveImplement($def, $name);
|
||||
}
|
||||
|
||||
if ($def->isDynamic()) {
|
||||
if (!$def->getType()) {
|
||||
throw new ServiceCreationException("Type is missing in definition of service '$name'.");
|
||||
}
|
||||
$def->setFactory(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
// complete class-factory pairs
|
||||
if (!$def->getEntity()) {
|
||||
if (!$def->getType()) {
|
||||
throw new ServiceCreationException("Factory and type are missing in definition of service '$name'.");
|
||||
}
|
||||
$def->setFactory($def->getType(), ($factory = $def->getFactory()) ? $factory->arguments : []);
|
||||
}
|
||||
|
||||
// auto-disable autowiring for aliases
|
||||
if (
|
||||
$def->getAutowired() === true
|
||||
&& ($alias = $this->getServiceName($def->getFactory()->getEntity()))
|
||||
&& (!$def->getImplement() || (!Strings::contains($alias, '\\') && $this->definitions[$alias]->getImplement()))
|
||||
) {
|
||||
$def->setAutowired(false);
|
||||
}
|
||||
}
|
||||
|
||||
// resolve and check classes
|
||||
foreach ($this->definitions as $name => $def) {
|
||||
$this->resolveServiceType($name);
|
||||
}
|
||||
|
||||
// build auto-wiring list
|
||||
$this->classList = $preferred = [];
|
||||
foreach ($this->definitions as $name => $def) {
|
||||
if ($type = $def->getImplement() ?: $def->getType()) {
|
||||
$defAutowired = $def->getAutowired();
|
||||
if (is_array($defAutowired)) {
|
||||
foreach ($defAutowired as $k => $autowiredType) {
|
||||
if ($autowiredType === self::THIS_SERVICE) {
|
||||
$defAutowired[$k] = $type;
|
||||
} elseif (!is_a($type, $autowiredType, true)) {
|
||||
throw new ServiceCreationException("Incompatible class $autowiredType in autowiring definition of service '$name'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (class_parents($type) + class_implements($type) + [$type] as $parent) {
|
||||
$autowired = $defAutowired && empty($this->excludedClasses[$parent]);
|
||||
if ($autowired && is_array($defAutowired)) {
|
||||
$autowired = false;
|
||||
foreach ($defAutowired as $autowiredType) {
|
||||
if (is_a($parent, $autowiredType, true)) {
|
||||
if (empty($preferred[$parent]) && isset($this->classList[$parent][true])) {
|
||||
$this->classList[$parent][false] = array_merge(...$this->classList[$parent]);
|
||||
$this->classList[$parent][true] = [];
|
||||
}
|
||||
$preferred[$parent] = $autowired = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif (isset($preferred[$parent])) {
|
||||
$autowired = false;
|
||||
}
|
||||
$this->classList[$parent][$autowired][] = (string) $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function resolveImplement(ServiceDefinition $def, $name)
|
||||
{
|
||||
$interface = $def->getImplement();
|
||||
if (!interface_exists($interface)) {
|
||||
throw new ServiceCreationException("Interface $interface used in service '$name' not found.");
|
||||
}
|
||||
$interface = Helpers::normalizeClass($interface);
|
||||
$def->setImplement($interface);
|
||||
|
||||
$rc = new ReflectionClass($interface);
|
||||
$this->addDependency($rc);
|
||||
$method = $rc->hasMethod('create')
|
||||
? $rc->getMethod('create')
|
||||
: ($rc->hasMethod('get') ? $rc->getMethod('get') : null);
|
||||
|
||||
if (count($rc->getMethods()) !== 1 || !$method || $method->isStatic()) {
|
||||
throw new ServiceCreationException("Interface $interface used in service '$name' must have just one non-static method create() or get().");
|
||||
}
|
||||
$def->setImplementMode($rc->hasMethod('create') ? $def::IMPLEMENT_MODE_CREATE : $def::IMPLEMENT_MODE_GET);
|
||||
$methodName = Reflection::toString($method) . '()';
|
||||
|
||||
if (!$def->getType() && !$def->getEntity()) {
|
||||
$returnType = Helpers::getReturnType($method);
|
||||
if (!$returnType) {
|
||||
throw new ServiceCreationException("Method $methodName used in service '$name' has not return type hint or annotation @return.");
|
||||
} elseif (!class_exists($returnType)) {
|
||||
throw new ServiceCreationException("Check a type hint or annotation @return of the $methodName method used in service '$name', class '$returnType' cannot be found.");
|
||||
}
|
||||
$def->setType($returnType);
|
||||
}
|
||||
|
||||
if ($rc->hasMethod('get')) {
|
||||
if ($method->getParameters()) {
|
||||
throw new ServiceCreationException("Method $methodName used in service '$name' must have no arguments.");
|
||||
} elseif ($def->getSetup()) {
|
||||
throw new ServiceCreationException("Service accessor '$name' must have no setup.");
|
||||
}
|
||||
if (!$def->getEntity()) {
|
||||
$def->setFactory('@\\' . ltrim($def->getType(), '\\'));
|
||||
} elseif (!$this->getServiceName($def->getFactory()->getEntity())) {
|
||||
throw new ServiceCreationException("Invalid factory in service '$name' definition.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!$def->parameters) {
|
||||
$ctorParams = [];
|
||||
if (!$def->getEntity()) {
|
||||
$def->setFactory($def->getType(), $def->getFactory() ? $def->getFactory()->arguments : []);
|
||||
}
|
||||
if (
|
||||
($class = $this->resolveEntityType($def->getFactory(), [$name => 1]))
|
||||
&& ($ctor = (new ReflectionClass($class))->getConstructor())
|
||||
) {
|
||||
foreach ($ctor->getParameters() as $param) {
|
||||
$ctorParams[$param->getName()] = $param;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($method->getParameters() as $param) {
|
||||
$hint = Reflection::getParameterType($param);
|
||||
if (isset($ctorParams[$param->getName()])) {
|
||||
$arg = $ctorParams[$param->getName()];
|
||||
$argHint = Reflection::getParameterType($arg);
|
||||
if ($hint !== $argHint && !is_a($hint, $argHint, true)) {
|
||||
throw new ServiceCreationException("Type hint for \${$param->getName()} in $methodName doesn't match type hint in $class constructor.");
|
||||
}
|
||||
$def->getFactory()->arguments[$arg->getPosition()] = self::literal('$' . $arg->getName());
|
||||
} elseif (!$def->getSetup()) {
|
||||
$hint = Nette\Utils\ObjectHelpers::getSuggestion(array_keys($ctorParams), $param->getName());
|
||||
throw new ServiceCreationException("Unused parameter \${$param->getName()} when implementing method $methodName" . ($hint ? ", did you mean \${$hint}?" : '.'));
|
||||
}
|
||||
$nullable = $hint && $param->allowsNull() && (!$param->isDefaultValueAvailable() || $param->getDefaultValue() !== null);
|
||||
$paramDef = ($nullable ? '?' : '') . $hint . ' ' . $param->getName();
|
||||
if ($param->isDefaultValueAvailable()) {
|
||||
$def->parameters[$paramDef] = Reflection::getParameterDefaultValue($param);
|
||||
} else {
|
||||
$def->parameters[] = $paramDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @return string|null */
|
||||
private function resolveServiceType($name, $recursive = [])
|
||||
{
|
||||
if (isset($recursive[$name])) {
|
||||
throw new ServiceCreationException(sprintf('Circular reference detected for services: %s.', implode(', ', array_keys($recursive))));
|
||||
}
|
||||
$recursive[$name] = true;
|
||||
|
||||
$def = $this->definitions[$name];
|
||||
$factoryClass = $def->getFactory() ? $this->resolveEntityType($def->getFactory()->getEntity(), $recursive) : null; // call always to check entities
|
||||
if ($type = $def->getType() ?: $factoryClass) {
|
||||
if (!class_exists($type) && !interface_exists($type)) {
|
||||
throw new ServiceCreationException("Class or interface '$type' used in service '$name' not found.");
|
||||
}
|
||||
$type = Helpers::normalizeClass($type);
|
||||
$def->setType($type);
|
||||
if (count($recursive) === 1) {
|
||||
$this->addDependency(new ReflectionClass($factoryClass ?: $type));
|
||||
}
|
||||
|
||||
} elseif ($def->getAutowired()) {
|
||||
throw new ServiceCreationException("Unknown type of service '$name', declare return type of factory method (for PHP 5 use annotation @return)");
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
|
||||
/** @return string|null */
|
||||
private function resolveEntityType($entity, $recursive = [])
|
||||
{
|
||||
$entity = $this->normalizeEntity($entity instanceof Statement ? $entity->getEntity() : $entity);
|
||||
$serviceName = current(array_slice(array_keys($recursive), -1));
|
||||
|
||||
if (is_array($entity)) {
|
||||
if (($service = $this->getServiceName($entity[0])) || $entity[0] instanceof Statement) {
|
||||
$entity[0] = $this->resolveEntityType($entity[0], $recursive);
|
||||
if (!$entity[0]) {
|
||||
return;
|
||||
} elseif (isset($this->definitions[$service]) && $this->definitions[$service]->getImplement()) { // @Implement::create
|
||||
return $entity[1] === 'create' ? $this->resolveServiceType($service, $recursive) : null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$reflection = Nette\Utils\Callback::toReflection($entity[0] === '' ? $entity[1] : $entity);
|
||||
$refClass = $reflection instanceof \ReflectionMethod ? $reflection->getDeclaringClass() : null;
|
||||
} catch (\ReflectionException $e) {
|
||||
}
|
||||
|
||||
if (isset($e) || ($refClass && (!$reflection->isPublic()
|
||||
|| ($refClass->isTrait() && !$reflection->isStatic())
|
||||
))) {
|
||||
throw new ServiceCreationException(sprintf("Method %s() used in service '%s' is not callable.", Nette\Utils\Callback::toString($entity), $serviceName));
|
||||
}
|
||||
$this->addDependency($reflection);
|
||||
|
||||
$type = Helpers::getReturnType($reflection);
|
||||
if ($type && !class_exists($type) && !interface_exists($type)) {
|
||||
throw new ServiceCreationException(sprintf("Class or interface '%s' not found. Is return type of %s() used in service '%s' correct?", $type, Nette\Utils\Callback::toString($entity), $serviceName));
|
||||
}
|
||||
return $type;
|
||||
|
||||
} elseif ($service = $this->getServiceName($entity)) { // alias or factory
|
||||
if (Strings::contains($service, '\\')) { // @\Class
|
||||
return $service;
|
||||
}
|
||||
return $this->definitions[$service]->getImplement()
|
||||
?: $this->definitions[$service]->getType()
|
||||
?: $this->resolveServiceType($service, $recursive);
|
||||
|
||||
} elseif (is_string($entity)) { // class
|
||||
if (!class_exists($entity)) {
|
||||
throw new ServiceCreationException("Class $entity used in service '$serviceName' not found.");
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function complete()
|
||||
{
|
||||
$this->prepareClassList();
|
||||
|
||||
foreach ($this->definitions as $name => $def) {
|
||||
if ($def->isDynamic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->currentService = null;
|
||||
$entity = $def->getFactory()->getEntity();
|
||||
$serviceRef = $this->getServiceName($entity);
|
||||
$factory = $serviceRef && !$def->getFactory()->arguments && !$def->getSetup() && $def->getImplementMode() !== $def::IMPLEMENT_MODE_CREATE
|
||||
? new Statement(['@' . self::THIS_CONTAINER, 'getService'], [$serviceRef])
|
||||
: $def->getFactory();
|
||||
|
||||
try {
|
||||
$def->setFactory($this->completeStatement($factory));
|
||||
$this->classListNeedsRefresh = false;
|
||||
|
||||
$this->currentService = $name;
|
||||
$setups = $def->getSetup();
|
||||
foreach ($setups as &$setup) {
|
||||
if (is_string($setup->getEntity()) && strpbrk($setup->getEntity(), ':@?\\') === false) { // auto-prepend @self
|
||||
$setup = new Statement(['@' . $name, $setup->getEntity()], $setup->arguments);
|
||||
}
|
||||
$setup = $this->completeStatement($setup);
|
||||
}
|
||||
$def->setSetup($setups);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$type = $def->getType();
|
||||
if (!$type) {
|
||||
$message = "Service '$name': " . $e->getMessage();
|
||||
} elseif (ctype_digit($name)) {
|
||||
$message = "Service of type $type: " . str_replace("$type::", '', $e->getMessage());
|
||||
} else {
|
||||
$message = "Service '$name' (type of $type): " . str_replace("$type::", '', $e->getMessage());
|
||||
}
|
||||
throw $e instanceof ServiceCreationException
|
||||
? $e->setMessage($message)
|
||||
: new ServiceCreationException($message, 0, $e);
|
||||
|
||||
} finally {
|
||||
$this->currentService = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Statement
|
||||
*/
|
||||
public function completeStatement(Statement $statement)
|
||||
{
|
||||
$entity = $this->normalizeEntity($statement->getEntity());
|
||||
$arguments = $statement->arguments;
|
||||
|
||||
if (is_string($entity) && Strings::contains($entity, '?')) { // PHP literal
|
||||
|
||||
} elseif ($service = $this->getServiceName($entity)) { // factory calling
|
||||
$params = [];
|
||||
foreach ($this->definitions[$service]->parameters as $k => $v) {
|
||||
$params[] = preg_replace('#\w+\z#', '\$$0', (is_int($k) ? $v : $k)) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v));
|
||||
}
|
||||
$rm = new \ReflectionFunction(eval('return function(' . implode(', ', $params) . ') {};'));
|
||||
$arguments = Helpers::autowireArguments($rm, $arguments, $this);
|
||||
$entity = '@' . $service;
|
||||
|
||||
} elseif ($entity === 'not') { // operator
|
||||
|
||||
} elseif (is_string($entity)) { // class name
|
||||
if (!class_exists($entity)) {
|
||||
throw new ServiceCreationException("Class $entity not found.");
|
||||
} elseif ((new ReflectionClass($entity))->isAbstract()) {
|
||||
throw new ServiceCreationException("Class $entity is abstract.");
|
||||
} elseif (($rm = (new ReflectionClass($entity))->getConstructor()) !== null && !$rm->isPublic()) {
|
||||
$visibility = $rm->isProtected() ? 'protected' : 'private';
|
||||
throw new ServiceCreationException("Class $entity has $visibility constructor.");
|
||||
} elseif ($constructor = (new ReflectionClass($entity))->getConstructor()) {
|
||||
$this->addDependency($constructor);
|
||||
$arguments = Helpers::autowireArguments($constructor, $arguments, $this);
|
||||
} elseif ($arguments) {
|
||||
throw new ServiceCreationException("Unable to pass arguments, class $entity has no constructor.");
|
||||
}
|
||||
|
||||
} elseif (!Nette\Utils\Arrays::isList($entity) || count($entity) !== 2) {
|
||||
throw new ServiceCreationException(sprintf('Expected class, method or property, %s given.', PhpHelpers::dump($entity)));
|
||||
|
||||
} elseif (!preg_match('#^\$?(\\\\?' . PhpHelpers::PHP_IDENT . ')+(\[\])?\z#', $entity[1])) {
|
||||
throw new ServiceCreationException("Expected function, method or property name, '$entity[1]' given.");
|
||||
|
||||
} elseif ($entity[0] === '') { // globalFunc
|
||||
if (!Nette\Utils\Arrays::isList($arguments)) {
|
||||
throw new ServiceCreationException("Unable to pass specified arguments to $entity[0].");
|
||||
} elseif (!function_exists($entity[1])) {
|
||||
throw new ServiceCreationException("Function $entity[1] doesn't exist.");
|
||||
}
|
||||
|
||||
$rf = new \ReflectionFunction($entity[1]);
|
||||
$this->addDependency($rf);
|
||||
$arguments = Helpers::autowireArguments($rf, $arguments, $this);
|
||||
|
||||
} else {
|
||||
if ($entity[0] instanceof Statement) {
|
||||
$entity[0] = $this->completeStatement($entity[0]);
|
||||
} elseif ($service = $this->getServiceName($entity[0])) { // service method
|
||||
$entity[0] = '@' . $service;
|
||||
}
|
||||
|
||||
if ($entity[1][0] === '$') { // property getter, setter or appender
|
||||
Validators::assert($arguments, 'list:0..1', "setup arguments for '" . Nette\Utils\Callback::toString($entity) . "'");
|
||||
if (!$arguments && substr($entity[1], -2) === '[]') {
|
||||
throw new ServiceCreationException("Missing argument for $entity[1].");
|
||||
}
|
||||
} elseif (
|
||||
$type = empty($service) || $entity[1] === 'create'
|
||||
? $this->resolveEntityType($entity[0])
|
||||
: $this->definitions[$service]->getType()
|
||||
) {
|
||||
$arguments = $this->autowireArguments($type, $entity[1], $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
array_walk_recursive($arguments, function (&$val) {
|
||||
if ($val instanceof Statement) {
|
||||
$val = $this->completeStatement($val);
|
||||
|
||||
} elseif ($val === $this) {
|
||||
trigger_error("Replace object ContainerBuilder in Statement arguments with '@container'.", E_USER_DEPRECATED);
|
||||
$val = self::literal('$this');
|
||||
|
||||
} elseif ($val instanceof ServiceDefinition) {
|
||||
$val = '@' . current(array_keys($this->getDefinitions(), $val, true));
|
||||
|
||||
} elseif (is_string($val) && strlen($val) > 1 && $val[0] === '@' && $val[1] !== '@') {
|
||||
$pair = explode('::', $val, 2);
|
||||
$name = $this->getServiceName($pair[0]);
|
||||
if (!isset($pair[1])) { // @service
|
||||
$val = '@' . $name;
|
||||
} elseif (preg_match('#^[A-Z][A-Z0-9_]*\z#', $pair[1], $m)) { // @service::CONSTANT
|
||||
$val = self::literal($this->getDefinition($name)->getType() . '::' . $pair[1]);
|
||||
} else { // @service::property
|
||||
$val = new Statement(['@' . $name, '$' . $pair[1]]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (ServiceCreationException $e) {
|
||||
if ((is_string($entity) || is_array($entity)) && !strpos($e->getMessage(), ' (used in')) {
|
||||
$desc = is_string($entity)
|
||||
? $entity . '::__construct()'
|
||||
: (is_string($entity[0]) ? ($entity[0] . '::') : '')
|
||||
. $entity[1] . (strpos($entity[1], '$') === false ? '()' : '');
|
||||
$e->setMessage($e->getMessage() . " (used in $desc)");
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return new Statement($entity, $arguments);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds item to the list of dependencies.
|
||||
* @param ReflectionClass|\ReflectionFunctionAbstract|string
|
||||
* @return static
|
||||
* @internal
|
||||
*/
|
||||
public function addDependency($dep)
|
||||
{
|
||||
$this->dependencies[] = $dep;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the list of dependencies.
|
||||
* @return array
|
||||
*/
|
||||
public function getDependencies()
|
||||
{
|
||||
return $this->dependencies;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expands %placeholders% in strings.
|
||||
* @return mixed
|
||||
* @deprecated
|
||||
*/
|
||||
public function expand($value)
|
||||
{
|
||||
return Helpers::expand($value, $this->parameters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Nette\PhpGenerator\PhpLiteral
|
||||
*/
|
||||
public static function literal($code, array $args = null)
|
||||
{
|
||||
return new Nette\PhpGenerator\PhpLiteral($args === null ? $code : PhpHelpers::formatArgs($code, $args));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|array Class, @service, [Class, member], [@service, member], [, globalFunc], [Statement, member]
|
||||
* @internal
|
||||
*/
|
||||
public function normalizeEntity($entity)
|
||||
{
|
||||
if (is_string($entity) && Strings::contains($entity, '::') && !Strings::contains($entity, '?')) { // Class::method -> [Class, method]
|
||||
$entity = explode('::', $entity);
|
||||
}
|
||||
|
||||
if (is_array($entity) && $entity[0] instanceof ServiceDefinition) { // [ServiceDefinition, ...] -> [@serviceName, ...]
|
||||
$entity[0] = '@' . current(array_keys($this->definitions, $entity[0], true));
|
||||
|
||||
} elseif ($entity instanceof ServiceDefinition) { // ServiceDefinition -> @serviceName
|
||||
$entity = '@' . current(array_keys($this->definitions, $entity, true));
|
||||
|
||||
} elseif (is_array($entity) && $entity[0] === $this) { // [$this, ...] -> [@container, ...]
|
||||
trigger_error("Replace object ContainerBuilder in Statement entity with '@container'.", E_USER_DEPRECATED);
|
||||
$entity[0] = '@' . self::THIS_CONTAINER;
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts @service or @\Class -> service name and checks its existence.
|
||||
* @return string of false, if argument is not service name
|
||||
* @internal
|
||||
*/
|
||||
public function getServiceName($arg)
|
||||
{
|
||||
if (!is_string($arg) || !preg_match('#^@[\w\\\\.][^:]*\z#', $arg)) {
|
||||
return false;
|
||||
}
|
||||
$service = substr($arg, 1);
|
||||
if ($service === self::THIS_SERVICE) {
|
||||
$service = $this->currentService;
|
||||
}
|
||||
if (Strings::contains($service, '\\')) {
|
||||
if ($this->classList === false) { // may be disabled by prepareClassList
|
||||
return $service;
|
||||
}
|
||||
$res = $this->getByType($service);
|
||||
if (!$res) {
|
||||
throw new ServiceCreationException("Reference to missing service of type $service.");
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
$service = isset($this->aliases[$service]) ? $this->aliases[$service] : $service;
|
||||
if (!isset($this->definitions[$service])) {
|
||||
throw new ServiceCreationException("Reference to missing service '$service'.");
|
||||
}
|
||||
return $service;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a list of arguments using autowiring.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
public function autowireArguments($class, $method, array $arguments)
|
||||
{
|
||||
$rc = new ReflectionClass($class);
|
||||
if (!$rc->hasMethod($method)) {
|
||||
if (!Nette\Utils\Arrays::isList($arguments)) {
|
||||
throw new ServiceCreationException("Unable to pass specified arguments to $class::$method().");
|
||||
}
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
$rm = $rc->getMethod($method);
|
||||
if (!$rm->isPublic()) {
|
||||
throw new ServiceCreationException("$class::$method() is not callable.");
|
||||
}
|
||||
$this->addDependency($rm);
|
||||
return Helpers::autowireArguments($rm, $arguments, $this);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function generateClasses($className = 'Container', $parentName = null)
|
||||
{
|
||||
trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
|
||||
return (new PhpGenerator($this))->generate($className);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function formatStatement(Statement $statement)
|
||||
{
|
||||
trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
|
||||
return (new PhpGenerator($this))->formatStatement($statement);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function formatPhp($statement, $args)
|
||||
{
|
||||
array_walk_recursive($args, function (&$val) {
|
||||
if ($val instanceof Statement) {
|
||||
$val = $this->completeStatement($val);
|
||||
|
||||
} elseif ($val === $this) {
|
||||
trigger_error("Replace object ContainerBuilder in Statement arguments with '@container'.", E_USER_DEPRECATED);
|
||||
$val = self::literal('$this');
|
||||
|
||||
} elseif ($val instanceof ServiceDefinition) {
|
||||
$val = '@' . current(array_keys($this->getDefinitions(), $val, true));
|
||||
}
|
||||
});
|
||||
return (new PhpGenerator($this))->formatPhp($statement, $args);
|
||||
}
|
||||
}
|
131
vendor/nette/di/src/DI/ContainerLoader.php
vendored
Normal file
131
vendor/nette/di/src/DI/ContainerLoader.php
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* DI container loader.
|
||||
*/
|
||||
class ContainerLoader
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @var bool */
|
||||
private $autoRebuild = false;
|
||||
|
||||
/** @var string */
|
||||
private $tempDirectory;
|
||||
|
||||
|
||||
public function __construct($tempDirectory, $autoRebuild = false)
|
||||
{
|
||||
$this->tempDirectory = $tempDirectory;
|
||||
$this->autoRebuild = $autoRebuild;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param callable function (Nette\DI\Compiler $compiler): string|null
|
||||
* @param mixed
|
||||
* @return string
|
||||
*/
|
||||
public function load($generator, $key = null)
|
||||
{
|
||||
if (!is_callable($generator)) { // back compatiblity
|
||||
trigger_error(__METHOD__ . ': order of arguments has been swapped.', E_USER_DEPRECATED);
|
||||
list($generator, $key) = [$key, $generator];
|
||||
}
|
||||
$class = $this->getClassName($key);
|
||||
if (!class_exists($class, false)) {
|
||||
$this->loadFile($class, $generator);
|
||||
}
|
||||
return $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClassName($key)
|
||||
{
|
||||
return 'Container_' . substr(md5(serialize($key)), 0, 10);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function loadFile($class, $generator)
|
||||
{
|
||||
$file = "$this->tempDirectory/$class.php";
|
||||
if (!$this->isExpired($file) && (@include $file) !== false) { // @ file may not exist
|
||||
return;
|
||||
}
|
||||
|
||||
Nette\Utils\FileSystem::createDir($this->tempDirectory);
|
||||
|
||||
$handle = @fopen("$file.lock", 'c+'); // @ is escalated to exception
|
||||
if (!$handle) {
|
||||
throw new Nette\IOException("Unable to create file '$file.lock'. " . error_get_last()['message']);
|
||||
} elseif (!@flock($handle, LOCK_EX)) { // @ is escalated to exception
|
||||
throw new Nette\IOException("Unable to acquire exclusive lock on '$file.lock'. " . error_get_last()['message']);
|
||||
}
|
||||
|
||||
if (!is_file($file) || $this->isExpired($file, $updatedMeta)) {
|
||||
if (isset($updatedMeta)) {
|
||||
$toWrite["$file.meta"] = $updatedMeta;
|
||||
} else {
|
||||
list($toWrite[$file], $toWrite["$file.meta"]) = $this->generate($class, $generator);
|
||||
}
|
||||
|
||||
foreach ($toWrite as $name => $content) {
|
||||
if (file_put_contents("$name.tmp", $content) !== strlen($content) || !rename("$name.tmp", $name)) {
|
||||
@unlink("$name.tmp"); // @ - file may not exist
|
||||
throw new Nette\IOException("Unable to create file '$name'.");
|
||||
} elseif (function_exists('opcache_invalidate')) {
|
||||
@opcache_invalidate($name, true); // @ can be restricted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((@include $file) === false) { // @ - error escalated to exception
|
||||
throw new Nette\IOException("Unable to include '$file'.");
|
||||
}
|
||||
flock($handle, LOCK_UN);
|
||||
}
|
||||
|
||||
|
||||
private function isExpired($file, &$updatedMeta = null)
|
||||
{
|
||||
if ($this->autoRebuild) {
|
||||
$meta = @unserialize((string) file_get_contents("$file.meta")); // @ - file may not exist
|
||||
$orig = $meta[2];
|
||||
return empty($meta[0])
|
||||
|| DependencyChecker::isExpired(...$meta)
|
||||
|| ($orig !== $meta[2] && $updatedMeta = serialize($meta));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array of (code, file[])
|
||||
*/
|
||||
protected function generate($class, $generator)
|
||||
{
|
||||
$compiler = new Compiler;
|
||||
$compiler->setClassName($class);
|
||||
$code = call_user_func_array($generator, [&$compiler]) ?: $compiler->compile();
|
||||
return [
|
||||
"<?php\n$code",
|
||||
serialize($compiler->exportDependencies()),
|
||||
];
|
||||
}
|
||||
}
|
176
vendor/nette/di/src/DI/DependencyChecker.php
vendored
Normal file
176
vendor/nette/di/src/DI/DependencyChecker.php
vendored
Normal file
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
use Nette\Utils\Reflection;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Cache dependencies checker.
|
||||
*/
|
||||
class DependencyChecker
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
const VERSION = 1;
|
||||
|
||||
/** @var array of ReflectionClass|\ReflectionFunctionAbstract|string */
|
||||
private $dependencies = [];
|
||||
|
||||
|
||||
/**
|
||||
* Adds dependencies to the list.
|
||||
* @return static
|
||||
*/
|
||||
public function add(array $deps)
|
||||
{
|
||||
$this->dependencies = array_merge($this->dependencies, $deps);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exports dependencies.
|
||||
* @return array
|
||||
*/
|
||||
public function export()
|
||||
{
|
||||
$files = $phpFiles = $classes = $functions = [];
|
||||
foreach ($this->dependencies as $dep) {
|
||||
if (is_string($dep)) {
|
||||
$files[] = $dep;
|
||||
|
||||
} elseif ($dep instanceof ReflectionClass) {
|
||||
if (empty($classes[$name = $dep->getName()])) {
|
||||
$all = [$name] + class_parents($name) + class_implements($name);
|
||||
foreach ($all as &$item) {
|
||||
$all += class_uses($item);
|
||||
$phpFiles[] = (new ReflectionClass($item))->getFileName();
|
||||
$classes[$item] = true;
|
||||
}
|
||||
}
|
||||
|
||||
} elseif ($dep instanceof \ReflectionFunctionAbstract) {
|
||||
$phpFiles[] = $dep->getFileName();
|
||||
$functions[] = Reflection::toString($dep);
|
||||
|
||||
} else {
|
||||
throw new Nette\InvalidStateException('Unexpected dependency ' . gettype($dep));
|
||||
}
|
||||
}
|
||||
|
||||
$classes = array_keys($classes);
|
||||
$functions = array_unique($functions, SORT_REGULAR);
|
||||
$hash = self::calculateHash($classes, $functions);
|
||||
$files = @array_map('filemtime', array_combine($files, $files)); // @ - file may not exist
|
||||
$phpFiles = @array_map('filemtime', array_combine($phpFiles, $phpFiles)); // @ - file may not exist
|
||||
return [self::VERSION, $files, $phpFiles, $classes, $functions, $hash];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Are dependencies expired?
|
||||
* @return bool
|
||||
*/
|
||||
public static function isExpired($version, $files, &$phpFiles, $classes, $functions, $hash)
|
||||
{
|
||||
$current = @array_map('filemtime', array_combine($tmp = array_keys($files), $tmp)); // @ - files may not exist
|
||||
$origPhpFiles = $phpFiles;
|
||||
$phpFiles = @array_map('filemtime', array_combine($tmp = array_keys($phpFiles), $tmp)); // @ - files may not exist
|
||||
return $version !== self::VERSION
|
||||
|| $files !== $current
|
||||
|| ($phpFiles !== $origPhpFiles && $hash !== self::calculateHash($classes, $functions));
|
||||
}
|
||||
|
||||
|
||||
private static function calculateHash($classes, $functions)
|
||||
{
|
||||
$hash = [];
|
||||
foreach ($classes as $name) {
|
||||
try {
|
||||
$class = new ReflectionClass($name);
|
||||
} catch (\ReflectionException $e) {
|
||||
return;
|
||||
}
|
||||
$hash[] = [
|
||||
$name,
|
||||
Reflection::getUseStatements($class),
|
||||
$class->isAbstract(),
|
||||
get_parent_class($name),
|
||||
class_implements($name),
|
||||
class_uses($name),
|
||||
];
|
||||
|
||||
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
|
||||
if ($prop->getDeclaringClass() == $class) { // intentionally ==
|
||||
$hash[] = [$name, $prop->getName(), $prop->getDocComment()];
|
||||
}
|
||||
}
|
||||
foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
|
||||
if ($method->getDeclaringClass() == $class) { // intentionally ==
|
||||
$hash[] = [
|
||||
$name,
|
||||
$method->getName(),
|
||||
$method->getDocComment(),
|
||||
self::hashParameters($method),
|
||||
PHP_VERSION_ID >= 70000 && $method->hasReturnType()
|
||||
? [(string) $method->getReturnType(), $method->getReturnType()->allowsNull()]
|
||||
: null,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$flip = array_flip($classes);
|
||||
foreach ($functions as $name) {
|
||||
try {
|
||||
$method = strpos($name, '::') ? new ReflectionMethod($name) : new \ReflectionFunction($name);
|
||||
} catch (\ReflectionException $e) {
|
||||
return;
|
||||
}
|
||||
$class = $method instanceof ReflectionMethod ? $method->getDeclaringClass() : null;
|
||||
if ($class && isset($flip[$class->getName()])) {
|
||||
continue;
|
||||
}
|
||||
$hash[] = [
|
||||
$name,
|
||||
$class ? Reflection::getUseStatements($method->getDeclaringClass()) : null,
|
||||
$method->getDocComment(),
|
||||
self::hashParameters($method),
|
||||
PHP_VERSION_ID >= 70000 && $method->hasReturnType()
|
||||
? [(string) $method->getReturnType(), $method->getReturnType()->allowsNull()]
|
||||
: null,
|
||||
];
|
||||
}
|
||||
|
||||
return md5(serialize($hash));
|
||||
}
|
||||
|
||||
|
||||
private static function hashParameters(\ReflectionFunctionAbstract $method)
|
||||
{
|
||||
$res = [];
|
||||
if (PHP_VERSION_ID < 70000 && $method->getNumberOfParameters() && $method->getFileName()) {
|
||||
$res[] = file($method->getFileName())[$method->getStartLine() - 1];
|
||||
}
|
||||
foreach ($method->getParameters() as $param) {
|
||||
$res[] = [
|
||||
$param->getName(),
|
||||
PHP_VERSION_ID >= 70000 ? [Reflection::getParameterType($param), $param->allowsNull()] : null,
|
||||
$param->isVariadic(),
|
||||
$param->isDefaultValueAvailable()
|
||||
? [Reflection::getParameterDefaultValue($param)]
|
||||
: null,
|
||||
];
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
24
vendor/nette/di/src/DI/Extensions/ConstantsExtension.php
vendored
Normal file
24
vendor/nette/di/src/DI/Extensions/ConstantsExtension.php
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Extensions;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Constant definitions.
|
||||
*/
|
||||
class ConstantsExtension extends Nette\DI\CompilerExtension
|
||||
{
|
||||
public function afterCompile(Nette\PhpGenerator\ClassType $class)
|
||||
{
|
||||
foreach ($this->getConfig() as $name => $value) {
|
||||
$class->getMethod('initialize')->addBody('define(?, ?);', [$name, $value]);
|
||||
}
|
||||
}
|
||||
}
|
67
vendor/nette/di/src/DI/Extensions/DIExtension.php
vendored
Normal file
67
vendor/nette/di/src/DI/Extensions/DIExtension.php
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Extensions;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* DI extension.
|
||||
*/
|
||||
class DIExtension extends Nette\DI\CompilerExtension
|
||||
{
|
||||
public $defaults = [
|
||||
'debugger' => true,
|
||||
'accessors' => false,
|
||||
'excluded' => [],
|
||||
'parentClass' => null,
|
||||
];
|
||||
|
||||
/** @var bool */
|
||||
private $debugMode;
|
||||
|
||||
/** @var int */
|
||||
private $time;
|
||||
|
||||
|
||||
public function __construct($debugMode = false)
|
||||
{
|
||||
$this->debugMode = $debugMode;
|
||||
$this->time = microtime(true);
|
||||
}
|
||||
|
||||
|
||||
public function loadConfiguration()
|
||||
{
|
||||
$config = $this->validateConfig($this->defaults);
|
||||
$builder = $this->getContainerBuilder();
|
||||
$builder->addExcludedClasses($config['excluded']);
|
||||
}
|
||||
|
||||
|
||||
public function afterCompile(Nette\PhpGenerator\ClassType $class)
|
||||
{
|
||||
if ($this->config['parentClass']) {
|
||||
$class->setExtends($this->config['parentClass']);
|
||||
}
|
||||
|
||||
$initialize = $class->getMethod('initialize');
|
||||
$builder = $this->getContainerBuilder();
|
||||
|
||||
if ($this->debugMode && $this->config['debugger']) {
|
||||
Nette\Bridges\DITracy\ContainerPanel::$compilationTime = $this->time;
|
||||
$initialize->addBody($builder->formatPhp('?;', [
|
||||
new Nette\DI\Statement('@Tracy\Bar::addPanel', [new Nette\DI\Statement(Nette\Bridges\DITracy\ContainerPanel::class)]),
|
||||
]));
|
||||
}
|
||||
|
||||
foreach (array_filter($builder->findByTag('run')) as $name => $on) {
|
||||
$initialize->addBody('$this->getService(?);', [$name]);
|
||||
}
|
||||
}
|
||||
}
|
68
vendor/nette/di/src/DI/Extensions/DecoratorExtension.php
vendored
Normal file
68
vendor/nette/di/src/DI/Extensions/DecoratorExtension.php
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Extensions;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Decorators for services.
|
||||
*/
|
||||
class DecoratorExtension extends Nette\DI\CompilerExtension
|
||||
{
|
||||
public $defaults = [
|
||||
'setup' => [],
|
||||
'tags' => [],
|
||||
'inject' => null,
|
||||
];
|
||||
|
||||
|
||||
public function beforeCompile()
|
||||
{
|
||||
foreach ($this->getConfig() as $type => $info) {
|
||||
$info = $this->validateConfig($this->defaults, $info, $this->prefix($type));
|
||||
if ($info['inject'] !== null) {
|
||||
$info['tags'][InjectExtension::TAG_INJECT] = $info['inject'];
|
||||
}
|
||||
$info = Nette\DI\Helpers::filterArguments($info);
|
||||
$this->addSetups($type, (array) $info['setup']);
|
||||
$this->addTags($type, (array) $info['tags']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function addSetups($type, array $setups)
|
||||
{
|
||||
foreach ($this->findByType($type) as $def) {
|
||||
foreach ($setups as $setup) {
|
||||
if (is_array($setup)) {
|
||||
$setup = new Nette\DI\Statement(key($setup), array_values($setup));
|
||||
}
|
||||
$def->addSetup($setup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function addTags($type, array $tags)
|
||||
{
|
||||
$tags = Nette\Utils\Arrays::normalize($tags, true);
|
||||
foreach ($this->findByType($type) as $def) {
|
||||
$def->setTags($def->getTags() + $tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function findByType($type)
|
||||
{
|
||||
return array_filter($this->getContainerBuilder()->getDefinitions(), function ($def) use ($type) {
|
||||
return is_a($def->getImplement(), $type, true)
|
||||
|| ($def->getImplementMode() !== $def::IMPLEMENT_MODE_GET && is_a($def->getType(), $type, true));
|
||||
});
|
||||
}
|
||||
}
|
32
vendor/nette/di/src/DI/Extensions/ExtensionsExtension.php
vendored
Normal file
32
vendor/nette/di/src/DI/Extensions/ExtensionsExtension.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Extensions;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Enables registration of other extensions in $config file
|
||||
*/
|
||||
class ExtensionsExtension extends Nette\DI\CompilerExtension
|
||||
{
|
||||
public function loadConfiguration()
|
||||
{
|
||||
foreach ($this->getConfig() as $name => $class) {
|
||||
if (is_int($name)) {
|
||||
$name = null;
|
||||
}
|
||||
if ($class instanceof Nette\DI\Statement) {
|
||||
$rc = new \ReflectionClass($class->getEntity());
|
||||
$this->compiler->addExtension($name, $rc->newInstanceArgs($class->arguments));
|
||||
} else {
|
||||
$this->compiler->addExtension($name, new $class);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
144
vendor/nette/di/src/DI/Extensions/InjectExtension.php
vendored
Normal file
144
vendor/nette/di/src/DI/Extensions/InjectExtension.php
vendored
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Extensions;
|
||||
|
||||
use Nette;
|
||||
use Nette\DI;
|
||||
use Nette\Utils\Reflection;
|
||||
|
||||
|
||||
/**
|
||||
* Calls inject methods and fills @inject properties.
|
||||
*/
|
||||
class InjectExtension extends DI\CompilerExtension
|
||||
{
|
||||
const TAG_INJECT = 'inject';
|
||||
|
||||
|
||||
public function beforeCompile()
|
||||
{
|
||||
foreach ($this->getContainerBuilder()->getDefinitions() as $def) {
|
||||
if ($def->getTag(self::TAG_INJECT) && $def->getType()) {
|
||||
$this->updateDefinition($def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function updateDefinition(DI\ServiceDefinition $def)
|
||||
{
|
||||
$class = $def->getType();
|
||||
$setups = $def->getSetup();
|
||||
|
||||
foreach (self::getInjectProperties($class) as $property => $type) {
|
||||
$builder = $this->getContainerBuilder();
|
||||
$inject = new DI\Statement('$' . $property, ['@\\' . ltrim($type, '\\')]);
|
||||
foreach ($setups as $key => $setup) {
|
||||
if ($setup->getEntity() === $inject->getEntity()) {
|
||||
$inject = $setup;
|
||||
$builder = null;
|
||||
unset($setups[$key]);
|
||||
}
|
||||
}
|
||||
self::checkType($class, $property, $type, $builder);
|
||||
array_unshift($setups, $inject);
|
||||
}
|
||||
|
||||
foreach (array_reverse(self::getInjectMethods($def->getType())) as $method) {
|
||||
$inject = new DI\Statement($method);
|
||||
foreach ($setups as $key => $setup) {
|
||||
if ($setup->getEntity() === $inject->getEntity()) {
|
||||
$inject = $setup;
|
||||
unset($setups[$key]);
|
||||
}
|
||||
}
|
||||
array_unshift($setups, $inject);
|
||||
}
|
||||
|
||||
$def->setSetup($setups);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates list of inject methods.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
public static function getInjectMethods($class)
|
||||
{
|
||||
$res = [];
|
||||
foreach (get_class_methods($class) as $name) {
|
||||
if (substr($name, 0, 6) === 'inject') {
|
||||
$res[$name] = (new \ReflectionMethod($class, $name))->getDeclaringClass()->getName();
|
||||
}
|
||||
}
|
||||
uksort($res, function ($a, $b) use ($res) {
|
||||
return $res[$a] === $res[$b]
|
||||
? strcmp($a, $b)
|
||||
: (is_a($res[$a], $res[$b], true) ? 1 : -1);
|
||||
});
|
||||
return array_keys($res);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates list of properties with annotation @inject.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
public static function getInjectProperties($class)
|
||||
{
|
||||
$res = [];
|
||||
foreach (get_class_vars($class) as $name => $foo) {
|
||||
$rp = new \ReflectionProperty($class, $name);
|
||||
if (DI\Helpers::parseAnnotation($rp, 'inject') !== null) {
|
||||
if ($type = DI\Helpers::parseAnnotation($rp, 'var')) {
|
||||
$type = Reflection::expandClassName($type, Reflection::getPropertyDeclaringClass($rp));
|
||||
}
|
||||
$res[$name] = $type;
|
||||
}
|
||||
}
|
||||
ksort($res);
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls all methods starting with with "inject" using autowiring.
|
||||
* @return void
|
||||
*/
|
||||
public static function callInjects(DI\Container $container, $service)
|
||||
{
|
||||
if (!is_object($service)) {
|
||||
throw new Nette\InvalidArgumentException(sprintf('Service must be object, %s given.', gettype($service)));
|
||||
}
|
||||
|
||||
foreach (self::getInjectMethods($service) as $method) {
|
||||
$container->callMethod([$service, $method]);
|
||||
}
|
||||
|
||||
foreach (self::getInjectProperties(get_class($service)) as $property => $type) {
|
||||
self::checkType($service, $property, $type, $container);
|
||||
$service->$property = $container->getByType($type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @internal */
|
||||
private static function checkType($class, $name, $type, $container = null)
|
||||
{
|
||||
$propName = Reflection::toString(new \ReflectionProperty($class, $name));
|
||||
if (!$type) {
|
||||
throw new Nette\InvalidStateException("Property $propName has no @var annotation.");
|
||||
} elseif (!class_exists($type) && !interface_exists($type)) {
|
||||
throw new Nette\InvalidStateException("Class or interface '$type' used in @var annotation at $propName not found. Check annotation and 'use' statements.");
|
||||
} elseif ($container && !$container->getByType($type, false)) {
|
||||
throw new Nette\InvalidStateException("Service of type $type used in @var annotation at $propName not found. Did you register it in configuration file?");
|
||||
}
|
||||
}
|
||||
}
|
48
vendor/nette/di/src/DI/Extensions/PhpExtension.php
vendored
Normal file
48
vendor/nette/di/src/DI/Extensions/PhpExtension.php
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI\Extensions;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* PHP directives definition.
|
||||
*/
|
||||
class PhpExtension extends Nette\DI\CompilerExtension
|
||||
{
|
||||
public function afterCompile(Nette\PhpGenerator\ClassType $class)
|
||||
{
|
||||
$initialize = $class->getMethod('initialize');
|
||||
foreach ($this->getConfig() as $name => $value) {
|
||||
if ($value === null) {
|
||||
continue;
|
||||
|
||||
} elseif (!is_scalar($value)) {
|
||||
throw new Nette\InvalidStateException("Configuration value for directive '$name' is not scalar.");
|
||||
|
||||
} elseif ($name === 'include_path') {
|
||||
$initialize->addBody('set_include_path(?);', [str_replace(';', PATH_SEPARATOR, $value)]);
|
||||
|
||||
} elseif ($name === 'ignore_user_abort') {
|
||||
$initialize->addBody('ignore_user_abort(?);', [$value]);
|
||||
|
||||
} elseif ($name === 'max_execution_time') {
|
||||
$initialize->addBody('set_time_limit(?);', [$value]);
|
||||
|
||||
} elseif ($name === 'date.timezone') {
|
||||
$initialize->addBody('date_default_timezone_set(?);', [$value]);
|
||||
|
||||
} elseif (function_exists('ini_set')) {
|
||||
$initialize->addBody('ini_set(?, ?);', [$name, $value]);
|
||||
|
||||
} elseif (ini_get($name) != $value) { // intentionally ==
|
||||
throw new Nette\NotSupportedException('Required function ini_set() is disabled.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
255
vendor/nette/di/src/DI/Helpers.php
vendored
Normal file
255
vendor/nette/di/src/DI/Helpers.php
vendored
Normal file
|
@ -0,0 +1,255 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
use Nette\PhpGenerator\PhpLiteral;
|
||||
use Nette\Utils\Reflection;
|
||||
|
||||
|
||||
/**
|
||||
* The DI helpers.
|
||||
* @internal
|
||||
*/
|
||||
class Helpers
|
||||
{
|
||||
use Nette\StaticClass;
|
||||
|
||||
/**
|
||||
* Expands %placeholders%.
|
||||
* @param mixed
|
||||
* @param array
|
||||
* @param bool|array
|
||||
* @return mixed
|
||||
* @throws Nette\InvalidArgumentException
|
||||
*/
|
||||
public static function expand($var, array $params, $recursive = false)
|
||||
{
|
||||
if (is_array($var)) {
|
||||
$res = [];
|
||||
foreach ($var as $key => $val) {
|
||||
$res[$key] = self::expand($val, $params, $recursive);
|
||||
}
|
||||
return $res;
|
||||
|
||||
} elseif ($var instanceof Statement) {
|
||||
return new Statement(self::expand($var->getEntity(), $params, $recursive), self::expand($var->arguments, $params, $recursive));
|
||||
|
||||
} elseif (!is_string($var)) {
|
||||
return $var;
|
||||
}
|
||||
|
||||
$parts = preg_split('#%([\w.-]*)%#i', $var, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$res = [];
|
||||
$php = false;
|
||||
foreach ($parts as $n => $part) {
|
||||
if ($n % 2 === 0) {
|
||||
$res[] = $part;
|
||||
|
||||
} elseif ($part === '') {
|
||||
$res[] = '%';
|
||||
|
||||
} elseif (isset($recursive[$part])) {
|
||||
throw new Nette\InvalidArgumentException(sprintf('Circular reference detected for variables: %s.', implode(', ', array_keys($recursive))));
|
||||
|
||||
} else {
|
||||
$val = $params;
|
||||
foreach (explode('.', $part) as $key) {
|
||||
if (is_array($val) && array_key_exists($key, $val)) {
|
||||
$val = $val[$key];
|
||||
} elseif ($val instanceof PhpLiteral) {
|
||||
$val = new PhpLiteral($val . '[' . var_export($key, true) . ']');
|
||||
} else {
|
||||
throw new Nette\InvalidArgumentException("Missing parameter '$part'.");
|
||||
}
|
||||
}
|
||||
if ($recursive) {
|
||||
$val = self::expand($val, $params, (is_array($recursive) ? $recursive : []) + [$part => 1]);
|
||||
}
|
||||
if (strlen($part) + 2 === strlen($var)) {
|
||||
return $val;
|
||||
}
|
||||
if ($val instanceof PhpLiteral) {
|
||||
$php = true;
|
||||
} elseif (!is_scalar($val)) {
|
||||
throw new Nette\InvalidArgumentException("Unable to concatenate non-scalar parameter '$part' into '$var'.");
|
||||
}
|
||||
$res[] = $val;
|
||||
}
|
||||
}
|
||||
if ($php) {
|
||||
$res = array_filter($res, function ($val) { return $val !== ''; });
|
||||
$res = array_map(function ($val) { return $val instanceof PhpLiteral ? "($val)" : var_export((string) $val, true); }, $res);
|
||||
return new PhpLiteral(implode(' . ', $res));
|
||||
}
|
||||
return implode('', $res);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates list of arguments using autowiring.
|
||||
* @return array
|
||||
* @throws ServiceCreationException
|
||||
*/
|
||||
public static function autowireArguments(\ReflectionFunctionAbstract $method, array $arguments, $container)
|
||||
{
|
||||
$optCount = 0;
|
||||
$num = -1;
|
||||
$res = [];
|
||||
$methodName = Reflection::toString($method) . '()';
|
||||
|
||||
foreach ($method->getParameters() as $num => $parameter) {
|
||||
$paramName = $parameter->getName();
|
||||
if (!$parameter->isVariadic() && array_key_exists($paramName, $arguments)) {
|
||||
$res[$num] = $arguments[$paramName];
|
||||
unset($arguments[$paramName], $arguments[$num]);
|
||||
$optCount = 0;
|
||||
|
||||
} elseif (array_key_exists($num, $arguments)) {
|
||||
$res[$num] = $arguments[$num];
|
||||
unset($arguments[$num]);
|
||||
$optCount = 0;
|
||||
|
||||
} elseif (($type = Reflection::getParameterType($parameter)) && !Reflection::isBuiltinType($type)) {
|
||||
try {
|
||||
$res[$num] = $container->getByType($type, false);
|
||||
} catch (ServiceCreationException $e) {
|
||||
throw new ServiceCreationException("{$e->getMessage()} (needed by $$paramName in $methodName)", 0, $e);
|
||||
}
|
||||
if ($res[$num] === null) {
|
||||
if ($parameter->allowsNull()) {
|
||||
$optCount++;
|
||||
} elseif (class_exists($type) || interface_exists($type)) {
|
||||
throw new ServiceCreationException("Service of type $type needed by $$paramName in $methodName not found. Did you register it in configuration file?");
|
||||
} else {
|
||||
throw new ServiceCreationException("Class $type needed by $$paramName in $methodName not found. Check type hint and 'use' statements.");
|
||||
}
|
||||
} else {
|
||||
if ($container instanceof ContainerBuilder) {
|
||||
$res[$num] = '@' . $res[$num];
|
||||
}
|
||||
$optCount = 0;
|
||||
}
|
||||
|
||||
} elseif (($type && $parameter->allowsNull()) || $parameter->isOptional() || $parameter->isDefaultValueAvailable()) {
|
||||
// !optional + defaultAvailable = func($a = null, $b) since 5.4.7
|
||||
// optional + !defaultAvailable = i.e. Exception::__construct, mysqli::mysqli, ...
|
||||
$res[$num] = $parameter->isDefaultValueAvailable() ? Reflection::getParameterDefaultValue($parameter) : null;
|
||||
$optCount++;
|
||||
|
||||
} else {
|
||||
throw new ServiceCreationException("Parameter $$paramName in $methodName has no class type hint or default value, so its value must be specified.");
|
||||
}
|
||||
}
|
||||
|
||||
// extra parameters
|
||||
while (array_key_exists(++$num, $arguments)) {
|
||||
$res[$num] = $arguments[$num];
|
||||
unset($arguments[$num]);
|
||||
$optCount = 0;
|
||||
}
|
||||
if ($arguments) {
|
||||
throw new ServiceCreationException("Unable to pass specified arguments to $methodName.");
|
||||
}
|
||||
|
||||
return $optCount ? array_slice($res, 0, -$optCount) : $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes ... and process constants recursively.
|
||||
* @return array
|
||||
*/
|
||||
public static function filterArguments(array $args)
|
||||
{
|
||||
foreach ($args as $k => $v) {
|
||||
if ($v === '...') {
|
||||
unset($args[$k]);
|
||||
} elseif (is_string($v) && preg_match('#^[\w\\\\]*::[A-Z][A-Z0-9_]*\z#', $v, $m)) {
|
||||
$args[$k] = constant(ltrim($v, ':'));
|
||||
} elseif (is_array($v)) {
|
||||
$args[$k] = self::filterArguments($v);
|
||||
} elseif ($v instanceof Statement) {
|
||||
$tmp = self::filterArguments([$v->getEntity()]);
|
||||
$args[$k] = new Statement($tmp[0], self::filterArguments($v->arguments));
|
||||
}
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replaces @extension with real extension name in service definition.
|
||||
* @param mixed
|
||||
* @param string
|
||||
* @return mixed
|
||||
*/
|
||||
public static function prefixServiceName($config, $namespace)
|
||||
{
|
||||
if (is_string($config)) {
|
||||
if (strncmp($config, '@extension.', 10) === 0) {
|
||||
$config = '@' . $namespace . '.' . substr($config, 11);
|
||||
}
|
||||
} elseif ($config instanceof Statement) {
|
||||
return new Statement(
|
||||
self::prefixServiceName($config->getEntity(), $namespace),
|
||||
self::prefixServiceName($config->arguments, $namespace)
|
||||
);
|
||||
} elseif (is_array($config)) {
|
||||
foreach ($config as &$val) {
|
||||
$val = self::prefixServiceName($val, $namespace);
|
||||
}
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an annotation value.
|
||||
* @return string|null
|
||||
*/
|
||||
public static function parseAnnotation(\Reflector $ref, $name)
|
||||
{
|
||||
if (!Reflection::areCommentsAvailable()) {
|
||||
throw new Nette\InvalidStateException('You have to enable phpDoc comments in opcode cache.');
|
||||
}
|
||||
$name = preg_quote($name, '#');
|
||||
if ($ref->getDocComment() && preg_match("#[\\s*]@$name(?:\\s++([^@]\\S*)?|$)#", trim($ref->getDocComment(), '/*'), $m)) {
|
||||
return isset($m[1]) ? $m[1] : '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getReturnType(\ReflectionFunctionAbstract $func)
|
||||
{
|
||||
if ($type = Reflection::getReturnType($func)) {
|
||||
return $type;
|
||||
} elseif ($type = preg_replace('#[|\s].*#', '', (string) self::parseAnnotation($func, 'return'))) {
|
||||
if ($type === 'object' || $type === 'mixed') {
|
||||
return null;
|
||||
} elseif ($func instanceof \ReflectionMethod) {
|
||||
return $type === 'static' || $type === '$this'
|
||||
? $func->getDeclaringClass()->getName()
|
||||
: Reflection::expandClassName($type, $func->getDeclaringClass());
|
||||
} else {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function normalizeClass($type)
|
||||
{
|
||||
return class_exists($type) || interface_exists($type)
|
||||
? (new \ReflectionClass($type))->getName()
|
||||
: $type;
|
||||
}
|
||||
}
|
275
vendor/nette/di/src/DI/PhpGenerator.php
vendored
Normal file
275
vendor/nette/di/src/DI/PhpGenerator.php
vendored
Normal file
|
@ -0,0 +1,275 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
use Nette\PhpGenerator\Helpers as PhpHelpers;
|
||||
use Nette\PhpGenerator\PhpLiteral;
|
||||
use Nette\Utils\Reflection;
|
||||
use Nette\Utils\Strings;
|
||||
|
||||
|
||||
/**
|
||||
* Container PHP code generator.
|
||||
*/
|
||||
class PhpGenerator
|
||||
{
|
||||
/** @var ContainerBuilder */
|
||||
private $builder;
|
||||
|
||||
/** @var string */
|
||||
private $className;
|
||||
|
||||
/** @var Nette\PhpGenerator\ClassType[] */
|
||||
private $generatedClasses = [];
|
||||
|
||||
/** @var string */
|
||||
private $currentService;
|
||||
|
||||
|
||||
public function __construct(ContainerBuilder $builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates PHP classes. First class is the container.
|
||||
* @return Nette\PhpGenerator\ClassType[]
|
||||
*/
|
||||
public function generate($className)
|
||||
{
|
||||
$this->builder->complete();
|
||||
|
||||
$this->generatedClasses = [];
|
||||
$this->className = $className;
|
||||
$containerClass = $this->generatedClasses[] = new Nette\PhpGenerator\ClassType($this->className);
|
||||
$containerClass->setExtends(Container::class);
|
||||
$containerClass->addMethod('__construct')
|
||||
->addBody('$this->parameters = $params;')
|
||||
->addBody('$this->parameters += ?;', [$this->builder->parameters])
|
||||
->addParameter('params', [])
|
||||
->setTypeHint('array');
|
||||
|
||||
$definitions = $this->builder->getDefinitions();
|
||||
ksort($definitions);
|
||||
|
||||
$meta = $containerClass->addProperty('meta')
|
||||
->setVisibility('protected')
|
||||
->setValue([Container::TYPES => $this->builder->getClassList()]);
|
||||
|
||||
foreach ($definitions as $name => $def) {
|
||||
$meta->value[Container::SERVICES][$name] = $def->getImplement() ?: $def->getType() ?: null;
|
||||
foreach ($def->getTags() as $tag => $value) {
|
||||
$meta->value[Container::TAGS][$tag][$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($definitions as $name => $def) {
|
||||
try {
|
||||
$name = (string) $name;
|
||||
$methodName = Container::getMethodName($name);
|
||||
if (!PhpHelpers::isIdentifier($methodName)) {
|
||||
throw new ServiceCreationException('Name contains invalid characters.');
|
||||
}
|
||||
$containerClass->addMethod($methodName)
|
||||
->addComment(PHP_VERSION_ID < 70000 ? '@return ' . ($def->getImplement() ?: $def->getType()) : '')
|
||||
->setReturnType(PHP_VERSION_ID >= 70000 ? ($def->getImplement() ?: $def->getType()) : null)
|
||||
->setBody($name === ContainerBuilder::THIS_CONTAINER ? 'return $this;' : $this->generateService($name))
|
||||
->setParameters($def->getImplement() ? [] : $this->convertParameters($def->parameters));
|
||||
} catch (\Exception $e) {
|
||||
throw new ServiceCreationException("Service '$name': " . $e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
$aliases = $this->builder->getAliases();
|
||||
ksort($aliases);
|
||||
$meta->value[Container::ALIASES] = $aliases;
|
||||
|
||||
return $this->generatedClasses;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates body of service method.
|
||||
* @return string
|
||||
*/
|
||||
private function generateService($name)
|
||||
{
|
||||
$def = $this->builder->getDefinition($name);
|
||||
|
||||
if ($def->isDynamic()) {
|
||||
return PhpHelpers::formatArgs('throw new Nette\\DI\\ServiceCreationException(?);',
|
||||
["Unable to create dynamic service '$name', it must be added using addService()"]
|
||||
);
|
||||
}
|
||||
|
||||
$entity = $def->getFactory()->getEntity();
|
||||
$serviceRef = $this->builder->getServiceName($entity);
|
||||
$factory = $serviceRef && !$def->getFactory()->arguments && !$def->getSetup() && $def->getImplementMode() !== $def::IMPLEMENT_MODE_CREATE
|
||||
? new Statement(['@' . ContainerBuilder::THIS_CONTAINER, 'getService'], [$serviceRef])
|
||||
: $def->getFactory();
|
||||
|
||||
$this->currentService = null;
|
||||
$code = '$service = ' . $this->formatStatement($factory) . ";\n";
|
||||
|
||||
if (
|
||||
(PHP_VERSION_ID < 70000 || $def->getSetup())
|
||||
&& ($type = $def->getType())
|
||||
&& !$serviceRef && $type !== $entity
|
||||
&& !(is_string($entity) && preg_match('#^[\w\\\\]+\z#', $entity) && is_subclass_of($entity, $type))
|
||||
) {
|
||||
$code .= PhpHelpers::formatArgs("if (!\$service instanceof $type) {\n"
|
||||
. "\tthrow new Nette\\UnexpectedValueException(?);\n}\n",
|
||||
["Unable to create service '$name', value returned by factory is not $type type."]
|
||||
);
|
||||
}
|
||||
|
||||
$this->currentService = $name;
|
||||
foreach ($def->getSetup() as $setup) {
|
||||
$code .= $this->formatStatement($setup) . ";\n";
|
||||
}
|
||||
|
||||
$code .= 'return $service;';
|
||||
|
||||
if (!$def->getImplement()) {
|
||||
return $code;
|
||||
}
|
||||
|
||||
$factoryClass = (new Nette\PhpGenerator\ClassType)
|
||||
->addImplement($def->getImplement());
|
||||
|
||||
$factoryClass->addProperty('container')
|
||||
->setVisibility('private');
|
||||
|
||||
$factoryClass->addMethod('__construct')
|
||||
->addBody('$this->container = $container;')
|
||||
->addParameter('container')
|
||||
->setTypeHint($this->className);
|
||||
|
||||
$rm = new \ReflectionMethod($def->getImplement(), $def->getImplementMode());
|
||||
|
||||
$factoryClass->addMethod($def->getImplementMode())
|
||||
->setParameters($this->convertParameters($def->parameters))
|
||||
->setBody(str_replace('$this', '$this->container', $code))
|
||||
->setReturnType(PHP_VERSION_ID >= 70000 ? (Reflection::getReturnType($rm) ?: $def->getType()) : null);
|
||||
|
||||
if (PHP_VERSION_ID < 70000) {
|
||||
$this->generatedClasses[] = $factoryClass;
|
||||
$factoryClass->setName(str_replace(['\\', '.'], '_', "{$this->className}_{$def->getImplement()}Impl_{$name}"));
|
||||
return "return new {$factoryClass->getName()}(\$this);";
|
||||
}
|
||||
|
||||
return 'return new class ($this) ' . $factoryClass . ';';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats PHP code for class instantiating, function calling or property setting in PHP.
|
||||
* @return string
|
||||
*/
|
||||
private function formatStatement(Statement $statement)
|
||||
{
|
||||
$entity = $statement->getEntity();
|
||||
$arguments = $statement->arguments;
|
||||
|
||||
if (is_string($entity) && Strings::contains($entity, '?')) { // PHP literal
|
||||
return $this->formatPhp($entity, $arguments);
|
||||
|
||||
} elseif ($service = $this->builder->getServiceName($entity)) { // factory calling
|
||||
return $this->formatPhp('$this->?(...?)', [Container::getMethodName($service), $arguments]);
|
||||
|
||||
} elseif ($entity === 'not') { // operator
|
||||
return $this->formatPhp('!?', [$arguments[0]]);
|
||||
|
||||
} elseif (is_string($entity)) { // class name
|
||||
return $this->formatPhp("new $entity" . ($arguments ? '(...?)' : ''), $arguments ? [$arguments] : []);
|
||||
|
||||
} elseif ($entity[0] === '') { // globalFunc
|
||||
return $this->formatPhp("$entity[1](...?)", [$arguments]);
|
||||
|
||||
} elseif ($entity[0] instanceof Statement) {
|
||||
$inner = $this->formatPhp('?', [$entity[0]]);
|
||||
if (substr($inner, 0, 4) === 'new ') {
|
||||
$inner = "($inner)";
|
||||
}
|
||||
return $this->formatPhp("$inner->?(...?)", [$entity[1], $arguments]);
|
||||
|
||||
} elseif ($entity[1][0] === '$') { // property getter, setter or appender
|
||||
$name = substr($entity[1], 1);
|
||||
if ($append = (substr($name, -2) === '[]')) {
|
||||
$name = substr($name, 0, -2);
|
||||
}
|
||||
if ($this->builder->getServiceName($entity[0])) {
|
||||
$prop = $this->formatPhp('?->?', [$entity[0], $name]);
|
||||
} else {
|
||||
$prop = $this->formatPhp($entity[0] . '::$?', [$name]);
|
||||
}
|
||||
return $arguments
|
||||
? $this->formatPhp($prop . ($append ? '[]' : '') . ' = ?', [$arguments[0]])
|
||||
: $prop;
|
||||
|
||||
} elseif ($service = $this->builder->getServiceName($entity[0])) { // service method
|
||||
return $this->formatPhp('?->?(...?)', [$entity[0], $entity[1], $arguments]);
|
||||
|
||||
} else { // static method
|
||||
return $this->formatPhp("$entity[0]::$entity[1](...?)", [$arguments]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats PHP statement.
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
public function formatPhp($statement, $args)
|
||||
{
|
||||
array_walk_recursive($args, function (&$val) {
|
||||
if ($val instanceof Statement) {
|
||||
$val = new PhpLiteral($this->formatStatement($val));
|
||||
|
||||
} elseif (is_string($val) && substr($val, 0, 2) === '@@') { // escaped text @@
|
||||
$val = substr($val, 1);
|
||||
|
||||
} elseif (is_string($val) && substr($val, 0, 1) === '@' && strlen($val) > 1) { // service reference
|
||||
$name = substr($val, 1);
|
||||
if ($name === ContainerBuilder::THIS_CONTAINER) {
|
||||
$val = new PhpLiteral('$this');
|
||||
} elseif ($name === $this->currentService) {
|
||||
$val = new PhpLiteral('$service');
|
||||
} else {
|
||||
$val = new PhpLiteral($this->formatStatement(new Statement(['@' . ContainerBuilder::THIS_CONTAINER, 'getService'], [$name])));
|
||||
}
|
||||
}
|
||||
});
|
||||
return PhpHelpers::formatArgs($statement, $args);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts parameters from ServiceDefinition to PhpGenerator.
|
||||
* @return Nette\PhpGenerator\Parameter[]
|
||||
*/
|
||||
private function convertParameters(array $parameters)
|
||||
{
|
||||
$res = [];
|
||||
foreach ($parameters as $k => $v) {
|
||||
$tmp = explode(' ', is_int($k) ? $v : $k);
|
||||
$param = $res[] = new Nette\PhpGenerator\Parameter(end($tmp));
|
||||
if (!is_int($k)) {
|
||||
@$param->setOptional(true); // @ deprecated in nette/php-generator 3.1
|
||||
$param->setDefaultValue($v);
|
||||
}
|
||||
if (isset($tmp[1])) {
|
||||
$param->setTypeHint($tmp[0]);
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
273
vendor/nette/di/src/DI/PhpReflection.php
vendored
Normal file
273
vendor/nette/di/src/DI/PhpReflection.php
vendored
Normal file
|
@ -0,0 +1,273 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* PHP reflection helpers.
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
class PhpReflection
|
||||
{
|
||||
use Nette\StaticClass;
|
||||
|
||||
/**
|
||||
* Returns an annotation value.
|
||||
* @return string|null
|
||||
*/
|
||||
public static function parseAnnotation(\Reflector $ref, $name)
|
||||
{
|
||||
static $ok;
|
||||
if (!$ok) {
|
||||
if (!(new \ReflectionMethod(__METHOD__))->getDocComment()) {
|
||||
throw new Nette\InvalidStateException('You have to enable phpDoc comments in opcode cache.');
|
||||
}
|
||||
$ok = true;
|
||||
}
|
||||
$name = preg_quote($name, '#');
|
||||
if ($ref->getDocComment() && preg_match("#[\\s*]@$name(?:\\s++([^@]\\S*)?|$)#", trim($ref->getDocComment(), '/*'), $m)) {
|
||||
return isset($m[1]) ? $m[1] : '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns declaring class or trait.
|
||||
* @return \ReflectionClass
|
||||
*/
|
||||
public static function getDeclaringClass(\ReflectionProperty $prop)
|
||||
{
|
||||
foreach ($prop->getDeclaringClass()->getTraits() as $trait) {
|
||||
if ($trait->hasProperty($prop->getName())) {
|
||||
return self::getDeclaringClass($trait->getProperty($prop->getName()));
|
||||
}
|
||||
}
|
||||
return $prop->getDeclaringClass();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getParameterType(\ReflectionParameter $param)
|
||||
{
|
||||
if (PHP_VERSION_ID >= 70000) {
|
||||
$type = $param->hasType() ? (string) $param->getType() : null;
|
||||
return strtolower($type) === 'self' ? $param->getDeclaringClass()->getName() : $type;
|
||||
} elseif ($param->isArray() || $param->isCallable()) {
|
||||
return $param->isArray() ? 'array' : 'callable';
|
||||
} else {
|
||||
try {
|
||||
return ($ref = $param->getClass()) ? $ref->getName() : null;
|
||||
} catch (\ReflectionException $e) {
|
||||
if (preg_match('#Class (.+) does not exist#', $e->getMessage(), $m)) {
|
||||
return $m[1];
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getReturnType(\ReflectionFunctionAbstract $func)
|
||||
{
|
||||
if (PHP_VERSION_ID >= 70000 && $func->hasReturnType()) {
|
||||
$type = (string) $func->getReturnType();
|
||||
return strtolower($type) === 'self' ? $func->getDeclaringClass()->getName() : $type;
|
||||
}
|
||||
$type = preg_replace('#[|\s].*#', '', (string) self::parseAnnotation($func, 'return'));
|
||||
if ($type) {
|
||||
return $func instanceof \ReflectionMethod
|
||||
? self::expandClassName($type, $func->getDeclaringClass())
|
||||
: ltrim($type, '\\');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @return bool
|
||||
*/
|
||||
public static function isBuiltinType($type)
|
||||
{
|
||||
return in_array(strtolower($type), ['string', 'int', 'float', 'bool', 'array', 'callable'], true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns class and all its descendants.
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getClassTree(\ReflectionClass $class)
|
||||
{
|
||||
$addTraits = function ($types) use (&$addTraits) {
|
||||
if ($traits = array_merge(...array_map('class_uses', array_values($types)))) {
|
||||
$types += $traits + $addTraits($traits);
|
||||
}
|
||||
return $types;
|
||||
};
|
||||
$class = $class->getName();
|
||||
return array_values($addTraits([$class] + class_parents($class) + class_implements($class)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expands class name into full name.
|
||||
* @param string
|
||||
* @return string full name
|
||||
* @throws Nette\InvalidArgumentException
|
||||
*/
|
||||
public static function expandClassName($name, \ReflectionClass $rc)
|
||||
{
|
||||
$lower = strtolower($name);
|
||||
if (empty($name)) {
|
||||
throw new Nette\InvalidArgumentException('Class name must not be empty.');
|
||||
|
||||
} elseif (self::isBuiltinType($lower)) {
|
||||
return $lower;
|
||||
|
||||
} elseif ($lower === 'self' || $lower === 'static' || $lower === '$this') {
|
||||
return $rc->getName();
|
||||
|
||||
} elseif ($name[0] === '\\') { // fully qualified name
|
||||
return ltrim($name, '\\');
|
||||
}
|
||||
|
||||
$uses = self::getUseStatements($rc);
|
||||
$parts = explode('\\', $name, 2);
|
||||
if (isset($uses[$parts[0]])) {
|
||||
$parts[0] = $uses[$parts[0]];
|
||||
return implode('\\', $parts);
|
||||
|
||||
} elseif ($rc->inNamespace()) {
|
||||
return $rc->getNamespaceName() . '\\' . $name;
|
||||
|
||||
} else {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array of [alias => class]
|
||||
*/
|
||||
public static function getUseStatements(\ReflectionClass $class)
|
||||
{
|
||||
static $cache = [];
|
||||
if (!isset($cache[$name = $class->getName()])) {
|
||||
if ($class->isInternal()) {
|
||||
$cache[$name] = [];
|
||||
} else {
|
||||
$code = file_get_contents($class->getFileName());
|
||||
$cache = self::parseUseStatements($code, $name) + $cache;
|
||||
}
|
||||
}
|
||||
return $cache[$name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses PHP code.
|
||||
* @param string
|
||||
* @return array of [class => [alias => class, ...]]
|
||||
*/
|
||||
public static function parseUseStatements($code, $forClass = null)
|
||||
{
|
||||
$tokens = token_get_all($code);
|
||||
$namespace = $class = $classLevel = $level = null;
|
||||
$res = $uses = [];
|
||||
|
||||
while ($token = current($tokens)) {
|
||||
next($tokens);
|
||||
switch (is_array($token) ? $token[0] : $token) {
|
||||
case T_NAMESPACE:
|
||||
$namespace = ltrim(self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]) . '\\', '\\');
|
||||
$uses = [];
|
||||
break;
|
||||
|
||||
case T_CLASS:
|
||||
case T_INTERFACE:
|
||||
case T_TRAIT:
|
||||
if ($name = self::fetch($tokens, T_STRING)) {
|
||||
$class = $namespace . $name;
|
||||
$classLevel = $level + 1;
|
||||
$res[$class] = $uses;
|
||||
if ($class === $forClass) {
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case T_USE:
|
||||
while (!$class && ($name = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]))) {
|
||||
$name = ltrim($name, '\\');
|
||||
if (self::fetch($tokens, '{')) {
|
||||
while ($suffix = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR])) {
|
||||
if (self::fetch($tokens, T_AS)) {
|
||||
$uses[self::fetch($tokens, T_STRING)] = $name . $suffix;
|
||||
} else {
|
||||
$tmp = explode('\\', $suffix);
|
||||
$uses[end($tmp)] = $name . $suffix;
|
||||
}
|
||||
if (!self::fetch($tokens, ',')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} elseif (self::fetch($tokens, T_AS)) {
|
||||
$uses[self::fetch($tokens, T_STRING)] = $name;
|
||||
|
||||
} else {
|
||||
$tmp = explode('\\', $name);
|
||||
$uses[end($tmp)] = $name;
|
||||
}
|
||||
if (!self::fetch($tokens, ',')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case T_CURLY_OPEN:
|
||||
case T_DOLLAR_OPEN_CURLY_BRACES:
|
||||
case '{':
|
||||
$level++;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
if ($level === $classLevel) {
|
||||
$class = $classLevel = null;
|
||||
}
|
||||
$level--;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
private static function fetch(&$tokens, $take)
|
||||
{
|
||||
$res = null;
|
||||
while ($token = current($tokens)) {
|
||||
list($token, $s) = is_array($token) ? $token : [$token, $token];
|
||||
if (in_array($token, (array) $take, true)) {
|
||||
$res .= $s;
|
||||
} elseif (!in_array($token, [T_DOC_COMMENT, T_WHITESPACE, T_COMMENT], true)) {
|
||||
break;
|
||||
}
|
||||
next($tokens);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
381
vendor/nette/di/src/DI/ServiceDefinition.php
vendored
Normal file
381
vendor/nette/di/src/DI/ServiceDefinition.php
vendored
Normal file
|
@ -0,0 +1,381 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Definition used by ContainerBuilder.
|
||||
*
|
||||
* @property string|null $class
|
||||
* @property Statement|null $factory
|
||||
* @property Statement[] $setup
|
||||
*/
|
||||
class ServiceDefinition
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
const
|
||||
IMPLEMENT_MODE_CREATE = 'create',
|
||||
IMPLEMENT_MODE_GET = 'get';
|
||||
|
||||
/** @var array */
|
||||
public $parameters = [];
|
||||
|
||||
/** @var string|null class or interface name */
|
||||
private $type;
|
||||
|
||||
/** @var Statement|null */
|
||||
private $factory;
|
||||
|
||||
/** @var Statement[] */
|
||||
private $setup = [];
|
||||
|
||||
/** @var array */
|
||||
private $tags = [];
|
||||
|
||||
/** @var bool|string[] */
|
||||
private $autowired = true;
|
||||
|
||||
/** @var bool */
|
||||
private $dynamic = false;
|
||||
|
||||
/** @var string|null interface name */
|
||||
private $implement;
|
||||
|
||||
/** @var string|null create | get */
|
||||
private $implementMode;
|
||||
|
||||
/** @var callable 'pi' is noop */
|
||||
private $notifier = 'pi';
|
||||
|
||||
|
||||
/**
|
||||
* @param string|null
|
||||
* @return static
|
||||
* @deprecated Use setType() instead.
|
||||
*/
|
||||
public function setClass($type, array $args = [])
|
||||
{
|
||||
call_user_func($this->notifier);
|
||||
$this->type = $type;
|
||||
if ($args) {
|
||||
$this->setFactory($type, $args);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
* @deprecated Use getType() instead.
|
||||
*/
|
||||
public function getClass()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string|null
|
||||
* @return static
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
call_user_func($this->notifier);
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setFactory($factory, array $args = [])
|
||||
{
|
||||
call_user_func($this->notifier);
|
||||
$this->factory = $factory instanceof Statement ? $factory : new Statement($factory, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Statement|null
|
||||
*/
|
||||
public function getFactory()
|
||||
{
|
||||
return $this->factory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|array|ServiceDefinition|null
|
||||
*/
|
||||
public function getEntity()
|
||||
{
|
||||
return $this->factory ? $this->factory->getEntity() : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setArguments(array $args = [])
|
||||
{
|
||||
if (!$this->factory) {
|
||||
$this->factory = new Statement($this->type);
|
||||
}
|
||||
$this->factory->arguments = $args;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Statement[]
|
||||
* @return static
|
||||
*/
|
||||
public function setSetup(array $setup)
|
||||
{
|
||||
foreach ($setup as $v) {
|
||||
if (!$v instanceof Statement) {
|
||||
throw new Nette\InvalidArgumentException('Argument must be Nette\DI\Statement[].');
|
||||
}
|
||||
}
|
||||
$this->setup = $setup;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Statement[]
|
||||
*/
|
||||
public function getSetup()
|
||||
{
|
||||
return $this->setup;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function addSetup($entity, array $args = [])
|
||||
{
|
||||
$this->setup[] = $entity instanceof Statement ? $entity : new Statement($entity, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setParameters(array $params)
|
||||
{
|
||||
$this->parameters = $params;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getParameters()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setTags(array $tags)
|
||||
{
|
||||
$this->tags = $tags;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function addTag($tag, $attr = true)
|
||||
{
|
||||
$this->tags[$tag] = $attr;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTag($tag)
|
||||
{
|
||||
return isset($this->tags[$tag]) ? $this->tags[$tag] : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool|string|string[]
|
||||
* @return static
|
||||
*/
|
||||
public function setAutowired($state = true)
|
||||
{
|
||||
call_user_func($this->notifier);
|
||||
$this->autowired = is_string($state) || is_array($state) ? (array) $state : (bool) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool|string[]
|
||||
*/
|
||||
public function isAutowired()
|
||||
{
|
||||
return $this->autowired;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool|string[]
|
||||
*/
|
||||
public function getAutowired()
|
||||
{
|
||||
return $this->autowired;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool
|
||||
* @return static
|
||||
*/
|
||||
public function setDynamic($state = true)
|
||||
{
|
||||
$this->dynamic = (bool) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDynamic()
|
||||
{
|
||||
return $this->dynamic;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @return static
|
||||
*/
|
||||
public function setImplement($interface)
|
||||
{
|
||||
call_user_func($this->notifier);
|
||||
$this->implement = $interface;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getImplement()
|
||||
{
|
||||
return $this->implement;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @return static
|
||||
*/
|
||||
public function setImplementMode($mode)
|
||||
{
|
||||
if (!in_array($mode, [self::IMPLEMENT_MODE_CREATE, self::IMPLEMENT_MODE_GET], true)) {
|
||||
throw new Nette\InvalidArgumentException('Argument must be get|create.');
|
||||
}
|
||||
$this->implementMode = $mode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getImplementMode()
|
||||
{
|
||||
return $this->implementMode;
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function setImplementType($type)
|
||||
{
|
||||
trigger_error(__METHOD__ . '() is deprecated, use setImplementMode()', E_USER_DEPRECATED);
|
||||
return $this->setImplementMode($type);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function getImplementType()
|
||||
{
|
||||
trigger_error(__METHOD__ . '() is deprecated, use getImplementMode()', E_USER_DEPRECATED);
|
||||
return $this->implementMode;
|
||||
}
|
||||
|
||||
|
||||
/** @return static */
|
||||
public function setInject($state = true)
|
||||
{
|
||||
//trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
|
||||
return $this->addTag(Extensions\InjectExtension::TAG_INJECT, $state);
|
||||
}
|
||||
|
||||
|
||||
/** @return bool|null */
|
||||
public function getInject()
|
||||
{
|
||||
//trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
|
||||
return $this->getTag(Extensions\InjectExtension::TAG_INJECT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function setNotifier(callable $notifier)
|
||||
{
|
||||
$this->notifier = $notifier;
|
||||
}
|
||||
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->factory = unserialize(serialize($this->factory));
|
||||
$this->setup = unserialize(serialize($this->setup));
|
||||
$this->notifier = 'pi';
|
||||
}
|
||||
}
|
60
vendor/nette/di/src/DI/Statement.php
vendored
Normal file
60
vendor/nette/di/src/DI/Statement.php
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Assignment or calling statement.
|
||||
*
|
||||
* @property string|array|ServiceDefinition|null $entity
|
||||
*/
|
||||
class Statement
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @var array */
|
||||
public $arguments;
|
||||
|
||||
/** @var string|array|ServiceDefinition|null */
|
||||
private $entity;
|
||||
|
||||
|
||||
/**
|
||||
* @param string|array|ServiceDefinition|null
|
||||
*/
|
||||
public function __construct($entity, array $arguments = [])
|
||||
{
|
||||
if (
|
||||
!is_string($entity) // Class, @service, not, PHP literal, entity::member
|
||||
&& !(is_array($entity) && isset($entity[0], $entity[1])) // [Class | @service | '' | Statement | ServiceDefinition, method | $property | $appender]
|
||||
&& !$entity instanceof ServiceDefinition
|
||||
&& $entity !== null
|
||||
) {
|
||||
throw new Nette\InvalidArgumentException('Argument is not valid Statement entity.');
|
||||
}
|
||||
$this->entity = $entity;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
public function setEntity($entity)
|
||||
{
|
||||
trigger_error(__METHOD__ . ' is deprecated, change Statement object itself.', E_USER_DEPRECATED);
|
||||
$this->__construct($entity, $this->arguments);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getEntity()
|
||||
{
|
||||
return $this->entity;
|
||||
}
|
||||
}
|
31
vendor/nette/di/src/DI/exceptions.php
vendored
Normal file
31
vendor/nette/di/src/DI/exceptions.php
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\DI;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Service not found exception.
|
||||
*/
|
||||
class MissingServiceException extends Nette\InvalidStateException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Service creation exception.
|
||||
*/
|
||||
class ServiceCreationException extends Nette\InvalidStateException
|
||||
{
|
||||
public function setMessage($message)
|
||||
{
|
||||
$this->message = $message;
|
||||
return $this;
|
||||
}
|
||||
}
|
37
vendor/nette/finder/composer.json
vendored
Normal file
37
vendor/nette/finder/composer.json
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "nette/finder",
|
||||
"description": "🔍 Nette Finder: find files and directories with an intuitive API.",
|
||||
"keywords": ["nette", "filesystem", "iterator", "glob"],
|
||||
"homepage": "https://nette.org",
|
||||
"license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Grudl",
|
||||
"homepage": "https://davidgrudl.com"
|
||||
},
|
||||
{
|
||||
"name": "Nette Community",
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"nette/utils": "~2.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "~2.0",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["src/"]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/nette/finder/contributing.md
vendored
Normal file
33
vendor/nette/finder/contributing.md
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
How to contribute & use the issue tracker
|
||||
=========================================
|
||||
|
||||
Nette welcomes your contributions. There are several ways to help out:
|
||||
|
||||
* Create an issue on GitHub, if you have found a bug
|
||||
* Write test cases for open bug issues
|
||||
* Write fixes for open bug/feature issues, preferably with test cases included
|
||||
* Contribute to the [documentation](https://nette.org/en/writing)
|
||||
|
||||
Issues
|
||||
------
|
||||
|
||||
Please **do not use the issue tracker to ask questions**. We will be happy to help you
|
||||
on [Nette forum](https://forum.nette.org) or chat with us on [Gitter](https://gitter.im/nette/nette).
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more
|
||||
information. Please try to be as detailed as possible in your report.
|
||||
|
||||
**Feature requests** are welcome. But take a moment to find out whether your idea
|
||||
fits with the scope and aims of the project. It's up to *you* to make a strong
|
||||
case to convince the project's developers of the merits of this feature.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
If you'd like to contribute, please take a moment to read [the contributing guide](https://nette.org/en/contributing).
|
||||
|
||||
The best way to propose a feature is to discuss your ideas on [Nette forum](https://forum.nette.org) before implementing them.
|
||||
|
||||
Please do not fix whitespace, format code, or make a purely cosmetic patch.
|
||||
|
||||
Thanks! :heart:
|
60
vendor/nette/finder/license.md
vendored
Normal file
60
vendor/nette/finder/license.md
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
Licenses
|
||||
========
|
||||
|
||||
Good news! You may use Nette Framework under the terms of either
|
||||
the New BSD License or the GNU General Public License (GPL) version 2 or 3.
|
||||
|
||||
The BSD License is recommended for most projects. It is easy to understand and it
|
||||
places almost no restrictions on what you can do with the framework. If the GPL
|
||||
fits better to your project, you can use the framework under this license.
|
||||
|
||||
You don't have to notify anyone which license you are using. You can freely
|
||||
use Nette Framework in commercial projects as long as the copyright header
|
||||
remains intact.
|
||||
|
||||
Please be advised that the name "Nette Framework" is a protected trademark and its
|
||||
usage has some limitations. So please do not use word "Nette" in the name of your
|
||||
project or top-level domain, and choose a name that stands on its own merits.
|
||||
If your stuff is good, it will not take long to establish a reputation for yourselves.
|
||||
|
||||
|
||||
New BSD License
|
||||
---------------
|
||||
|
||||
Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "Nette Framework" nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as is" and
|
||||
any express or implied warranties, including, but not limited to, the implied
|
||||
warranties of merchantability and fitness for a particular purpose are
|
||||
disclaimed. In no event shall the copyright owner or contributors be liable for
|
||||
any direct, indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or services;
|
||||
loss of use, data, or profits; or business interruption) however caused and on
|
||||
any theory of liability, whether in contract, strict liability, or tort
|
||||
(including negligence or otherwise) arising in any way out of the use of this
|
||||
software, even if advised of the possibility of such damage.
|
||||
|
||||
|
||||
GNU General Public License
|
||||
--------------------------
|
||||
|
||||
GPL licenses are very very long, so instead of including them here we offer
|
||||
you URLs with full text:
|
||||
|
||||
- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
|
||||
- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
|
168
vendor/nette/finder/readme.md
vendored
Normal file
168
vendor/nette/finder/readme.md
vendored
Normal file
|
@ -0,0 +1,168 @@
|
|||
Nette Finder: Files Searching
|
||||
=============================
|
||||
|
||||
[](https://packagist.org/packages/nette/finder)
|
||||
[](https://travis-ci.org/nette/finder)
|
||||
[](https://coveralls.io/github/nette/finder?branch=master)
|
||||
[](https://github.com/nette/finder/releases)
|
||||
[](https://github.com/nette/finder/blob/master/license.md)
|
||||
|
||||
Class `Nette\Utils\Finder` makes browsing the directory structure really easy.
|
||||
|
||||
|
||||
All examples assume the following class alias is defined:
|
||||
|
||||
```php
|
||||
use Nette\Utils\Finder;
|
||||
```
|
||||
|
||||
|
||||
Searching for Files
|
||||
-------------------
|
||||
|
||||
How to find all `*.txt` files in `$dir` directory without recursing subdirectories?
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('*.txt')->in($dir) as $key => $file) {
|
||||
echo $key; // $key is a string containing absolute filename with path
|
||||
echo $file; // $file is an instance of SplFileInfo
|
||||
}
|
||||
```
|
||||
|
||||
As a result, the finder returns instances of `SplFileInfo`.
|
||||
|
||||
If the directory does not exist, an `UnexpectedValueException` is thrown.
|
||||
|
||||
And what about searching for `*.txt` files in `$dir` including subdirectories? Instead of `in()`, use `from()`:
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('*.txt')->from($dir) as $file) {
|
||||
echo $file;
|
||||
}
|
||||
```
|
||||
|
||||
Search by more masks, even inside more directories within one iteration:
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('*.txt', '*.php')
|
||||
->in($dir1, $dir2) as $file) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Parameters can also be arrays:
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles($masks)->in($dirs) as $file) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Searching for `*.txt` files containing a number in the name:
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('*[0-9]*.txt')->from($dir) as $file) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Searching for `*.txt` files, except those containing '`X`' in the name:
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('*.txt')
|
||||
->exclude('*X*')->from($dir) as $file) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
`exclude()` is specified just after `findFiles()`, thus it applies to filename.
|
||||
|
||||
|
||||
Directories to omit can be specified using the `exclude` **after** `from` clause:
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('*.php')
|
||||
->from($dir)->exclude('temp', '.git') as $file) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Here `exclude()` is after `from()`, thus it applies to the directory name.
|
||||
|
||||
|
||||
And now something a bit more complicated: searching for `*.txt` files located in subdirectories starting with '`te`', but not '`temp`':
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('te*/*.txt')
|
||||
->exclude('temp*/*')->from($dir) as $file) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Depth of search can be limited using the `limitDepth()` method.
|
||||
|
||||
|
||||
|
||||
Searching for directories
|
||||
----------------
|
||||
|
||||
In addition to files, it is possible to search for directories using `Finder::findDirectories('subdir*')`, or to search for files and directories: `Finder::find('file.txt')`.
|
||||
|
||||
|
||||
Filtering
|
||||
----------
|
||||
|
||||
You can also filter results. For example by size. This way we will traverse the files of size between 100B and 200B:
|
||||
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('*.php')->size('>=', 100)->size('<=', 200)
|
||||
->from($dir) as $file) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Or files changed in the last two weeks:
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('*.php')->date('>', '- 2 weeks')
|
||||
->from($dir) as $file) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Here we traverse PHP files with number of lines greater than 1000. As a filter we use a custom callback:
|
||||
|
||||
```php
|
||||
$finder = Finder::findFiles('*.php')->filter(function($file) {
|
||||
return count(file($file->getPathname())) > 1000;
|
||||
})->from($dir);
|
||||
```
|
||||
|
||||
|
||||
Finder, find images larger than 50px × 50px:
|
||||
|
||||
```php
|
||||
foreach (Finder::findFiles('*')
|
||||
->dimensions('>50', '>50')->from($dir) as $file) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Connection to Amazon S3
|
||||
----------------------
|
||||
|
||||
It's possible to use custom streams, for example Zend_Service_Amazon_S3:
|
||||
|
||||
```php
|
||||
$s3 = new Zend_Service_Amazon_S3($key, $secret);
|
||||
$s3->registerStreamWrapper('s3');
|
||||
|
||||
foreach (Finder::findFiles('photos*')
|
||||
->size('<=', 1e6)->in('s3://bucket-name') as $file) {
|
||||
echo $file;
|
||||
}
|
||||
```
|
||||
|
||||
Handy, right? You will certainly find a use for Finder in your applications.
|
393
vendor/nette/finder/src/Utils/Finder.php
vendored
Normal file
393
vendor/nette/finder/src/Utils/Finder.php
vendored
Normal file
|
@ -0,0 +1,393 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
namespace Nette\Utils;
|
||||
|
||||
use Nette;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
|
||||
/**
|
||||
* Finder allows searching through directory trees using iterator.
|
||||
*
|
||||
* <code>
|
||||
* Finder::findFiles('*.php')
|
||||
* ->size('> 10kB')
|
||||
* ->from('.')
|
||||
* ->exclude('temp');
|
||||
* </code>
|
||||
*/
|
||||
class Finder implements \IteratorAggregate, \Countable
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @var array */
|
||||
private $paths = [];
|
||||
|
||||
/** @var array of filters */
|
||||
private $groups = [];
|
||||
|
||||
/** @var array filter for recursive traversing */
|
||||
private $exclude = [];
|
||||
|
||||
/** @var int */
|
||||
private $order = RecursiveIteratorIterator::SELF_FIRST;
|
||||
|
||||
/** @var int */
|
||||
private $maxDepth = -1;
|
||||
|
||||
/** @var array */
|
||||
private $cursor;
|
||||
|
||||
|
||||
/**
|
||||
* Begins search for files matching mask and all directories.
|
||||
* @param mixed
|
||||
* @return static
|
||||
*/
|
||||
public static function find(...$masks)
|
||||
{
|
||||
$masks = $masks && is_array($masks[0]) ? $masks[0] : $masks;
|
||||
return (new static)->select($masks, 'isDir')->select($masks, 'isFile');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Begins search for files matching mask.
|
||||
* @param mixed
|
||||
* @return static
|
||||
*/
|
||||
public static function findFiles(...$masks)
|
||||
{
|
||||
$masks = $masks && is_array($masks[0]) ? $masks[0] : $masks;
|
||||
return (new static)->select($masks, 'isFile');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Begins search for directories matching mask.
|
||||
* @param mixed
|
||||
* @return static
|
||||
*/
|
||||
public static function findDirectories(...$masks)
|
||||
{
|
||||
$masks = $masks && is_array($masks[0]) ? $masks[0] : $masks;
|
||||
return (new static)->select($masks, 'isDir');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates filtering group by mask & type selector.
|
||||
* @param array
|
||||
* @param string
|
||||
* @return static
|
||||
*/
|
||||
private function select($masks, $type)
|
||||
{
|
||||
$this->cursor = &$this->groups[];
|
||||
$pattern = self::buildPattern($masks);
|
||||
if ($type || $pattern) {
|
||||
$this->filter(function (RecursiveDirectoryIterator $file) use ($type, $pattern) {
|
||||
return !$file->isDot()
|
||||
&& (!$type || $file->$type())
|
||||
&& (!$pattern || preg_match($pattern, '/' . strtr($file->getSubPathName(), '\\', '/')));
|
||||
});
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Searchs in the given folder(s).
|
||||
* @param string|array
|
||||
* @return static
|
||||
*/
|
||||
public function in(...$paths)
|
||||
{
|
||||
$this->maxDepth = 0;
|
||||
return $this->from(...$paths);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Searchs recursively from the given folder(s).
|
||||
* @param string|array
|
||||
* @return static
|
||||
*/
|
||||
public function from(...$paths)
|
||||
{
|
||||
if ($this->paths) {
|
||||
throw new Nette\InvalidStateException('Directory to search has already been specified.');
|
||||
}
|
||||
$this->paths = is_array($paths[0]) ? $paths[0] : $paths;
|
||||
$this->cursor = &$this->exclude;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows folder content prior to the folder.
|
||||
* @return static
|
||||
*/
|
||||
public function childFirst()
|
||||
{
|
||||
$this->order = RecursiveIteratorIterator::CHILD_FIRST;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts Finder pattern to regular expression.
|
||||
* @param array
|
||||
* @return string|null
|
||||
*/
|
||||
private static function buildPattern($masks)
|
||||
{
|
||||
$pattern = [];
|
||||
foreach ($masks as $mask) {
|
||||
$mask = rtrim(strtr($mask, '\\', '/'), '/');
|
||||
$prefix = '';
|
||||
if ($mask === '') {
|
||||
continue;
|
||||
|
||||
} elseif ($mask === '*') {
|
||||
return null;
|
||||
|
||||
} elseif ($mask[0] === '/') { // absolute fixing
|
||||
$mask = ltrim($mask, '/');
|
||||
$prefix = '(?<=^/)';
|
||||
}
|
||||
$pattern[] = $prefix . strtr(preg_quote($mask, '#'),
|
||||
['\*\*' => '.*', '\*' => '[^/]*', '\?' => '[^/]', '\[\!' => '[^', '\[' => '[', '\]' => ']', '\-' => '-']);
|
||||
}
|
||||
return $pattern ? '#/(' . implode('|', $pattern) . ')\z#i' : null;
|
||||
}
|
||||
|
||||
|
||||
/********************* iterator generator ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of found files and/or directories.
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return iterator_count($this->getIterator());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns iterator.
|
||||
* @return \Iterator
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
if (!$this->paths) {
|
||||
throw new Nette\InvalidStateException('Call in() or from() to specify directory to search.');
|
||||
|
||||
} elseif (count($this->paths) === 1) {
|
||||
return $this->buildIterator($this->paths[0]);
|
||||
|
||||
} else {
|
||||
$iterator = new \AppendIterator();
|
||||
$iterator->append($workaround = new \ArrayIterator(['workaround PHP bugs #49104, #63077']));
|
||||
foreach ($this->paths as $path) {
|
||||
$iterator->append($this->buildIterator($path));
|
||||
}
|
||||
unset($workaround[0]);
|
||||
return $iterator;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns per-path iterator.
|
||||
* @param string
|
||||
* @return \Iterator
|
||||
*/
|
||||
private function buildIterator($path)
|
||||
{
|
||||
$iterator = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::FOLLOW_SYMLINKS);
|
||||
|
||||
if ($this->exclude) {
|
||||
$iterator = new \RecursiveCallbackFilterIterator($iterator, function ($foo, $bar, RecursiveDirectoryIterator $file) {
|
||||
if (!$file->isDot() && !$file->isFile()) {
|
||||
foreach ($this->exclude as $filter) {
|
||||
if (!call_user_func($filter, $file)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if ($this->maxDepth !== 0) {
|
||||
$iterator = new RecursiveIteratorIterator($iterator, $this->order);
|
||||
$iterator->setMaxDepth($this->maxDepth);
|
||||
}
|
||||
|
||||
$iterator = new \CallbackFilterIterator($iterator, function ($foo, $bar, \Iterator $file) {
|
||||
while ($file instanceof \OuterIterator) {
|
||||
$file = $file->getInnerIterator();
|
||||
}
|
||||
|
||||
foreach ($this->groups as $filters) {
|
||||
foreach ($filters as $filter) {
|
||||
if (!call_user_func($filter, $file)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return $iterator;
|
||||
}
|
||||
|
||||
|
||||
/********************* filtering ****************d*g**/
|
||||
|
||||
|
||||
/**
|
||||
* Restricts the search using mask.
|
||||
* Excludes directories from recursive traversing.
|
||||
* @param mixed
|
||||
* @return static
|
||||
*/
|
||||
public function exclude(...$masks)
|
||||
{
|
||||
$masks = $masks && is_array($masks[0]) ? $masks[0] : $masks;
|
||||
$pattern = self::buildPattern($masks);
|
||||
if ($pattern) {
|
||||
$this->filter(function (RecursiveDirectoryIterator $file) use ($pattern) {
|
||||
return !preg_match($pattern, '/' . strtr($file->getSubPathName(), '\\', '/'));
|
||||
});
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restricts the search using callback.
|
||||
* @param callable function (RecursiveDirectoryIterator $file)
|
||||
* @return static
|
||||
*/
|
||||
public function filter($callback)
|
||||
{
|
||||
$this->cursor[] = $callback;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Limits recursion level.
|
||||
* @param int
|
||||
* @return static
|
||||
*/
|
||||
public function limitDepth($depth)
|
||||
{
|
||||
$this->maxDepth = $depth;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restricts the search by size.
|
||||
* @param string "[operator] [size] [unit]" example: >=10kB
|
||||
* @param int
|
||||
* @return static
|
||||
*/
|
||||
public function size($operator, $size = null)
|
||||
{
|
||||
if (func_num_args() === 1) { // in $operator is predicate
|
||||
if (!preg_match('#^(?:([=<>!]=?|<>)\s*)?((?:\d*\.)?\d+)\s*(K|M|G|)B?\z#i', $operator, $matches)) {
|
||||
throw new Nette\InvalidArgumentException('Invalid size predicate format.');
|
||||
}
|
||||
list(, $operator, $size, $unit) = $matches;
|
||||
static $units = ['' => 1, 'k' => 1e3, 'm' => 1e6, 'g' => 1e9];
|
||||
$size *= $units[strtolower($unit)];
|
||||
$operator = $operator ?: '=';
|
||||
}
|
||||
return $this->filter(function (RecursiveDirectoryIterator $file) use ($operator, $size) {
|
||||
return self::compare($file->getSize(), $operator, $size);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restricts the search by modified time.
|
||||
* @param string "[operator] [date]" example: >1978-01-23
|
||||
* @param mixed
|
||||
* @return static
|
||||
*/
|
||||
public function date($operator, $date = null)
|
||||
{
|
||||
if (func_num_args() === 1) { // in $operator is predicate
|
||||
if (!preg_match('#^(?:([=<>!]=?|<>)\s*)?(.+)\z#i', $operator, $matches)) {
|
||||
throw new Nette\InvalidArgumentException('Invalid date predicate format.');
|
||||
}
|
||||
list(, $operator, $date) = $matches;
|
||||
$operator = $operator ?: '=';
|
||||
}
|
||||
$date = DateTime::from($date)->format('U');
|
||||
return $this->filter(function (RecursiveDirectoryIterator $file) use ($operator, $date) {
|
||||
return self::compare($file->getMTime(), $operator, $date);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compares two values.
|
||||
* @param mixed
|
||||
* @param mixed
|
||||
* @return bool
|
||||
*/
|
||||
public static function compare($l, $operator, $r)
|
||||
{
|
||||
switch ($operator) {
|
||||
case '>':
|
||||
return $l > $r;
|
||||
case '>=':
|
||||
return $l >= $r;
|
||||
case '<':
|
||||
return $l < $r;
|
||||
case '<=':
|
||||
return $l <= $r;
|
||||
case '=':
|
||||
case '==':
|
||||
return $l == $r;
|
||||
case '!':
|
||||
case '!=':
|
||||
case '<>':
|
||||
return $l != $r;
|
||||
default:
|
||||
throw new Nette\InvalidArgumentException("Unknown operator $operator.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************* extension methods ****************d*g**/
|
||||
|
||||
|
||||
public function __call($name, $args)
|
||||
{
|
||||
if ($callback = Nette\Utils\ObjectMixin::getExtensionMethod(__CLASS__, $name)) {
|
||||
return $callback($this, ...$args);
|
||||
}
|
||||
Nette\Utils\ObjectMixin::strictCall(__CLASS__, $name);
|
||||
}
|
||||
|
||||
|
||||
public static function extensionMethod($name, $callback)
|
||||
{
|
||||
Nette\Utils\ObjectMixin::setExtensionMethod(__CLASS__, $name, $callback);
|
||||
}
|
||||
}
|
35
vendor/nette/neon/composer.json
vendored
Normal file
35
vendor/nette/neon/composer.json
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "nette/neon",
|
||||
"description": "🍸 Nette NEON: encodes and decodes NEON file format.",
|
||||
"keywords": ["nette", "neon", "import", "export", "yaml"],
|
||||
"homepage": "http://ne-on.org",
|
||||
"license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Grudl",
|
||||
"homepage": "https://davidgrudl.com"
|
||||
},
|
||||
{
|
||||
"name": "Nette Community",
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "^2.0",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["src/"]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/nette/neon/contributing.md
vendored
Normal file
33
vendor/nette/neon/contributing.md
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
How to contribute & use the issue tracker
|
||||
=========================================
|
||||
|
||||
Nette welcomes your contributions. There are several ways to help out:
|
||||
|
||||
* Create an issue on GitHub, if you have found a bug
|
||||
* Write test cases for open bug issues
|
||||
* Write fixes for open bug/feature issues, preferably with test cases included
|
||||
* Contribute to the [documentation](https://nette.org/en/writing)
|
||||
|
||||
Issues
|
||||
------
|
||||
|
||||
Please **do not use the issue tracker to ask questions**. We will be happy to help you
|
||||
on [Nette forum](https://forum.nette.org) or chat with us on [Gitter](https://gitter.im/nette/nette).
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more
|
||||
information. Please try to be as detailed as possible in your report.
|
||||
|
||||
**Feature requests** are welcome. But take a moment to find out whether your idea
|
||||
fits with the scope and aims of the project. It's up to *you* to make a strong
|
||||
case to convince the project's developers of the merits of this feature.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
If you'd like to contribute, please take a moment to read [the contributing guide](https://nette.org/en/contributing).
|
||||
|
||||
The best way to propose a feature is to discuss your ideas on [Nette forum](https://forum.nette.org) before implementing them.
|
||||
|
||||
Please do not fix whitespace, format code, or make a purely cosmetic patch.
|
||||
|
||||
Thanks! :heart:
|
60
vendor/nette/neon/license.md
vendored
Normal file
60
vendor/nette/neon/license.md
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
Licenses
|
||||
========
|
||||
|
||||
Good news! You may use Nette Framework under the terms of either
|
||||
the New BSD License or the GNU General Public License (GPL) version 2 or 3.
|
||||
|
||||
The BSD License is recommended for most projects. It is easy to understand and it
|
||||
places almost no restrictions on what you can do with the framework. If the GPL
|
||||
fits better to your project, you can use the framework under this license.
|
||||
|
||||
You don't have to notify anyone which license you are using. You can freely
|
||||
use Nette Framework in commercial projects as long as the copyright header
|
||||
remains intact.
|
||||
|
||||
Please be advised that the name "Nette Framework" is a protected trademark and its
|
||||
usage has some limitations. So please do not use word "Nette" in the name of your
|
||||
project or top-level domain, and choose a name that stands on its own merits.
|
||||
If your stuff is good, it will not take long to establish a reputation for yourselves.
|
||||
|
||||
|
||||
New BSD License
|
||||
---------------
|
||||
|
||||
Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "Nette Framework" nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as is" and
|
||||
any express or implied warranties, including, but not limited to, the implied
|
||||
warranties of merchantability and fitness for a particular purpose are
|
||||
disclaimed. In no event shall the copyright owner or contributors be liable for
|
||||
any direct, indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or services;
|
||||
loss of use, data, or profits; or business interruption) however caused and on
|
||||
any theory of liability, whether in contract, strict liability, or tort
|
||||
(including negligence or otherwise) arising in any way out of the use of this
|
||||
software, even if advised of the possibility of such damage.
|
||||
|
||||
|
||||
GNU General Public License
|
||||
--------------------------
|
||||
|
||||
GPL licenses are very very long, so instead of including them here we offer
|
||||
you URLs with full text:
|
||||
|
||||
- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
|
||||
- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
|
96
vendor/nette/neon/readme.md
vendored
Normal file
96
vendor/nette/neon/readme.md
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
[NEON](http://ne-on.org): Nette Object Notation
|
||||
===============================================
|
||||
|
||||
[](https://packagist.org/packages/nette/neon)
|
||||
[](https://travis-ci.org/nette/neon)
|
||||
[](https://coveralls.io/github/nette/neon?branch=master)
|
||||
[](https://github.com/nette/neon/releases)
|
||||
[](https://github.com/nette/neon/blob/master/license.md)
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
NEON is a human-readable data serialization language. It is commonly used for configuration files, but could be used in many applications where data is being stored
|
||||
|
||||
NEON is very similar to YAML.The main difference is that the NEON supports "entities" (so can be used e.g. to parse phpDoc annotations) and tab characters for indentation.
|
||||
NEON syntax is a little simpler and the parsing is faster.
|
||||
|
||||
Documentation can be found on the [website](https://doc.nette.org/neon).
|
||||
|
||||
If you like Nette, **[please make a donation now](https://nette.org/donate)**. Thank you!
|
||||
|
||||
|
||||
NEON language
|
||||
-------------
|
||||
|
||||
Try NEON [in sandbox](https://ne-on.org)!
|
||||
|
||||
Example of NEON code:
|
||||
|
||||
```
|
||||
# my web application config
|
||||
|
||||
php:
|
||||
date.timezone: Europe/Prague
|
||||
zlib.output_compression: yes # use gzip
|
||||
|
||||
database:
|
||||
driver: mysql
|
||||
username: root
|
||||
password: beruska92
|
||||
|
||||
users:
|
||||
- Dave
|
||||
- Kryten
|
||||
- Rimmer
|
||||
```
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
The recommended way to install is via Composer:
|
||||
|
||||
```
|
||||
composer require nette/neon
|
||||
```
|
||||
|
||||
It requires PHP version 5.6 and supports PHP up to 7.3. The dev-master version requires PHP 7.0.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
`Nette\Neon\Neon` is a static class for encoding and decoding NEON files.
|
||||
|
||||
`Neon::encode()` returns $value encoded into NEON. Flags accepts Neon::BLOCK which formats NEON in multiline format.
|
||||
|
||||
```php
|
||||
use Nette\Neon\Neon;
|
||||
$neon = Neon::encode($value); // Returns $value encoded in NEON
|
||||
$neon = Neon::encode($value, Neon::BLOCK); // Returns formatted $value encoded in NEON
|
||||
```
|
||||
|
||||
`Neon::decode()` converts given NEON to PHP value:
|
||||
|
||||
```php
|
||||
$value = Neon::decode('hello: world'); // Returns an array ['hello' => 'world']
|
||||
```
|
||||
|
||||
Both methods throw `Nette\Neon\Exception` on error.
|
||||
|
||||
|
||||
Editors plugins
|
||||
---------------
|
||||
|
||||
- NetBeans IDE has built-in support
|
||||
- [PhpStorm](https://plugins.jetbrains.com/plugin/7060?pr)
|
||||
- [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=Kasik96.latte)
|
||||
- [Emacs](https://github.com/Fuco1/neon-mode)
|
||||
|
||||
|
||||
Other languages
|
||||
---------------
|
||||
|
||||
- [Neon for Javascript](https://github.com/matej21/neon-js)
|
||||
- [Neon for Python](https://github.com/paveldedik/neon-py)
|
358
vendor/nette/neon/src/Neon/Decoder.php
vendored
Normal file
358
vendor/nette/neon/src/Neon/Decoder.php
vendored
Normal file
|
@ -0,0 +1,358 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Neon;
|
||||
|
||||
|
||||
/**
|
||||
* Parser for Nette Object Notation.
|
||||
* @internal
|
||||
*/
|
||||
final class Decoder
|
||||
{
|
||||
const PATTERNS = [
|
||||
'
|
||||
\'\'\'\n (?:(?: [^\n] | \n(?![\t\ ]*+\'\'\') )*+ \n)?[\t\ ]*+\'\'\' |
|
||||
"""\n (?:(?: [^\n] | \n(?![\t\ ]*+""") )*+ \n)?[\t\ ]*+""" |
|
||||
\'[^\'\n]*+\' |
|
||||
" (?: \\\\. | [^"\\\\\n] )*+ "
|
||||
', // string
|
||||
'
|
||||
(?: [^#"\',:=[\]{}()\x00-\x20!`-] | [:-][^"\',\]})\s] )
|
||||
(?:
|
||||
[^,:=\]})(\x00-\x20]++ |
|
||||
:(?! [\s,\]})] | $ ) |
|
||||
[\ \t]++ [^#,:=\]})(\x00-\x20]
|
||||
)*+
|
||||
', // literal / boolean / integer / float
|
||||
'
|
||||
[,:=[\]{}()-]
|
||||
', // symbol
|
||||
'?:\#.*+', // comment
|
||||
'\n[\t\ ]*+', // new line + indent
|
||||
'?:[\t\ ]++', // whitespace
|
||||
];
|
||||
|
||||
const PATTERN_DATETIME = '#\d\d\d\d-\d\d?-\d\d?(?:(?:[Tt]| ++)\d\d?:\d\d:\d\d(?:\.\d*+)? *+(?:Z|[-+]\d\d?(?::?\d\d)?)?)?\z#A';
|
||||
|
||||
const PATTERN_HEX = '#0x[0-9a-fA-F]++\z#A';
|
||||
|
||||
const PATTERN_OCTAL = '#0o[0-7]++\z#A';
|
||||
|
||||
const PATTERN_BINARY = '#0b[0-1]++\z#A';
|
||||
|
||||
const SIMPLE_TYPES = [
|
||||
'true' => 'TRUE', 'True' => 'TRUE', 'TRUE' => 'TRUE', 'yes' => 'TRUE', 'Yes' => 'TRUE', 'YES' => 'TRUE', 'on' => 'TRUE', 'On' => 'TRUE', 'ON' => 'TRUE',
|
||||
'false' => 'FALSE', 'False' => 'FALSE', 'FALSE' => 'FALSE', 'no' => 'FALSE', 'No' => 'FALSE', 'NO' => 'FALSE', 'off' => 'FALSE', 'Off' => 'FALSE', 'OFF' => 'FALSE',
|
||||
'null' => 'NULL', 'Null' => 'NULL', 'NULL' => 'NULL',
|
||||
];
|
||||
|
||||
const ESCAPE_SEQUENCES = [
|
||||
't' => "\t", 'n' => "\n", 'r' => "\r", 'f' => "\x0C", 'b' => "\x08", '"' => '"', '\\' => '\\', '/' => '/', '_' => "\u{A0}",
|
||||
];
|
||||
|
||||
const BRACKETS = [
|
||||
'[' => ']',
|
||||
'{' => '}',
|
||||
'(' => ')',
|
||||
];
|
||||
|
||||
/** @var string */
|
||||
private $input;
|
||||
|
||||
/** @var array */
|
||||
private $tokens;
|
||||
|
||||
/** @var int */
|
||||
private $pos;
|
||||
|
||||
|
||||
/**
|
||||
* Decodes a NEON string.
|
||||
* @return mixed
|
||||
*/
|
||||
public function decode(string $input)
|
||||
{
|
||||
if (!is_string($input)) {
|
||||
throw new \InvalidArgumentException(sprintf('Argument must be a string, %s given.', gettype($input)));
|
||||
|
||||
} elseif (substr($input, 0, 3) === "\u{FEFF}") { // BOM
|
||||
$input = substr($input, 3);
|
||||
}
|
||||
$this->input = "\n" . str_replace("\r", '', $input); // \n forces indent detection
|
||||
|
||||
$pattern = '~(' . implode(')|(', self::PATTERNS) . ')~Amix';
|
||||
$this->tokens = preg_split($pattern, $this->input, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
$last = end($this->tokens);
|
||||
if ($this->tokens && !preg_match($pattern, $last[0])) {
|
||||
$this->pos = count($this->tokens) - 1;
|
||||
$this->error();
|
||||
}
|
||||
|
||||
$this->pos = 0;
|
||||
$res = $this->parse(null);
|
||||
|
||||
while (isset($this->tokens[$this->pos])) {
|
||||
if ($this->tokens[$this->pos][0][0] === "\n") {
|
||||
$this->pos++;
|
||||
} else {
|
||||
$this->error();
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string|bool|null $indent indentation (for block-parser)
|
||||
* @return mixed
|
||||
*/
|
||||
private function parse($indent, array $result = null, $key = null, bool $hasKey = false)
|
||||
{
|
||||
$inlineParser = $indent === false;
|
||||
$value = null;
|
||||
$hasValue = false;
|
||||
$tokens = $this->tokens;
|
||||
$n = &$this->pos;
|
||||
$count = count($tokens);
|
||||
$mainResult = &$result;
|
||||
|
||||
for (; $n < $count; $n++) {
|
||||
$t = $tokens[$n][0];
|
||||
|
||||
if ($t === ',') { // ArrayEntry separator
|
||||
if ((!$hasKey && !$hasValue) || !$inlineParser) {
|
||||
$this->error();
|
||||
}
|
||||
$this->addValue($result, $hasKey ? $key : null, $hasValue ? $value : null);
|
||||
$hasKey = $hasValue = false;
|
||||
|
||||
} elseif ($t === ':' || $t === '=') { // KeyValuePair separator
|
||||
if ($hasValue && (is_array($value) || is_object($value))) {
|
||||
$this->error('Unacceptable key');
|
||||
|
||||
} elseif ($hasKey && $key === null && $hasValue && !$inlineParser) {
|
||||
$n++;
|
||||
$result[] = $this->parse($indent . ' ', [], $value, true);
|
||||
$newIndent = isset($tokens[$n], $tokens[$n + 1]) ? (string) substr($tokens[$n][0], 1) : ''; // not last
|
||||
if (strlen($newIndent) > strlen($indent)) {
|
||||
$n++;
|
||||
$this->error('Bad indentation');
|
||||
} elseif (strlen($newIndent) < strlen($indent)) {
|
||||
return $mainResult; // block parser exit point
|
||||
}
|
||||
$hasKey = $hasValue = false;
|
||||
|
||||
} elseif ($hasKey || !$hasValue) {
|
||||
$this->error();
|
||||
|
||||
} else {
|
||||
$key = (string) $value;
|
||||
$hasKey = true;
|
||||
$hasValue = false;
|
||||
$result = &$mainResult;
|
||||
}
|
||||
|
||||
} elseif ($t === '-') { // BlockArray bullet
|
||||
if ($hasKey || $hasValue || $inlineParser) {
|
||||
$this->error();
|
||||
}
|
||||
$key = null;
|
||||
$hasKey = true;
|
||||
|
||||
} elseif (isset(self::BRACKETS[$t])) { // Opening bracket [ ( {
|
||||
if ($hasValue) {
|
||||
if ($t !== '(') {
|
||||
$this->error();
|
||||
}
|
||||
$n++;
|
||||
if ($value instanceof Entity && $value->value === Neon::CHAIN) {
|
||||
end($value->attributes)->attributes = $this->parse(false, []);
|
||||
} else {
|
||||
$value = new Entity($value, $this->parse(false, []));
|
||||
}
|
||||
} else {
|
||||
$n++;
|
||||
$value = $this->parse(false, []);
|
||||
}
|
||||
$hasValue = true;
|
||||
if (!isset($tokens[$n]) || $tokens[$n][0] !== self::BRACKETS[$t]) { // unexpected type of bracket or block-parser
|
||||
$this->error();
|
||||
}
|
||||
|
||||
} elseif ($t === ']' || $t === '}' || $t === ')') { // Closing bracket ] ) }
|
||||
if (!$inlineParser) {
|
||||
$this->error();
|
||||
}
|
||||
break;
|
||||
|
||||
} elseif ($t[0] === "\n") { // Indent
|
||||
if ($inlineParser) {
|
||||
if ($hasKey || $hasValue) {
|
||||
$this->addValue($result, $hasKey ? $key : null, $hasValue ? $value : null);
|
||||
$hasKey = $hasValue = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
while (isset($tokens[$n + 1]) && $tokens[$n + 1][0][0] === "\n") {
|
||||
$n++; // skip to last indent
|
||||
}
|
||||
if (!isset($tokens[$n + 1])) {
|
||||
break;
|
||||
}
|
||||
|
||||
$newIndent = (string) substr($tokens[$n][0], 1);
|
||||
if ($indent === null) { // first iteration
|
||||
$indent = $newIndent;
|
||||
}
|
||||
$minlen = min(strlen($newIndent), strlen($indent));
|
||||
if ($minlen && (string) substr($newIndent, 0, $minlen) !== (string) substr($indent, 0, $minlen)) {
|
||||
$n++;
|
||||
$this->error('Invalid combination of tabs and spaces');
|
||||
}
|
||||
|
||||
if (strlen($newIndent) > strlen($indent)) { // open new block-array or hash
|
||||
if ($hasValue || !$hasKey) {
|
||||
$n++;
|
||||
$this->error('Bad indentation');
|
||||
}
|
||||
$this->addValue($result, $key, $this->parse($newIndent));
|
||||
$newIndent = isset($tokens[$n], $tokens[$n + 1]) ? (string) substr($tokens[$n][0], 1) : ''; // not last
|
||||
if (strlen($newIndent) > strlen($indent)) {
|
||||
$n++;
|
||||
$this->error('Bad indentation');
|
||||
}
|
||||
$hasKey = false;
|
||||
|
||||
} else {
|
||||
if ($hasValue && !$hasKey) { // block items must have "key"; null key means list item
|
||||
break;
|
||||
|
||||
} elseif ($hasKey) {
|
||||
$this->addValue($result, $key, $hasValue ? $value : null);
|
||||
if ($key !== null && !$hasValue && $newIndent === $indent && isset($tokens[$n + 1]) && $tokens[$n + 1][0] === '-') {
|
||||
$result = &$result[$key];
|
||||
}
|
||||
$hasKey = $hasValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($newIndent) < strlen($indent)) { // close block
|
||||
return $mainResult; // block parser exit point
|
||||
}
|
||||
}
|
||||
|
||||
} else { // Value
|
||||
if ($t[0] === '"' || $t[0] === "'") {
|
||||
if (preg_match('#^...\n++([\t ]*+)#', $t, $m)) {
|
||||
$converted = substr($t, 3, -3);
|
||||
$converted = str_replace("\n" . $m[1], "\n", $converted);
|
||||
$converted = preg_replace('#^\n|\n[\t ]*+\z#', '', $converted);
|
||||
} else {
|
||||
$converted = substr($t, 1, -1);
|
||||
}
|
||||
if ($t[0] === '"') {
|
||||
$converted = preg_replace_callback('#\\\\(?:ud[89ab][0-9a-f]{2}\\\\ud[c-f][0-9a-f]{2}|u[0-9a-f]{4}|x[0-9a-f]{2}|.)#i', [$this, 'cbString'], $converted);
|
||||
}
|
||||
} elseif (($fix56 = self::SIMPLE_TYPES) && isset($fix56[$t]) && (!isset($tokens[$n + 1][0]) || ($tokens[$n + 1][0] !== ':' && $tokens[$n + 1][0] !== '='))) {
|
||||
$converted = constant(self::SIMPLE_TYPES[$t]);
|
||||
} elseif (is_numeric($t)) {
|
||||
$converted = $t * 1;
|
||||
} elseif (preg_match(self::PATTERN_HEX, $t)) {
|
||||
$converted = hexdec($t);
|
||||
} elseif (preg_match(self::PATTERN_OCTAL, $t)) {
|
||||
$converted = octdec($t);
|
||||
} elseif (preg_match(self::PATTERN_BINARY, $t)) {
|
||||
$converted = bindec($t);
|
||||
} elseif (preg_match(self::PATTERN_DATETIME, $t)) {
|
||||
$converted = new \DateTimeImmutable($t);
|
||||
} else { // literal
|
||||
$converted = $t;
|
||||
}
|
||||
if ($hasValue) {
|
||||
if ($value instanceof Entity) { // Entity chaining
|
||||
if ($value->value !== Neon::CHAIN) {
|
||||
$value = new Entity(Neon::CHAIN, [$value]);
|
||||
}
|
||||
$value->attributes[] = new Entity($converted);
|
||||
} else {
|
||||
$this->error();
|
||||
}
|
||||
} else {
|
||||
$value = $converted;
|
||||
$hasValue = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($inlineParser) {
|
||||
if ($hasKey || $hasValue) {
|
||||
$this->addValue($result, $hasKey ? $key : null, $hasValue ? $value : null);
|
||||
}
|
||||
} else {
|
||||
if ($hasValue && !$hasKey) { // block items must have "key"
|
||||
if ($result === null) {
|
||||
$result = $value; // simple value parser
|
||||
} else {
|
||||
$this->error();
|
||||
}
|
||||
} elseif ($hasKey) {
|
||||
$this->addValue($result, $key, $hasValue ? $value : null);
|
||||
}
|
||||
}
|
||||
return $mainResult;
|
||||
}
|
||||
|
||||
|
||||
private function addValue(&$result, $key, $value)
|
||||
{
|
||||
if ($key === null) {
|
||||
$result[] = $value;
|
||||
} elseif ($result && array_key_exists($key, $result)) {
|
||||
$this->error("Duplicated key '$key'");
|
||||
} else {
|
||||
$result[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function cbString(array $m): string
|
||||
{
|
||||
$sq = $m[0];
|
||||
if (($fix56 = self::ESCAPE_SEQUENCES) && isset($fix56[$sq[1]])) { // workaround for PHP 5.6
|
||||
return self::ESCAPE_SEQUENCES[$sq[1]];
|
||||
} elseif ($sq[1] === 'u' && strlen($sq) >= 6) {
|
||||
$lead = hexdec(substr($sq, 2, 4));
|
||||
$tail = hexdec(substr($sq, 8, 4));
|
||||
$code = $tail ? (0x2400 + (($lead - 0xD800) << 10) + $tail) : $lead;
|
||||
if ($code >= 0xD800 && $code <= 0xDFFF) {
|
||||
$this->error("Invalid UTF-8 (lone surrogate) $sq");
|
||||
}
|
||||
return iconv('UTF-32BE', 'UTF-8//IGNORE', pack('N', $code));
|
||||
} elseif ($sq[1] === 'x' && strlen($sq) === 4) {
|
||||
return chr(hexdec(substr($sq, 2)));
|
||||
} else {
|
||||
$this->error("Invalid escaping sequence $sq");
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function error(string $message = "Unexpected '%s'")
|
||||
{
|
||||
$last = isset($this->tokens[$this->pos]) ? $this->tokens[$this->pos] : null;
|
||||
$offset = $last ? $last[1] : strlen($this->input);
|
||||
$text = substr($this->input, 0, $offset);
|
||||
$line = substr_count($text, "\n");
|
||||
$col = $offset - strrpos("\n" . $text, "\n") + 1;
|
||||
$token = $last ? str_replace("\n", '<new line>', substr($last[0], 0, 40)) : 'end';
|
||||
throw new Exception(str_replace('%s', $token, $message) . " on line $line, column $col.");
|
||||
}
|
||||
}
|
84
vendor/nette/neon/src/Neon/Encoder.php
vendored
Normal file
84
vendor/nette/neon/src/Neon/Encoder.php
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Neon;
|
||||
|
||||
|
||||
/**
|
||||
* Simple generator for Nette Object Notation.
|
||||
*/
|
||||
final class Encoder
|
||||
{
|
||||
const BLOCK = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the NEON representation of a value.
|
||||
*/
|
||||
public function encode($var, int $flags = 0): string
|
||||
{
|
||||
if ($var instanceof \DateTimeInterface) {
|
||||
return $var->format('Y-m-d H:i:s O');
|
||||
|
||||
} elseif ($var instanceof Entity) {
|
||||
if ($var->value === Neon::CHAIN) {
|
||||
return implode('', array_map([$this, 'encode'], $var->attributes));
|
||||
}
|
||||
return $this->encode($var->value) . '('
|
||||
. (is_array($var->attributes) ? substr($this->encode($var->attributes), 1, -1) : '') . ')';
|
||||
}
|
||||
|
||||
if (is_object($var)) {
|
||||
$obj = $var;
|
||||
$var = [];
|
||||
foreach ($obj as $k => $v) {
|
||||
$var[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($var)) {
|
||||
$isList = !$var || array_keys($var) === range(0, count($var) - 1);
|
||||
$s = '';
|
||||
if ($flags & self::BLOCK) {
|
||||
if (count($var) === 0) {
|
||||
return '[]';
|
||||
}
|
||||
foreach ($var as $k => $v) {
|
||||
$v = $this->encode($v, self::BLOCK);
|
||||
$s .= ($isList ? '-' : $this->encode($k) . ':')
|
||||
. (strpos($v, "\n") === false
|
||||
? ' ' . $v . "\n"
|
||||
: "\n" . preg_replace('#^(?=.)#m', "\t", $v) . (substr($v, -2, 1) === "\n" ? '' : "\n"));
|
||||
}
|
||||
return $s;
|
||||
|
||||
} else {
|
||||
foreach ($var as $k => $v) {
|
||||
$s .= ($isList ? '' : $this->encode($k) . ': ') . $this->encode($v) . ', ';
|
||||
}
|
||||
return ($isList ? '[' : '{') . substr($s, 0, -2) . ($isList ? ']' : '}');
|
||||
}
|
||||
|
||||
} elseif (
|
||||
is_string($var)
|
||||
&& !is_numeric($var)
|
||||
&& !preg_match('~[\x00-\x1F]|^\d{4}|^(true|false|yes|no|on|off|null)\z~i', $var)
|
||||
&& preg_match('~^' . Decoder::PATTERNS[1] . '\z~x', $var) // 1 = literals
|
||||
) {
|
||||
return $var;
|
||||
|
||||
} elseif (is_float($var)) {
|
||||
$var = json_encode($var);
|
||||
return strpos($var, '.') === false ? $var . '.0' : $var;
|
||||
|
||||
} else {
|
||||
return json_encode($var, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
}
|
||||
}
|
36
vendor/nette/neon/src/Neon/Entity.php
vendored
Normal file
36
vendor/nette/neon/src/Neon/Entity.php
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Neon;
|
||||
|
||||
|
||||
/**
|
||||
* Representation of 'foo(bar=1)' literal
|
||||
*/
|
||||
final class Entity extends \stdClass
|
||||
{
|
||||
/** @var mixed */
|
||||
public $value;
|
||||
|
||||
/** @var array */
|
||||
public $attributes;
|
||||
|
||||
|
||||
public function __construct($value, array $attrs = [])
|
||||
{
|
||||
$this->value = $value;
|
||||
$this->attributes = $attrs;
|
||||
}
|
||||
|
||||
|
||||
public static function __set_state(array $properties)
|
||||
{
|
||||
return new self($properties['value'], $properties['attributes']);
|
||||
}
|
||||
}
|
18
vendor/nette/neon/src/Neon/Exception.php
vendored
Normal file
18
vendor/nette/neon/src/Neon/Exception.php
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Neon;
|
||||
|
||||
|
||||
/**
|
||||
* The exception that indicates error of NEON processing.
|
||||
*/
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
42
vendor/nette/neon/src/Neon/Neon.php
vendored
Normal file
42
vendor/nette/neon/src/Neon/Neon.php
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Neon;
|
||||
|
||||
|
||||
/**
|
||||
* Simple parser & generator for Nette Object Notation.
|
||||
*/
|
||||
final class Neon
|
||||
{
|
||||
const BLOCK = Encoder::BLOCK;
|
||||
|
||||
const CHAIN = '!!chain';
|
||||
|
||||
|
||||
/**
|
||||
* Returns the NEON representation of a value.
|
||||
*/
|
||||
public static function encode($var, int $flags = 0): string
|
||||
{
|
||||
$encoder = new Encoder;
|
||||
return $encoder->encode($var, $flags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decodes a NEON string.
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode(string $input)
|
||||
{
|
||||
$decoder = new Decoder;
|
||||
return $decoder->decode($input);
|
||||
}
|
||||
}
|
9
vendor/nette/neon/src/neon.php
vendored
Normal file
9
vendor/nette/neon/src/neon.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/Neon/Decoder.php';
|
||||
require __DIR__ . '/Neon/Encoder.php';
|
||||
require __DIR__ . '/Neon/Entity.php';
|
||||
require __DIR__ . '/Neon/Exception.php';
|
||||
require __DIR__ . '/Neon/Neon.php';
|
32
vendor/nette/neon/syntax.txt
vendored
Normal file
32
vendor/nette/neon/syntax.txt
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
Preprocessing
|
||||
-------------
|
||||
- tabs are converted to single space
|
||||
- \r is removed
|
||||
|
||||
|
||||
Comment
|
||||
-------
|
||||
Comment ::= '#' .*
|
||||
|
||||
|
||||
Values
|
||||
------
|
||||
Value ::= Boolean | Null | integer | float | String | DateTime | Literal | InlineArray | Entity
|
||||
Boolean ::= 'true' | 'TRUE' | 'false' | 'FALSE' | 'yes' | 'YES' | 'no' | 'NO'
|
||||
Null ::= 'null' | 'NULL' | ''
|
||||
String ::= "word\u231" | 'word'
|
||||
Literal ::= trimmed stream of characters [^#"',:=@[\]{}()\s!`] ( [^#,:=\]})(] | ':' [^\s,\]})] | \S '#' )*
|
||||
Entity ::= Value '(' ( ArrayEntry ',' )* ')'
|
||||
|
||||
|
||||
InlineArray
|
||||
-----------
|
||||
InlineArray ::= '{' ( ArrayEntry ',' )* '}' | '[' ( ArrayEntry ',' )* ']' | '(' ( ArrayEntry ',' )* ')'
|
||||
|
||||
ArrayEntry ::= Value | KeyValuePair
|
||||
KeyValuePair ::= Value '=' Value | Value ': ' Value
|
||||
|
||||
|
||||
BlockArray
|
||||
----------
|
||||
BlockArray ::= Indent ( '- ' Value | KeyValuePair ) EOL
|
37
vendor/nette/php-generator/composer.json
vendored
Normal file
37
vendor/nette/php-generator/composer.json
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "nette/php-generator",
|
||||
"description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.3 features.",
|
||||
"keywords": ["nette", "php", "code", "scaffolding"],
|
||||
"homepage": "https://nette.org",
|
||||
"license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Grudl",
|
||||
"homepage": "https://davidgrudl.com"
|
||||
},
|
||||
{
|
||||
"name": "Nette Community",
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1",
|
||||
"nette/utils": "^2.4.2 || ~3.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "^2.0",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["src/"]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/nette/php-generator/contributing.md
vendored
Normal file
33
vendor/nette/php-generator/contributing.md
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
How to contribute & use the issue tracker
|
||||
=========================================
|
||||
|
||||
Nette welcomes your contributions. There are several ways to help out:
|
||||
|
||||
* Create an issue on GitHub, if you have found a bug
|
||||
* Write test cases for open bug issues
|
||||
* Write fixes for open bug/feature issues, preferably with test cases included
|
||||
* Contribute to the [documentation](https://nette.org/en/writing)
|
||||
|
||||
Issues
|
||||
------
|
||||
|
||||
Please **do not use the issue tracker to ask questions**. We will be happy to help you
|
||||
on [Nette forum](https://forum.nette.org) or chat with us on [Gitter](https://gitter.im/nette/nette).
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more
|
||||
information. Please try to be as detailed as possible in your report.
|
||||
|
||||
**Feature requests** are welcome. But take a moment to find out whether your idea
|
||||
fits with the scope and aims of the project. It's up to *you* to make a strong
|
||||
case to convince the project's developers of the merits of this feature.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
If you'd like to contribute, please take a moment to read [the contributing guide](https://nette.org/en/contributing).
|
||||
|
||||
The best way to propose a feature is to discuss your ideas on [Nette forum](https://forum.nette.org) before implementing them.
|
||||
|
||||
Please do not fix whitespace, format code, or make a purely cosmetic patch.
|
||||
|
||||
Thanks! :heart:
|
60
vendor/nette/php-generator/license.md
vendored
Normal file
60
vendor/nette/php-generator/license.md
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
Licenses
|
||||
========
|
||||
|
||||
Good news! You may use Nette Framework under the terms of either
|
||||
the New BSD License or the GNU General Public License (GPL) version 2 or 3.
|
||||
|
||||
The BSD License is recommended for most projects. It is easy to understand and it
|
||||
places almost no restrictions on what you can do with the framework. If the GPL
|
||||
fits better to your project, you can use the framework under this license.
|
||||
|
||||
You don't have to notify anyone which license you are using. You can freely
|
||||
use Nette Framework in commercial projects as long as the copyright header
|
||||
remains intact.
|
||||
|
||||
Please be advised that the name "Nette Framework" is a protected trademark and its
|
||||
usage has some limitations. So please do not use word "Nette" in the name of your
|
||||
project or top-level domain, and choose a name that stands on its own merits.
|
||||
If your stuff is good, it will not take long to establish a reputation for yourselves.
|
||||
|
||||
|
||||
New BSD License
|
||||
---------------
|
||||
|
||||
Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "Nette Framework" nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as is" and
|
||||
any express or implied warranties, including, but not limited to, the implied
|
||||
warranties of merchantability and fitness for a particular purpose are
|
||||
disclaimed. In no event shall the copyright owner or contributors be liable for
|
||||
any direct, indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or services;
|
||||
loss of use, data, or profits; or business interruption) however caused and on
|
||||
any theory of liability, whether in contract, strict liability, or tort
|
||||
(including negligence or otherwise) arising in any way out of the use of this
|
||||
software, even if advised of the possibility of such damage.
|
||||
|
||||
|
||||
GNU General Public License
|
||||
--------------------------
|
||||
|
||||
GPL licenses are very very long, so instead of including them here we offer
|
||||
you URLs with full text:
|
||||
|
||||
- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
|
||||
- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
|
512
vendor/nette/php-generator/readme.md
vendored
Normal file
512
vendor/nette/php-generator/readme.md
vendored
Normal file
|
@ -0,0 +1,512 @@
|
|||
Nette PHP Generator
|
||||
===================
|
||||
|
||||
[](https://packagist.org/packages/nette/php-generator)
|
||||
[](https://travis-ci.org/nette/php-generator)
|
||||
[](https://coveralls.io/github/nette/php-generator?branch=master)
|
||||
[](https://github.com/nette/php-generator/releases)
|
||||
[](https://github.com/nette/php-generator/blob/master/license.md)
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Generate PHP code, classes, namespaces etc. with a simple programmatical API.
|
||||
|
||||
Documentation can be found on the [website](https://doc.nette.org/php-generator).
|
||||
|
||||
If you like Nette, **[please make a donation now](https://nette.org/donate)**. Thank you!
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
The recommended way to install is via Composer:
|
||||
|
||||
```
|
||||
composer require nette/php-generator
|
||||
```
|
||||
|
||||
- v3.2 requires PHP 7.1 or newer (is compatible up to 7.3)
|
||||
- v3.1 requires PHP 7.1 or newer (is compatible up to 7.3)
|
||||
- v3.0 requires PHP 7.0 or newer (is compatible up to 7.3)
|
||||
- v2.6 requires PHP 5.6 or newer (is compatible up to 7.3)
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Usage is very easy. Let's start with a straightforward example of generating class:
|
||||
|
||||
```php
|
||||
$class = new Nette\PhpGenerator\ClassType('Demo');
|
||||
|
||||
$class
|
||||
->setFinal()
|
||||
->setExtends('ParentClass')
|
||||
->addImplement('Countable')
|
||||
->addTrait('Nette\SmartObject')
|
||||
->addComment("Description of class.\nSecond line\n")
|
||||
->addComment('@property-read Nette\Forms\Form $form');
|
||||
|
||||
// to generate PHP code simply cast to string or use echo:
|
||||
echo $class;
|
||||
```
|
||||
|
||||
It will render this result:
|
||||
|
||||
```php
|
||||
/**
|
||||
* Description of class.
|
||||
* Second line
|
||||
*
|
||||
* @property-read Nette\Forms\Form $form
|
||||
*/
|
||||
final class Demo extends ParentClass implements Countable
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
}
|
||||
```
|
||||
|
||||
We can add constants and properties:
|
||||
|
||||
```php
|
||||
$class->addConstant('ID', 123);
|
||||
|
||||
$class->addProperty('items', [1, 2, 3])
|
||||
->setVisibility('private')
|
||||
->setStatic()
|
||||
->addComment('@var int[]');
|
||||
```
|
||||
|
||||
It generates:
|
||||
|
||||
```php
|
||||
const ID = 123;
|
||||
|
||||
/** @var int[] */
|
||||
private static $items = [1, 2, 3];
|
||||
```
|
||||
|
||||
And we can add methods with parameters:
|
||||
|
||||
```php
|
||||
$method = $class->addMethod('count')
|
||||
->addComment('Count it.')
|
||||
->addComment('@return int')
|
||||
->setFinal()
|
||||
->setVisibility('protected')
|
||||
->setBody('return count($items ?: $this->items);');
|
||||
|
||||
$method->addParameter('items', []) // $items = []
|
||||
->setReference() // &$items = []
|
||||
->setTypeHint('array'); // array &$items = []
|
||||
```
|
||||
|
||||
It results in:
|
||||
|
||||
```php
|
||||
/**
|
||||
* Count it.
|
||||
* @return int
|
||||
*/
|
||||
final protected function count(array &$items = [])
|
||||
{
|
||||
return count($items ?: $this->items);
|
||||
}
|
||||
```
|
||||
|
||||
If the property, constant, method or parameter already exist, it will be overwritten.
|
||||
|
||||
Members can be removed using `removeProperty()`, `removeConstant()`, `removeMethod()` or `removeParameter()`.
|
||||
|
||||
PHP Generator supports all new PHP 7.3 features:
|
||||
|
||||
```php
|
||||
$class = new Nette\PhpGenerator\ClassType('Demo');
|
||||
|
||||
$class->addConstant('ID', 123)
|
||||
->setVisibility('private'); // constant visiblity
|
||||
|
||||
$method = $class->addMethod('getValue')
|
||||
->setReturnType('int') // method return type
|
||||
->setReturnNullable() // nullable return type
|
||||
->setBody('return count($this->items);');
|
||||
|
||||
$method->addParameter('id')
|
||||
->setTypeHint('int') // scalar type hint
|
||||
->setNullable(); // nullable type hint
|
||||
|
||||
echo $class;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
class Demo
|
||||
{
|
||||
private const ID = 123;
|
||||
|
||||
public function getValue(?int $id): ?int
|
||||
{
|
||||
return count($this->items);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can also add existing `Method`, `Property` or `Constant` objects to the class:
|
||||
|
||||
```php
|
||||
$method = new Nette\PhpGenerator\Method('getHandle');
|
||||
$property = new Nette\PhpGenerator\Property('handle');
|
||||
$const = new Nette\PhpGenerator\Constant('ROLE');
|
||||
|
||||
$class = (new Nette\PhpGenerator\ClassType('Demo'))
|
||||
->addMember($method)
|
||||
->addMember($property)
|
||||
->addMember($const);
|
||||
```
|
||||
|
||||
You can clone existing methods, properties and constants with a different name using `cloneWithName()`:
|
||||
|
||||
```php
|
||||
$methodCount = $class->getMethod('count');
|
||||
$methodRecount = $methodCount->cloneWithName('recount');
|
||||
$class->addMember($methodRecount);
|
||||
```
|
||||
|
||||
Tabs versus spaces
|
||||
------------------
|
||||
|
||||
The generated code uses tabs for indentation. If you want to have the output compatible with PSR-2 or PSR-12, use `PsrPrinter`:
|
||||
|
||||
```php
|
||||
$printer = new Nette\PhpGenerator\PsrPrinter;
|
||||
|
||||
$class = new Nette\PhpGenerator\ClassType('Demo');
|
||||
// ...
|
||||
|
||||
echo $printer->printClass($class); // 4 spaces indentation
|
||||
```
|
||||
|
||||
It can be used also for functions, closures, namespaces etc.
|
||||
|
||||
|
||||
Literals
|
||||
--------
|
||||
|
||||
You can pass any PHP code to property or parameter default values via `PhpLiteral`:
|
||||
|
||||
```php
|
||||
use Nette\PhpGenerator\PhpLiteral;
|
||||
|
||||
$class = new Nette\PhpGenerator\ClassType('Demo');
|
||||
|
||||
$class->addProperty('foo', new PhpLiteral('Iterator::SELF_FIRST'));
|
||||
|
||||
$class->addMethod('bar')
|
||||
->addParameter('id', new PhpLiteral('1 + 2'));
|
||||
|
||||
echo $class;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
class Demo
|
||||
{
|
||||
public $foo = Iterator::SELF_FIRST;
|
||||
|
||||
public function bar($id = 1 + 2)
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Interface or Trait
|
||||
------------------
|
||||
|
||||
```php
|
||||
$class = new Nette\PhpGenerator\ClassType('DemoInterface');
|
||||
$class->setType('interface');
|
||||
// or $class->setType('trait');
|
||||
```
|
||||
|
||||
Trait Resolutions and Visibility
|
||||
--------------------------------
|
||||
|
||||
```php
|
||||
$class = new Nette\PhpGenerator\ClassType('Demo');
|
||||
$class->addTrait('SmartObject', ['sayHello as protected']);
|
||||
echo $class;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
class Demo
|
||||
{
|
||||
use SmartObject {
|
||||
sayHello as protected;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Anonymous Class
|
||||
---------------
|
||||
|
||||
```php
|
||||
$class = new Nette\PhpGenerator\ClassType(null);
|
||||
$class->addMethod('__construct')
|
||||
->addParameter('foo');
|
||||
|
||||
echo '$obj = new class ($val) ' . $class . ';';
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
$obj = new class ($val) {
|
||||
|
||||
public function __construct($foo)
|
||||
{
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Global Function
|
||||
---------------
|
||||
|
||||
Code of function:
|
||||
|
||||
```php
|
||||
$function = new Nette\PhpGenerator\GlobalFunction('foo');
|
||||
$function->setBody('return $a + $b;');
|
||||
$function->addParameter('a');
|
||||
$function->addParameter('b');
|
||||
echo $function;
|
||||
|
||||
// or use PsrPrinter for output compatible with PSR-2 / PSR-12
|
||||
// echo (new Nette\PhpGenerator\PsrPrinter)->printFunction($function);
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
function foo($a, $b)
|
||||
{
|
||||
return $a + $b;
|
||||
}
|
||||
```
|
||||
|
||||
Closure
|
||||
-------
|
||||
|
||||
Code of closure:
|
||||
|
||||
```php
|
||||
$closure = new Nette\PhpGenerator\Closure;
|
||||
$closure->setBody('return $a + $b;');
|
||||
$closure->addParameter('a');
|
||||
$closure->addParameter('b');
|
||||
$closure->addUse('c')
|
||||
->setReference();
|
||||
echo $closure;
|
||||
|
||||
// or use PsrPrinter for output compatible with PSR-2 / PSR-12
|
||||
// echo (new Nette\PhpGenerator\PsrPrinter)->printClosure($closure);
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
function ($a, $b) use (&$c) {
|
||||
return $a + $b;
|
||||
}
|
||||
```
|
||||
|
||||
Method and Function Body Generator
|
||||
----------------------------------
|
||||
|
||||
You can use special placeholders for handy way to generate method or function body.
|
||||
|
||||
Simple placeholders:
|
||||
|
||||
```php
|
||||
$str = 'any string';
|
||||
$num = 3;
|
||||
$function = new Nette\PhpGenerator\GlobalFunction('foo');
|
||||
$function->addBody('return strlen(?, ?);', [$str, $num]);
|
||||
echo $function;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
function foo()
|
||||
{
|
||||
return strlen('any string', 3);
|
||||
}
|
||||
```
|
||||
|
||||
Variadic placeholder:
|
||||
|
||||
```php
|
||||
$items = [1, 2, 3];
|
||||
$function = new Nette\PhpGenerator\GlobalFunction('foo');
|
||||
$function->setBody('myfunc(...?);', [$items]);
|
||||
echo $function;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
function foo()
|
||||
{
|
||||
myfunc(1, 2, 3);
|
||||
}
|
||||
```
|
||||
|
||||
Escape placeholder using slash:
|
||||
|
||||
```php
|
||||
$num = 3;
|
||||
$function = new Nette\PhpGenerator\GlobalFunction('foo');
|
||||
$function->addParameter('a');
|
||||
$function->addBody('return $a \? 10 : ?;', [$num]);
|
||||
echo $function;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
function foo($a)
|
||||
{
|
||||
return $a ? 10 : 3;
|
||||
}
|
||||
```
|
||||
|
||||
Namespace
|
||||
---------
|
||||
|
||||
Classes, traits and interfaces (hereinafter classes) can be grouped into namespaces:
|
||||
|
||||
```php
|
||||
$namespace = new Nette\PhpGenerator\PhpNamespace('Foo');
|
||||
|
||||
$class = $namespace->addClass('Task');
|
||||
$interface = $namespace->addInterface('Countable');
|
||||
$trait = $namespace->addTrait('NameAware');
|
||||
|
||||
// or
|
||||
$class = new Nette\PhpGenerator\ClassType('Task');
|
||||
$namespace->add($class);
|
||||
```
|
||||
|
||||
If the class already exists, it will be overwritten.
|
||||
|
||||
You can define use-statements:
|
||||
|
||||
```php
|
||||
$namespace->addUse('Http\Request'); // use Http\Request;
|
||||
$namespace->addUse('Http\Request', 'HttpReq'); // use Http\Request as HttpReq;
|
||||
```
|
||||
|
||||
**IMPORTANT NOTE:** when the class is part of the namespace, it is rendered slightly differently: all types (ie. type hints, return types, parent class name,
|
||||
implemented interfaces and used traits) are automatically *resolved*. It means that you have to **use full class names** in definitions
|
||||
and they will be replaced with aliases (according to the use-statements) or fully qualified names in the resulting code:
|
||||
|
||||
```php
|
||||
$namespace = new Nette\PhpGenerator\PhpNamespace('Foo');
|
||||
$namespace->addUse('Bar\AliasedClass');
|
||||
|
||||
$class = $namespace->addClass('Demo');
|
||||
$class->addImplement('Foo\A') // it will resolve to A
|
||||
->addTrait('Bar\AliasedClass'); // it will resolve to AliasedClass
|
||||
|
||||
$method = $class->addMethod('method');
|
||||
$method->addComment('@return ' . $namespace->unresolveName('Foo\D')); // in comments resolve manually
|
||||
$method->addParameter('arg')
|
||||
->setTypeHint('Bar\OtherClass'); // it will resolve to \Bar\OtherClass
|
||||
|
||||
echo $namespace;
|
||||
|
||||
// or use PsrPrinter for output compatible with PSR-2 / PSR-12
|
||||
// echo (new Nette\PhpGenerator\PsrPrinter)->printNamespace($namespace);
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
namespace Foo;
|
||||
|
||||
use Bar\AliasedClass;
|
||||
|
||||
class Demo implements A
|
||||
{
|
||||
use AliasedClass;
|
||||
|
||||
/**
|
||||
* @return D
|
||||
*/
|
||||
public function method(\Bar\OtherClass $arg)
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
PHP Files
|
||||
---------
|
||||
|
||||
PHP files can contains multiple classes, namespaces and comments:
|
||||
|
||||
```php
|
||||
$file = new Nette\PhpGenerator\PhpFile;
|
||||
$file->addComment('This file is auto-generated.');
|
||||
$file->setStrictTypes(); // adds declare(strict_types=1)
|
||||
|
||||
$namespace = $file->addNamespace('Foo');
|
||||
$class = $namespace->addClass('A');
|
||||
$class->addMethod('hello');
|
||||
|
||||
echo $file;
|
||||
|
||||
// or use PsrPrinter for output compatible with PSR-2 / PSR-12
|
||||
// echo (new Nette\PhpGenerator\PsrPrinter)->printFile($file);
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is auto-generated.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Foo;
|
||||
|
||||
class A
|
||||
{
|
||||
public function hello()
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Generate using Reflection
|
||||
-------------------------
|
||||
|
||||
Another common use case is to create class or method based on existing ones:
|
||||
|
||||
```php
|
||||
$class = Nette\PhpGenerator\ClassType::from(PDO::class);
|
||||
|
||||
$function = Nette\PhpGenerator\GlobalFunction::from('trim');
|
||||
|
||||
$closure = Nette\PhpGenerator\Closure::from(
|
||||
function (stdClass $a, $b = null) {}
|
||||
);
|
||||
```
|
495
vendor/nette/php-generator/src/PhpGenerator/ClassType.php
vendored
Normal file
495
vendor/nette/php-generator/src/PhpGenerator/ClassType.php
vendored
Normal file
|
@ -0,0 +1,495 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Class/Interface/Trait description.
|
||||
*
|
||||
* @property Method[] $methods
|
||||
* @property Property[] $properties
|
||||
*/
|
||||
final class ClassType
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
use Traits\CommentAware;
|
||||
|
||||
public const
|
||||
TYPE_CLASS = 'class',
|
||||
TYPE_INTERFACE = 'interface',
|
||||
TYPE_TRAIT = 'trait';
|
||||
|
||||
public const
|
||||
VISIBILITY_PUBLIC = 'public',
|
||||
VISIBILITY_PROTECTED = 'protected',
|
||||
VISIBILITY_PRIVATE = 'private';
|
||||
|
||||
/** @var PhpNamespace|null */
|
||||
private $namespace;
|
||||
|
||||
/** @var string|null */
|
||||
private $name;
|
||||
|
||||
/** @var string class|interface|trait */
|
||||
private $type = self::TYPE_CLASS;
|
||||
|
||||
/** @var bool */
|
||||
private $final = false;
|
||||
|
||||
/** @var bool */
|
||||
private $abstract = false;
|
||||
|
||||
/** @var string|string[] */
|
||||
private $extends = [];
|
||||
|
||||
/** @var string[] */
|
||||
private $implements = [];
|
||||
|
||||
/** @var array[] */
|
||||
private $traits = [];
|
||||
|
||||
/** @var Constant[] name => Constant */
|
||||
private $consts = [];
|
||||
|
||||
/** @var Property[] name => Property */
|
||||
private $properties = [];
|
||||
|
||||
/** @var Method[] name => Method */
|
||||
private $methods = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string|object $class
|
||||
* @return static
|
||||
*/
|
||||
public static function from($class): self
|
||||
{
|
||||
return (new Factory)->fromClassReflection(new \ReflectionClass($class));
|
||||
}
|
||||
|
||||
|
||||
public function __construct(string $name = null, PhpNamespace $namespace = null)
|
||||
{
|
||||
$this->setName($name);
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
try {
|
||||
return (new Printer)->printClass($this, $this->namespace);
|
||||
} catch (\Throwable $e) {
|
||||
trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deprecated: an object can be in multiple namespaces.
|
||||
* @deprecated
|
||||
*/
|
||||
public function getNamespace(): ?PhpNamespace
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setName(?string $name): self
|
||||
{
|
||||
if ($name !== null && !Helpers::isIdentifier($name)) {
|
||||
throw new Nette\InvalidArgumentException("Value '$name' is not valid class name.");
|
||||
}
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setType(string $type): self
|
||||
{
|
||||
if (!in_array($type, [self::TYPE_CLASS, self::TYPE_INTERFACE, self::TYPE_TRAIT], true)) {
|
||||
throw new Nette\InvalidArgumentException('Argument must be class|interface|trait.');
|
||||
}
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setFinal(bool $state = true): self
|
||||
{
|
||||
$this->final = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isFinal(): bool
|
||||
{
|
||||
return $this->final;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setAbstract(bool $state = true): self
|
||||
{
|
||||
$this->abstract = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isAbstract(): bool
|
||||
{
|
||||
return $this->abstract;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string|string[] $names
|
||||
* @return static
|
||||
*/
|
||||
public function setExtends($names): self
|
||||
{
|
||||
if (!is_string($names) && !is_array($names)) {
|
||||
throw new Nette\InvalidArgumentException('Argument must be string or string[].');
|
||||
}
|
||||
$this->validateNames((array) $names);
|
||||
$this->extends = $names;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|string[]
|
||||
*/
|
||||
public function getExtends()
|
||||
{
|
||||
return $this->extends;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function addExtend(string $name): self
|
||||
{
|
||||
$this->validateNames([$name]);
|
||||
$this->extends = (array) $this->extends;
|
||||
$this->extends[] = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string[] $names
|
||||
* @return static
|
||||
*/
|
||||
public function setImplements(array $names): self
|
||||
{
|
||||
$this->validateNames($names);
|
||||
$this->implements = $names;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getImplements(): array
|
||||
{
|
||||
return $this->implements;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function addImplement(string $name): self
|
||||
{
|
||||
$this->validateNames([$name]);
|
||||
$this->implements[] = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string[] $names
|
||||
* @return static
|
||||
*/
|
||||
public function setTraits(array $names): self
|
||||
{
|
||||
$this->validateNames($names);
|
||||
$this->traits = array_fill_keys($names, []);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getTraits(): array
|
||||
{
|
||||
return array_keys($this->traits);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getTraitResolutions(): array
|
||||
{
|
||||
return $this->traits;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function addTrait(string $name, array $resolutions = []): self
|
||||
{
|
||||
$this->validateNames([$name]);
|
||||
$this->traits[$name] = $resolutions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Method|Property|Constant $member
|
||||
* @return static
|
||||
*/
|
||||
public function addMember($member): self
|
||||
{
|
||||
if ($member instanceof Method) {
|
||||
if ($this->type === self::TYPE_INTERFACE) {
|
||||
$member->setBody(null);
|
||||
}
|
||||
$this->methods[$member->getName()] = $member;
|
||||
|
||||
} elseif ($member instanceof Property) {
|
||||
$this->properties[$member->getName()] = $member;
|
||||
|
||||
} elseif ($member instanceof Constant) {
|
||||
$this->consts[$member->getName()] = $member;
|
||||
|
||||
} else {
|
||||
throw new Nette\InvalidArgumentException('Argument must be Method|Property|Constant.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Constant[]|mixed[] $consts
|
||||
* @return static
|
||||
*/
|
||||
public function setConstants(array $consts): self
|
||||
{
|
||||
$this->consts = [];
|
||||
foreach ($consts as $k => $v) {
|
||||
$const = $v instanceof Constant ? $v : (new Constant($k))->setValue($v);
|
||||
$this->consts[$const->getName()] = $const;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Constant[]
|
||||
*/
|
||||
public function getConstants(): array
|
||||
{
|
||||
return $this->consts;
|
||||
}
|
||||
|
||||
|
||||
public function addConstant(string $name, $value): Constant
|
||||
{
|
||||
return $this->consts[$name] = (new Constant($name))->setValue($value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function removeConstant(string $name): self
|
||||
{
|
||||
unset($this->consts[$name]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Property[] $props
|
||||
* @return static
|
||||
*/
|
||||
public function setProperties(array $props): self
|
||||
{
|
||||
$this->properties = [];
|
||||
foreach ($props as $v) {
|
||||
if (!$v instanceof Property) {
|
||||
throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Property[].');
|
||||
}
|
||||
$this->properties[$v->getName()] = $v;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Property[]
|
||||
*/
|
||||
public function getProperties(): array
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
|
||||
|
||||
public function getProperty(string $name): Property
|
||||
{
|
||||
if (!isset($this->properties[$name])) {
|
||||
throw new Nette\InvalidArgumentException("Property '$name' not found.");
|
||||
}
|
||||
return $this->properties[$name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name without $
|
||||
*/
|
||||
public function addProperty(string $name, $value = null): Property
|
||||
{
|
||||
return $this->properties[$name] = (new Property($name))->setValue($value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name without $
|
||||
* @return static
|
||||
*/
|
||||
public function removeProperty(string $name): self
|
||||
{
|
||||
unset($this->properties[$name]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Method[] $methods
|
||||
* @return static
|
||||
*/
|
||||
public function setMethods(array $methods): self
|
||||
{
|
||||
$this->methods = [];
|
||||
foreach ($methods as $v) {
|
||||
if (!$v instanceof Method) {
|
||||
throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Method[].');
|
||||
}
|
||||
$this->methods[$v->getName()] = $v;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Method[]
|
||||
*/
|
||||
public function getMethods(): array
|
||||
{
|
||||
return $this->methods;
|
||||
}
|
||||
|
||||
|
||||
public function getMethod(string $name): Method
|
||||
{
|
||||
if (!isset($this->methods[$name])) {
|
||||
throw new Nette\InvalidArgumentException("Method '$name' not found.");
|
||||
}
|
||||
return $this->methods[$name];
|
||||
}
|
||||
|
||||
|
||||
public function addMethod(string $name): Method
|
||||
{
|
||||
$method = new Method($name);
|
||||
if ($this->type === self::TYPE_INTERFACE) {
|
||||
$method->setBody(null);
|
||||
} else {
|
||||
$method->setVisibility(self::VISIBILITY_PUBLIC);
|
||||
}
|
||||
return $this->methods[$name] = $method;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function removeMethod(string $name): self
|
||||
{
|
||||
unset($this->methods[$name]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Nette\InvalidStateException
|
||||
*/
|
||||
public function validate(): void
|
||||
{
|
||||
if ($this->abstract && $this->final) {
|
||||
throw new Nette\InvalidStateException('Class cannot be abstract and final.');
|
||||
|
||||
} elseif (!$this->name && ($this->abstract || $this->final)) {
|
||||
throw new Nette\InvalidStateException('Anonymous class cannot be abstract or final.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function validateNames(array $names): void
|
||||
{
|
||||
foreach ($names as $name) {
|
||||
if (!Helpers::isNamespaceIdentifier($name, true)) {
|
||||
throw new Nette\InvalidArgumentException("Value '$name' is not valid class name.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$clone = function ($item) { return clone $item; };
|
||||
$this->consts = array_map($clone, $this->consts);
|
||||
$this->properties = array_map($clone, $this->properties);
|
||||
$this->methods = array_map($clone, $this->methods);
|
||||
}
|
||||
}
|
70
vendor/nette/php-generator/src/PhpGenerator/Closure.php
vendored
Normal file
70
vendor/nette/php-generator/src/PhpGenerator/Closure.php
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Closure.
|
||||
*
|
||||
* @property string $body
|
||||
*/
|
||||
final class Closure
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
use Traits\FunctionLike;
|
||||
|
||||
/** @var Parameter[] */
|
||||
private $uses = [];
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public static function from(\Closure $closure): self
|
||||
{
|
||||
return (new Factory)->fromFunctionReflection(new \ReflectionFunction($closure));
|
||||
}
|
||||
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
try {
|
||||
return (new Printer)->printClosure($this);
|
||||
} catch (\Throwable $e) {
|
||||
trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Parameter[] $uses
|
||||
* @return static
|
||||
*/
|
||||
public function setUses(array $uses): self
|
||||
{
|
||||
(function (Parameter ...$uses) {})(...$uses);
|
||||
$this->uses = $uses;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getUses(): array
|
||||
{
|
||||
return $this->uses;
|
||||
}
|
||||
|
||||
|
||||
public function addUse(string $name): Parameter
|
||||
{
|
||||
return $this->uses[] = new Parameter($name);
|
||||
}
|
||||
}
|
43
vendor/nette/php-generator/src/PhpGenerator/Constant.php
vendored
Normal file
43
vendor/nette/php-generator/src/PhpGenerator/Constant.php
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Class constant.
|
||||
*/
|
||||
final class Constant
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
use Traits\NameAware;
|
||||
use Traits\VisibilityAware;
|
||||
use Traits\CommentAware;
|
||||
|
||||
/** @var mixed */
|
||||
private $value;
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setValue($val): self
|
||||
{
|
||||
$this->value = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
134
vendor/nette/php-generator/src/PhpGenerator/Factory.php
vendored
Normal file
134
vendor/nette/php-generator/src/PhpGenerator/Factory.php
vendored
Normal file
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a representation based on reflection.
|
||||
*/
|
||||
final class Factory
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
public function fromClassReflection(\ReflectionClass $from): ClassType
|
||||
{
|
||||
$class = $from->isAnonymous()
|
||||
? new ClassType
|
||||
: new ClassType($from->getShortName(), new PhpNamespace($from->getNamespaceName()));
|
||||
$class->setType($from->isInterface() ? $class::TYPE_INTERFACE : ($from->isTrait() ? $class::TYPE_TRAIT : $class::TYPE_CLASS));
|
||||
$class->setFinal($from->isFinal() && $class->getType() === $class::TYPE_CLASS);
|
||||
$class->setAbstract($from->isAbstract() && $class->getType() === $class::TYPE_CLASS);
|
||||
|
||||
$ifaces = $from->getInterfaceNames();
|
||||
foreach ($ifaces as $iface) {
|
||||
$ifaces = array_filter($ifaces, function (string $item) use ($iface): bool {
|
||||
return !is_subclass_of($iface, $item);
|
||||
});
|
||||
}
|
||||
$class->setImplements($ifaces);
|
||||
|
||||
$class->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
|
||||
if ($from->getParentClass()) {
|
||||
$class->setExtends($from->getParentClass()->getName());
|
||||
$class->setImplements(array_diff($class->getImplements(), $from->getParentClass()->getInterfaceNames()));
|
||||
}
|
||||
$props = $methods = [];
|
||||
foreach ($from->getProperties() as $prop) {
|
||||
if ($prop->isDefault() && $prop->getDeclaringClass()->getName() === $from->getName()) {
|
||||
$props[] = $this->fromPropertyReflection($prop);
|
||||
}
|
||||
}
|
||||
$class->setProperties($props);
|
||||
foreach ($from->getMethods() as $method) {
|
||||
if ($method->getDeclaringClass()->getName() === $from->getName()) {
|
||||
$methods[] = $this->fromMethodReflection($method);
|
||||
}
|
||||
}
|
||||
$class->setMethods($methods);
|
||||
$class->setConstants($from->getConstants());
|
||||
return $class;
|
||||
}
|
||||
|
||||
|
||||
public function fromMethodReflection(\ReflectionMethod $from): Method
|
||||
{
|
||||
$method = new Method($from->getName());
|
||||
$method->setParameters(array_map([$this, 'fromParameterReflection'], $from->getParameters()));
|
||||
$method->setStatic($from->isStatic());
|
||||
$isInterface = $from->getDeclaringClass()->isInterface();
|
||||
$method->setVisibility($from->isPrivate()
|
||||
? ClassType::VISIBILITY_PRIVATE
|
||||
: ($from->isProtected() ? ClassType::VISIBILITY_PROTECTED : ($isInterface ? null : ClassType::VISIBILITY_PUBLIC))
|
||||
);
|
||||
$method->setFinal($from->isFinal());
|
||||
$method->setAbstract($from->isAbstract() && !$isInterface);
|
||||
$method->setBody($from->isAbstract() ? null : '');
|
||||
$method->setReturnReference($from->returnsReference());
|
||||
$method->setVariadic($from->isVariadic());
|
||||
$method->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
|
||||
if ($from->hasReturnType()) {
|
||||
$method->setReturnType((string) $from->getReturnType());
|
||||
$method->setReturnNullable($from->getReturnType()->allowsNull());
|
||||
}
|
||||
return $method;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return GlobalFunction|Closure
|
||||
*/
|
||||
public function fromFunctionReflection(\ReflectionFunction $from)
|
||||
{
|
||||
$function = $from->isClosure() ? new Closure : new GlobalFunction($from->getName());
|
||||
$function->setParameters(array_map([$this, 'fromParameterReflection'], $from->getParameters()));
|
||||
$function->setReturnReference($from->returnsReference());
|
||||
$function->setVariadic($from->isVariadic());
|
||||
if (!$from->isClosure()) {
|
||||
$function->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
|
||||
}
|
||||
if ($from->hasReturnType()) {
|
||||
$function->setReturnType((string) $from->getReturnType());
|
||||
$function->setReturnNullable($from->getReturnType()->allowsNull());
|
||||
}
|
||||
return $function;
|
||||
}
|
||||
|
||||
|
||||
public function fromParameterReflection(\ReflectionParameter $from): Parameter
|
||||
{
|
||||
$param = new Parameter($from->getName());
|
||||
$param->setReference($from->isPassedByReference());
|
||||
$param->setTypeHint($from->hasType() ? (string) $from->getType() : null);
|
||||
$param->setNullable($from->hasType() && $from->getType()->allowsNull());
|
||||
if ($from->isDefaultValueAvailable()) {
|
||||
$param->setDefaultValue($from->isDefaultValueConstant()
|
||||
? new PhpLiteral($from->getDefaultValueConstantName())
|
||||
: $from->getDefaultValue());
|
||||
$param->setNullable($param->isNullable() && $param->getDefaultValue() !== null);
|
||||
}
|
||||
return $param;
|
||||
}
|
||||
|
||||
|
||||
public function fromPropertyReflection(\ReflectionProperty $from): Property
|
||||
{
|
||||
$prop = new Property($from->getName());
|
||||
$prop->setValue($from->getDeclaringClass()->getDefaultProperties()[$prop->getName()] ?? null);
|
||||
$prop->setStatic($from->isStatic());
|
||||
$prop->setVisibility($from->isPrivate()
|
||||
? ClassType::VISIBILITY_PRIVATE
|
||||
: ($from->isProtected() ? ClassType::VISIBILITY_PROTECTED : ClassType::VISIBILITY_PUBLIC)
|
||||
);
|
||||
$prop->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
|
||||
return $prop;
|
||||
}
|
||||
}
|
44
vendor/nette/php-generator/src/PhpGenerator/GlobalFunction.php
vendored
Normal file
44
vendor/nette/php-generator/src/PhpGenerator/GlobalFunction.php
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Global function.
|
||||
*
|
||||
* @property string $body
|
||||
*/
|
||||
final class GlobalFunction
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
use Traits\FunctionLike;
|
||||
use Traits\NameAware;
|
||||
use Traits\CommentAware;
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public static function from(string $function): self
|
||||
{
|
||||
return (new Factory)->fromFunctionReflection(new \ReflectionFunction($function));
|
||||
}
|
||||
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
try {
|
||||
return (new Printer)->printFunction($this);
|
||||
} catch (\Throwable $e) {
|
||||
trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
273
vendor/nette/php-generator/src/PhpGenerator/Helpers.php
vendored
Normal file
273
vendor/nette/php-generator/src/PhpGenerator/Helpers.php
vendored
Normal file
|
@ -0,0 +1,273 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* PHP code generator utils.
|
||||
*/
|
||||
final class Helpers
|
||||
{
|
||||
use Nette\StaticClass;
|
||||
|
||||
public const PHP_IDENT = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
|
||||
|
||||
public const WRAP_LENGTH = 100;
|
||||
|
||||
public const INDENT_LENGTH = 4;
|
||||
|
||||
private const MAX_DEPTH = 50;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a PHP representation of a variable.
|
||||
*/
|
||||
public static function dump($var): string
|
||||
{
|
||||
return self::_dump($var);
|
||||
}
|
||||
|
||||
|
||||
private static function _dump(&$var, int $level = 0)
|
||||
{
|
||||
if ($var instanceof PhpLiteral) {
|
||||
return (string) $var;
|
||||
|
||||
} elseif (is_float($var)) {
|
||||
if (is_finite($var)) {
|
||||
$var = var_export($var, true);
|
||||
return strpos($var, '.') === false ? $var . '.0' : $var; // workaround for PHP < 7.0.2
|
||||
}
|
||||
return str_replace('.0', '', var_export($var, true)); // workaround for PHP 7.0.2
|
||||
|
||||
} elseif ($var === null) {
|
||||
return 'null';
|
||||
|
||||
} elseif (is_string($var) && (preg_match('#[^\x09\x20-\x7E\xA0-\x{10FFFF}]#u', $var) || preg_last_error())) {
|
||||
static $table;
|
||||
if ($table === null) {
|
||||
foreach (array_merge(range("\x00", "\x1F"), range("\x7F", "\xFF")) as $ch) {
|
||||
$table[$ch] = '\x' . str_pad(dechex(ord($ch)), 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
$table['\\'] = '\\\\';
|
||||
$table["\r"] = '\r';
|
||||
$table["\n"] = '\n';
|
||||
$table["\t"] = '\t';
|
||||
$table['$'] = '\$';
|
||||
$table['"'] = '\"';
|
||||
}
|
||||
return '"' . strtr($var, $table) . '"';
|
||||
|
||||
} elseif (is_string($var)) {
|
||||
return "'" . preg_replace('#\'|\\\\(?=[\'\\\\]|\z)#', '\\\\$0', $var) . "'";
|
||||
|
||||
} elseif (is_array($var)) {
|
||||
$space = str_repeat("\t", $level);
|
||||
|
||||
static $marker;
|
||||
if ($marker === null) {
|
||||
$marker = uniqid("\x00", true);
|
||||
}
|
||||
if (empty($var)) {
|
||||
$out = '';
|
||||
|
||||
} elseif ($level > self::MAX_DEPTH || isset($var[$marker])) {
|
||||
throw new Nette\InvalidArgumentException('Nesting level too deep or recursive dependency.');
|
||||
|
||||
} else {
|
||||
$out = '';
|
||||
$outWrapped = "\n$space";
|
||||
$var[$marker] = true;
|
||||
$counter = 0;
|
||||
foreach ($var as $k => &$v) {
|
||||
if ($k !== $marker) {
|
||||
$item = ($k === $counter ? '' : self::_dump($k, $level + 1) . ' => ') . self::_dump($v, $level + 1);
|
||||
$counter = is_int($k) ? max($k + 1, $counter) : $counter;
|
||||
$out .= ($out === '' ? '' : ', ') . $item;
|
||||
$outWrapped .= "\t$item,\n$space";
|
||||
}
|
||||
}
|
||||
unset($var[$marker]);
|
||||
}
|
||||
$wrap = strpos($out, "\n") !== false || strlen($out) > self::WRAP_LENGTH - $level * self::INDENT_LENGTH;
|
||||
return '[' . ($wrap ? $outWrapped : $out) . ']';
|
||||
|
||||
} elseif ($var instanceof \Serializable) {
|
||||
$var = serialize($var);
|
||||
return 'unserialize(' . self::_dump($var, $level) . ')';
|
||||
|
||||
} elseif ($var instanceof \Closure) {
|
||||
throw new Nette\InvalidArgumentException('Cannot dump closure.');
|
||||
|
||||
} elseif (is_object($var)) {
|
||||
$class = get_class($var);
|
||||
if ((new \ReflectionObject($var))->isAnonymous()) {
|
||||
throw new Nette\InvalidArgumentException('Cannot dump anonymous class.');
|
||||
|
||||
} elseif (in_array($class, ['DateTime', 'DateTimeImmutable'], true)) {
|
||||
return self::formatArgs("new $class(?, new DateTimeZone(?))", [$var->format('Y-m-d H:i:s.u'), $var->getTimeZone()->getName()]);
|
||||
}
|
||||
|
||||
$arr = (array) $var;
|
||||
$space = str_repeat("\t", $level);
|
||||
|
||||
static $list = [];
|
||||
if ($level > self::MAX_DEPTH || in_array($var, $list, true)) {
|
||||
throw new Nette\InvalidArgumentException('Nesting level too deep or recursive dependency.');
|
||||
|
||||
} else {
|
||||
$out = "\n";
|
||||
$list[] = $var;
|
||||
if (method_exists($var, '__sleep')) {
|
||||
foreach ($var->__sleep() as $v) {
|
||||
$props[$v] = $props["\x00*\x00$v"] = $props["\x00$class\x00$v"] = true;
|
||||
}
|
||||
}
|
||||
foreach ($arr as $k => &$v) {
|
||||
if (!isset($props) || isset($props[$k])) {
|
||||
$out .= "$space\t" . self::_dump($k, $level + 1) . ' => ' . self::_dump($v, $level + 1) . ",\n";
|
||||
}
|
||||
}
|
||||
array_pop($list);
|
||||
$out .= $space;
|
||||
}
|
||||
return $class === 'stdClass'
|
||||
? "(object) [$out]"
|
||||
: __CLASS__ . "::createObject('$class', [$out])";
|
||||
|
||||
} elseif (is_resource($var)) {
|
||||
throw new Nette\InvalidArgumentException('Cannot dump resource.');
|
||||
|
||||
} else {
|
||||
return var_export($var, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates PHP statement.
|
||||
*/
|
||||
public static function format(string $statement, ...$args): string
|
||||
{
|
||||
return self::formatArgs($statement, $args);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates PHP statement.
|
||||
*/
|
||||
public static function formatArgs(string $statement, array $args): string
|
||||
{
|
||||
$tokens = preg_split('#(\.\.\.\?|\$\?|->\?|::\?|\\\\\?|\?\*|\?)#', $statement, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$res = '';
|
||||
foreach ($tokens as $n => $token) {
|
||||
if ($n % 2 === 0) {
|
||||
$res .= $token;
|
||||
} elseif ($token === '\\?') {
|
||||
$res .= '?';
|
||||
} elseif (!$args) {
|
||||
throw new Nette\InvalidArgumentException('Insufficient number of arguments.');
|
||||
} elseif ($token === '?') {
|
||||
$res .= self::dump(array_shift($args));
|
||||
} elseif ($token === '...?' || $token === '?*') {
|
||||
$arg = array_shift($args);
|
||||
if (!is_array($arg)) {
|
||||
throw new Nette\InvalidArgumentException('Argument must be an array.');
|
||||
}
|
||||
$items = [];
|
||||
foreach ($arg as $tmp) {
|
||||
$items[] = self::dump($tmp);
|
||||
}
|
||||
$res .= strlen($tmp = implode(', ', $items)) > self::WRAP_LENGTH && count($items) > 1
|
||||
? "\n" . Nette\Utils\Strings::indent(implode(",\n", $items)) . "\n"
|
||||
: $tmp;
|
||||
|
||||
} else { // $ -> ::
|
||||
$res .= substr($token, 0, -1) . self::formatMember(array_shift($args));
|
||||
}
|
||||
}
|
||||
if ($args) {
|
||||
throw new Nette\InvalidArgumentException('Insufficient number of placeholders.');
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a PHP representation of a object member.
|
||||
*/
|
||||
public static function formatMember($name): string
|
||||
{
|
||||
return $name instanceof PhpLiteral || !self::isIdentifier($name)
|
||||
? '{' . self::_dump($name) . '}'
|
||||
: $name;
|
||||
}
|
||||
|
||||
|
||||
public static function formatDocComment(string $content): string
|
||||
{
|
||||
if (($s = trim($content)) === '') {
|
||||
return '';
|
||||
} elseif (strpos($content, "\n") === false) {
|
||||
return "/** $s */\n";
|
||||
} else {
|
||||
return str_replace("\n", "\n * ", "/**\n$s") . "\n */\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function unformatDocComment(string $comment): string
|
||||
{
|
||||
return preg_replace('#^\s*\* ?#m', '', trim(trim(trim($comment), '/*')));
|
||||
}
|
||||
|
||||
|
||||
public static function isIdentifier($value): bool
|
||||
{
|
||||
return is_string($value) && preg_match('#^' . self::PHP_IDENT . '\z#', $value);
|
||||
}
|
||||
|
||||
|
||||
public static function isNamespaceIdentifier($value, bool $allowLeadingSlash = false): bool
|
||||
{
|
||||
$re = '#^' . ($allowLeadingSlash ? '\\\\?' : '') . self::PHP_IDENT . '(\\\\' . self::PHP_IDENT . ')*\z#';
|
||||
return is_string($value) && preg_match($re, $value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return object
|
||||
* @internal
|
||||
*/
|
||||
public static function createObject(string $class, array $props)
|
||||
{
|
||||
return unserialize('O' . substr(serialize($class), 1, -1) . substr(serialize($props), 1));
|
||||
}
|
||||
|
||||
|
||||
public static function extractNamespace(string $name): string
|
||||
{
|
||||
return ($pos = strrpos($name, '\\')) ? substr($name, 0, $pos) : '';
|
||||
}
|
||||
|
||||
|
||||
public static function extractShortName(string $name): string
|
||||
{
|
||||
return ($pos = strrpos($name, '\\')) === false ? $name : substr($name, $pos + 1);
|
||||
}
|
||||
|
||||
|
||||
public static function tabsToSpaces(string $s, int $count = self::INDENT_LENGTH): string
|
||||
{
|
||||
return str_replace("\t", str_repeat(' ', $count), $s);
|
||||
}
|
||||
}
|
134
vendor/nette/php-generator/src/PhpGenerator/Method.php
vendored
Normal file
134
vendor/nette/php-generator/src/PhpGenerator/Method.php
vendored
Normal file
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Class method.
|
||||
*
|
||||
* @property string|null $body
|
||||
*/
|
||||
final class Method
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
use Traits\FunctionLike;
|
||||
use Traits\NameAware;
|
||||
use Traits\VisibilityAware;
|
||||
use Traits\CommentAware;
|
||||
|
||||
/** @var string|null */
|
||||
private $body = '';
|
||||
|
||||
/** @var bool */
|
||||
private $static = false;
|
||||
|
||||
/** @var bool */
|
||||
private $final = false;
|
||||
|
||||
/** @var bool */
|
||||
private $abstract = false;
|
||||
|
||||
|
||||
/**
|
||||
* @param string|array $method
|
||||
* @return static
|
||||
*/
|
||||
public static function from($method): self
|
||||
{
|
||||
return (new Factory)->fromMethodReflection(Nette\Utils\Callback::toReflection($method));
|
||||
}
|
||||
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
try {
|
||||
return (new Printer)->printMethod($this);
|
||||
} catch (\Throwable $e) {
|
||||
trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setBody(?string $code, array $args = null): self
|
||||
{
|
||||
$this->body = $args === null || $code === null ? $code : Helpers::formatArgs($code, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getBody(): ?string
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setStatic(bool $state = true): self
|
||||
{
|
||||
$this->static = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isStatic(): bool
|
||||
{
|
||||
return $this->static;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setFinal(bool $state = true): self
|
||||
{
|
||||
$this->final = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isFinal(): bool
|
||||
{
|
||||
return $this->final;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setAbstract(bool $state = true): self
|
||||
{
|
||||
$this->abstract = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isAbstract(): bool
|
||||
{
|
||||
return $this->abstract;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Nette\InvalidStateException
|
||||
*/
|
||||
public function validate(): void
|
||||
{
|
||||
if ($this->abstract && ($this->final || $this->visibility === ClassType::VISIBILITY_PRIVATE)) {
|
||||
throw new Nette\InvalidStateException('Method cannot be abstract and final or private.');
|
||||
}
|
||||
}
|
||||
}
|
122
vendor/nette/php-generator/src/PhpGenerator/Parameter.php
vendored
Normal file
122
vendor/nette/php-generator/src/PhpGenerator/Parameter.php
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Method parameter description.
|
||||
*
|
||||
* @property mixed $defaultValue
|
||||
*/
|
||||
final class Parameter
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
use Traits\NameAware;
|
||||
|
||||
/** @var bool */
|
||||
private $reference = false;
|
||||
|
||||
/** @var string|null */
|
||||
private $typeHint;
|
||||
|
||||
/** @var bool */
|
||||
private $nullable = false;
|
||||
|
||||
/** @var bool */
|
||||
private $hasDefaultValue = false;
|
||||
|
||||
/** @var mixed */
|
||||
private $defaultValue;
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setReference(bool $state = true): self
|
||||
{
|
||||
$this->reference = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isReference(): bool
|
||||
{
|
||||
return $this->reference;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setTypeHint(?string $hint): self
|
||||
{
|
||||
$this->typeHint = $hint;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getTypeHint(): ?string
|
||||
{
|
||||
return $this->typeHint;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated just use setDefaultValue()
|
||||
* @return static
|
||||
*/
|
||||
public function setOptional(bool $state = true): self
|
||||
{
|
||||
trigger_error(__METHOD__ . '() is deprecated, use setDefaultValue()', E_USER_DEPRECATED);
|
||||
$this->hasDefaultValue = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setNullable(bool $state = true): self
|
||||
{
|
||||
$this->nullable = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isNullable(): bool
|
||||
{
|
||||
return $this->nullable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setDefaultValue($val): self
|
||||
{
|
||||
$this->defaultValue = $val;
|
||||
$this->hasDefaultValue = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getDefaultValue()
|
||||
{
|
||||
return $this->defaultValue;
|
||||
}
|
||||
|
||||
|
||||
public function hasDefaultValue(): bool
|
||||
{
|
||||
return $this->hasDefaultValue;
|
||||
}
|
||||
}
|
115
vendor/nette/php-generator/src/PhpGenerator/PhpFile.php
vendored
Normal file
115
vendor/nette/php-generator/src/PhpGenerator/PhpFile.php
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Instance of PHP file.
|
||||
*
|
||||
* Generates:
|
||||
* - opening tag (<?php)
|
||||
* - doc comments
|
||||
* - one or more namespaces
|
||||
*/
|
||||
final class PhpFile
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
use Traits\CommentAware;
|
||||
|
||||
/** @var PhpNamespace[] */
|
||||
private $namespaces = [];
|
||||
|
||||
/** @var bool */
|
||||
private $strictTypes = false;
|
||||
|
||||
|
||||
public function addClass(string $name): ClassType
|
||||
{
|
||||
return $this
|
||||
->addNamespace(Helpers::extractNamespace($name))
|
||||
->addClass(Helpers::extractShortName($name));
|
||||
}
|
||||
|
||||
|
||||
public function addInterface(string $name): ClassType
|
||||
{
|
||||
return $this
|
||||
->addNamespace(Helpers::extractNamespace($name))
|
||||
->addInterface(Helpers::extractShortName($name));
|
||||
}
|
||||
|
||||
|
||||
public function addTrait(string $name): ClassType
|
||||
{
|
||||
return $this
|
||||
->addNamespace(Helpers::extractNamespace($name))
|
||||
->addTrait(Helpers::extractShortName($name));
|
||||
}
|
||||
|
||||
|
||||
public function addNamespace(string $name): PhpNamespace
|
||||
{
|
||||
if (!isset($this->namespaces[$name])) {
|
||||
$this->namespaces[$name] = new PhpNamespace($name);
|
||||
foreach ($this->namespaces as $namespace) {
|
||||
$namespace->setBracketedSyntax(count($this->namespaces) > 1 && isset($this->namespaces['']));
|
||||
}
|
||||
}
|
||||
return $this->namespaces[$name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return PhpNamespace[]
|
||||
*/
|
||||
public function getNamespaces(): array
|
||||
{
|
||||
return $this->namespaces;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function addUse(string $name, string $alias = null): self
|
||||
{
|
||||
$this->addNamespace('')->addUse($name, $alias);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds declare(strict_types=1) to output.
|
||||
* @return static
|
||||
*/
|
||||
public function setStrictTypes(bool $on = true): self
|
||||
{
|
||||
$this->strictTypes = $on;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getStrictTypes(): bool
|
||||
{
|
||||
return $this->strictTypes;
|
||||
}
|
||||
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
try {
|
||||
return (new Printer)->printFile($this);
|
||||
} catch (\Throwable $e) {
|
||||
trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
32
vendor/nette/php-generator/src/PhpGenerator/PhpLiteral.php
vendored
Normal file
32
vendor/nette/php-generator/src/PhpGenerator/PhpLiteral.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
|
||||
/**
|
||||
* PHP literal value.
|
||||
*/
|
||||
final class PhpLiteral
|
||||
{
|
||||
/** @var string */
|
||||
private $value;
|
||||
|
||||
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
199
vendor/nette/php-generator/src/PhpGenerator/PhpNamespace.php
vendored
Normal file
199
vendor/nette/php-generator/src/PhpGenerator/PhpNamespace.php
vendored
Normal file
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
use Nette\InvalidStateException;
|
||||
use Nette\Utils\Strings;
|
||||
|
||||
|
||||
/**
|
||||
* Namespaced part of a PHP file.
|
||||
*
|
||||
* Generates:
|
||||
* - namespace statement
|
||||
* - variable amount of use statements
|
||||
* - one or more class declarations
|
||||
*/
|
||||
final class PhpNamespace
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
private const KEYWORDS = [
|
||||
'string' => 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1,
|
||||
'callable' => 1, 'iterable' => 1, 'void' => 1, 'self' => 1, 'parent' => 1,
|
||||
];
|
||||
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var bool */
|
||||
private $bracketedSyntax = false;
|
||||
|
||||
/** @var string[] */
|
||||
private $uses = [];
|
||||
|
||||
/** @var ClassType[] */
|
||||
private $classes = [];
|
||||
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
if ($name !== '' && !Helpers::isNamespaceIdentifier($name)) {
|
||||
throw new Nette\InvalidArgumentException("Value '$name' is not valid name.");
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
* @internal
|
||||
*/
|
||||
public function setBracketedSyntax(bool $state = true): self
|
||||
{
|
||||
$this->bracketedSyntax = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getBracketedSyntax(): bool
|
||||
{
|
||||
return $this->bracketedSyntax;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws InvalidStateException
|
||||
* @return static
|
||||
*/
|
||||
public function addUse(string $name, string $alias = null, string &$aliasOut = null): self
|
||||
{
|
||||
$name = ltrim($name, '\\');
|
||||
if ($alias === null && $this->name === Helpers::extractNamespace($name)) {
|
||||
$alias = Helpers::extractShortName($name);
|
||||
}
|
||||
if ($alias === null) {
|
||||
$path = explode('\\', $name);
|
||||
$counter = null;
|
||||
do {
|
||||
if (empty($path)) {
|
||||
$counter++;
|
||||
} else {
|
||||
$alias = array_pop($path) . $alias;
|
||||
}
|
||||
} while (isset($this->uses[$alias . $counter]) && $this->uses[$alias . $counter] !== $name);
|
||||
$alias .= $counter;
|
||||
|
||||
} elseif (isset($this->uses[$alias]) && $this->uses[$alias] !== $name) {
|
||||
throw new InvalidStateException(
|
||||
"Alias '$alias' used already for '{$this->uses[$alias]}', cannot use for '{$name}'."
|
||||
);
|
||||
}
|
||||
|
||||
$aliasOut = $alias;
|
||||
$this->uses[$alias] = $name;
|
||||
asort($this->uses);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getUses(): array
|
||||
{
|
||||
return $this->uses;
|
||||
}
|
||||
|
||||
|
||||
public function unresolveName(string $name): string
|
||||
{
|
||||
if (isset(self::KEYWORDS[strtolower($name)]) || $name === '') {
|
||||
return $name;
|
||||
}
|
||||
$name = ltrim($name, '\\');
|
||||
$res = null;
|
||||
$lower = strtolower($name);
|
||||
foreach ($this->uses as $alias => $original) {
|
||||
if (Strings::startsWith($lower . '\\', strtolower($original) . '\\')) {
|
||||
$short = $alias . substr($name, strlen($original));
|
||||
if (!isset($res) || strlen($res) > strlen($short)) {
|
||||
$res = $short;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$res && Strings::startsWith($lower, strtolower($this->name) . '\\')) {
|
||||
return substr($name, strlen($this->name) + 1);
|
||||
} else {
|
||||
return $res ?: ($this->name ? '\\' : '') . $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function add(ClassType $class): self
|
||||
{
|
||||
$name = $class->getName();
|
||||
if ($name === null) {
|
||||
throw new Nette\InvalidArgumentException('Class does not have a name.');
|
||||
}
|
||||
$this->addUse($this->name . '\\' . $name);
|
||||
$this->classes[$name] = $class;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function addClass(string $name): ClassType
|
||||
{
|
||||
$this->add($class = new ClassType($name, $this));
|
||||
return $class;
|
||||
}
|
||||
|
||||
|
||||
public function addInterface(string $name): ClassType
|
||||
{
|
||||
return $this->addClass($name)->setType(ClassType::TYPE_INTERFACE);
|
||||
}
|
||||
|
||||
|
||||
public function addTrait(string $name): ClassType
|
||||
{
|
||||
return $this->addClass($name)->setType(ClassType::TYPE_TRAIT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return ClassType[]
|
||||
*/
|
||||
public function getClasses(): array
|
||||
{
|
||||
return $this->classes;
|
||||
}
|
||||
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
try {
|
||||
return (new Printer)->printNamespace($this);
|
||||
} catch (\Throwable $e) {
|
||||
trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
226
vendor/nette/php-generator/src/PhpGenerator/Printer.php
vendored
Normal file
226
vendor/nette/php-generator/src/PhpGenerator/Printer.php
vendored
Normal file
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
use Nette\Utils\Strings;
|
||||
|
||||
|
||||
/**
|
||||
* Generates PHP code.
|
||||
*/
|
||||
class Printer
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @var string */
|
||||
protected $indentation = "\t";
|
||||
|
||||
/** @var int */
|
||||
protected $linesBetweenMethods = 2;
|
||||
|
||||
|
||||
public function printFunction(GlobalFunction $function, PhpNamespace $namespace = null): string
|
||||
{
|
||||
return Helpers::formatDocComment($function->getComment() . "\n")
|
||||
. 'function '
|
||||
. ($function->getReturnReference() ? '&' : '')
|
||||
. $function->getName()
|
||||
. $this->printParameters($function, $namespace)
|
||||
. $this->printReturnType($function, $namespace)
|
||||
. "\n{\n" . $this->indent(ltrim(rtrim($function->getBody()) . "\n")) . "}\n";
|
||||
}
|
||||
|
||||
|
||||
public function printClosure(Closure $closure): string
|
||||
{
|
||||
$uses = [];
|
||||
foreach ($closure->getUses() as $param) {
|
||||
$uses[] = ($param->isReference() ? '&' : '') . '$' . $param->getName();
|
||||
}
|
||||
$useStr = strlen($tmp = implode(', ', $uses)) > Helpers::WRAP_LENGTH && count($uses) > 1
|
||||
? "\n" . $this->indentation . implode(",\n" . $this->indentation, $uses) . "\n"
|
||||
: $tmp;
|
||||
|
||||
return 'function '
|
||||
. ($closure->getReturnReference() ? '&' : '')
|
||||
. $this->printParameters($closure, null)
|
||||
. ($uses ? " use ($useStr)" : '')
|
||||
. $this->printReturnType($closure, null)
|
||||
. " {\n" . $this->indent(ltrim(rtrim($closure->getBody()) . "\n")) . '}';
|
||||
}
|
||||
|
||||
|
||||
public function printMethod(Method $method, PhpNamespace $namespace = null): string
|
||||
{
|
||||
$method->validate();
|
||||
return Helpers::formatDocComment($method->getComment() . "\n")
|
||||
. ($method->isAbstract() ? 'abstract ' : '')
|
||||
. ($method->isFinal() ? 'final ' : '')
|
||||
. ($method->getVisibility() ? $method->getVisibility() . ' ' : '')
|
||||
. ($method->isStatic() ? 'static ' : '')
|
||||
. 'function '
|
||||
. ($method->getReturnReference() ? '&' : '')
|
||||
. $method->getName()
|
||||
. ($params = $this->printParameters($method, $namespace))
|
||||
. $this->printReturnType($method, $namespace)
|
||||
. ($method->isAbstract() || $method->getBody() === null
|
||||
? ";\n"
|
||||
: (strpos($params, "\n") === false ? "\n" : ' ')
|
||||
. "{\n"
|
||||
. $this->indent(ltrim(rtrim($method->getBody()) . "\n"))
|
||||
. "}\n");
|
||||
}
|
||||
|
||||
|
||||
public function printClass(ClassType $class, PhpNamespace $namespace = null): string
|
||||
{
|
||||
$class->validate();
|
||||
$resolver = $namespace ? [$namespace, 'unresolveName'] : function ($s) { return $s; };
|
||||
|
||||
$traits = [];
|
||||
foreach ($class->getTraitResolutions() as $trait => $resolutions) {
|
||||
$traits[] = 'use ' . $resolver($trait)
|
||||
. ($resolutions ? " {\n" . $this->indentation . implode(";\n" . $this->indentation, $resolutions) . ";\n}\n" : ";\n");
|
||||
}
|
||||
|
||||
$consts = [];
|
||||
foreach ($class->getConstants() as $const) {
|
||||
$consts[] = Helpers::formatDocComment((string) $const->getComment())
|
||||
. ($const->getVisibility() ? $const->getVisibility() . ' ' : '')
|
||||
. 'const ' . $const->getName() . ' = ' . Helpers::dump($const->getValue()) . ";\n";
|
||||
}
|
||||
|
||||
$properties = [];
|
||||
foreach ($class->getProperties() as $property) {
|
||||
$properties[] = Helpers::formatDocComment((string) $property->getComment())
|
||||
. ($property->getVisibility() ?: 'public') . ($property->isStatic() ? ' static' : '') . ' $' . $property->getName()
|
||||
. ($property->getValue() === null ? '' : ' = ' . Helpers::dump($property->getValue()))
|
||||
. ";\n";
|
||||
}
|
||||
|
||||
$methods = [];
|
||||
foreach ($class->getMethods() as $method) {
|
||||
$methods[] = $this->printMethod($method, $namespace);
|
||||
}
|
||||
|
||||
$members = array_filter([
|
||||
implode('', $traits),
|
||||
implode('', $consts),
|
||||
implode("\n", $properties),
|
||||
($methods && $properties ? str_repeat("\n", $this->linesBetweenMethods - 1) : '')
|
||||
. implode(str_repeat("\n", $this->linesBetweenMethods), $methods),
|
||||
]);
|
||||
|
||||
return Strings::normalize(
|
||||
Helpers::formatDocComment($class->getComment() . "\n")
|
||||
. ($class->isAbstract() ? 'abstract ' : '')
|
||||
. ($class->isFinal() ? 'final ' : '')
|
||||
. ($class->getName() ? $class->getType() . ' ' . $class->getName() . ' ' : '')
|
||||
. ($class->getExtends() ? 'extends ' . implode(', ', array_map($resolver, (array) $class->getExtends())) . ' ' : '')
|
||||
. ($class->getImplements() ? 'implements ' . implode(', ', array_map($resolver, $class->getImplements())) . ' ' : '')
|
||||
. ($class->getName() ? "\n" : '') . "{\n"
|
||||
. ($members ? $this->indent(implode("\n", $members)) : '')
|
||||
. '}'
|
||||
) . ($class->getName() ? "\n" : '');
|
||||
}
|
||||
|
||||
|
||||
public function printNamespace(PhpNamespace $namespace): string
|
||||
{
|
||||
$name = $namespace->getName();
|
||||
|
||||
$uses = [];
|
||||
foreach ($namespace->getUses() as $alias => $original) {
|
||||
if ($original !== ($name ? $name . '\\' . $alias : $alias)) {
|
||||
if ($alias === $original || substr($original, -(strlen($alias) + 1)) === '\\' . $alias) {
|
||||
$uses[] = "use $original;";
|
||||
} else {
|
||||
$uses[] = "use $original as $alias;";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$classes = [];
|
||||
foreach ($namespace->getClasses() as $class) {
|
||||
$classes[] = $this->printClass($class, $namespace);
|
||||
}
|
||||
|
||||
$body = ($uses ? implode("\n", $uses) . "\n\n" : '')
|
||||
. implode("\n", $classes);
|
||||
|
||||
if ($namespace->getBracketedSyntax()) {
|
||||
return 'namespace' . ($name ? " $name" : '') . "\n{\n"
|
||||
. $this->indent($body)
|
||||
. "}\n";
|
||||
|
||||
} else {
|
||||
return ($name ? "namespace $name;\n\n" : '')
|
||||
. $body;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function printFile(PhpFile $file): string
|
||||
{
|
||||
$namespaces = [];
|
||||
foreach ($file->getNamespaces() as $namespace) {
|
||||
$namespaces[] = $this->printNamespace($namespace);
|
||||
}
|
||||
|
||||
return Strings::normalize(
|
||||
"<?php\n"
|
||||
. ($file->getComment() ? "\n" . Helpers::formatDocComment($file->getComment() . "\n") : '')
|
||||
. "\n"
|
||||
. ($file->getStrictTypes() ? "declare(strict_types=1);\n\n" : '')
|
||||
. implode("\n\n", $namespaces)
|
||||
) . "\n";
|
||||
}
|
||||
|
||||
|
||||
protected function indent(string $s): string
|
||||
{
|
||||
return Strings::indent($s, 1, $this->indentation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Nette\PhpGenerator\Traits\FunctionLike $function
|
||||
*/
|
||||
protected function printParameters($function, ?PhpNamespace $namespace): string
|
||||
{
|
||||
$params = [];
|
||||
$list = $function->getParameters();
|
||||
foreach ($list as $param) {
|
||||
$variadic = $function->isVariadic() && $param === end($list);
|
||||
$hint = $param->getTypeHint();
|
||||
$params[] = ($hint ? ($param->isNullable() ? '?' : '') . ($namespace ? $namespace->unresolveName($hint) : $hint) . ' ' : '')
|
||||
. ($param->isReference() ? '&' : '')
|
||||
. ($variadic ? '...' : '')
|
||||
. '$' . $param->getName()
|
||||
. ($param->hasDefaultValue() && !$variadic ? ' = ' . Helpers::dump($param->getDefaultValue()) : '');
|
||||
}
|
||||
|
||||
return strlen($tmp = implode(', ', $params)) > Helpers::WRAP_LENGTH && count($params) > 1
|
||||
? "(\n" . $this->indentation . implode(",\n" . $this->indentation, $params) . "\n)"
|
||||
: "($tmp)";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Nette\PhpGenerator\Traits\FunctionLike $function
|
||||
*/
|
||||
protected function printReturnType($function, ?PhpNamespace $namespace): string
|
||||
{
|
||||
return $function->getReturnType()
|
||||
? ': ' . ($function->getReturnNullable() ? '?' : '') . ($namespace ? $namespace->unresolveName($function->getReturnType()) : $function->getReturnType())
|
||||
: '';
|
||||
}
|
||||
}
|
64
vendor/nette/php-generator/src/PhpGenerator/Property.php
vendored
Normal file
64
vendor/nette/php-generator/src/PhpGenerator/Property.php
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\PhpGenerator;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Class property description.
|
||||
*
|
||||
* @property mixed $value
|
||||
*/
|
||||
final class Property
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
use Traits\NameAware;
|
||||
use Traits\VisibilityAware;
|
||||
use Traits\CommentAware;
|
||||
|
||||
/** @var mixed */
|
||||
private $value;
|
||||
|
||||
/** @var bool */
|
||||
private $static = false;
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setValue($val): self
|
||||
{
|
||||
$this->value = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function &getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function setStatic(bool $state = true): self
|
||||
{
|
||||
$this->static = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isStatic(): bool
|
||||
{
|
||||
return $this->static;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue