[GetAndSetToMethodCallRector] decouple dependency on specific class

This commit is contained in:
Tomas Votruba 2018-05-31 18:05:03 +02:00
parent 18d9097ca0
commit 962495cda3
8 changed files with 31 additions and 474 deletions

View File

@ -1,265 +0,0 @@
<?php
# source: https://raw.githubusercontent.com/nette/bootstrap/v2.2/src/Bootstrap/Configurator.php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
namespace Nette\Config;
use Nette;
use Nette\DI;
use Nette\Object;
use Tracy;
/**
* Initial system DI container generator.
*
* @author David Grudl
*/
class Configurator extends Object
{
const AUTO = TRUE;
/** @deprecated */
const DEVELOPMENT = 'development',
PRODUCTION = 'production',
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 = array(
'php' => 'Nette\DI\Extensions\PhpExtension',
'constants' => 'Nette\DI\Extensions\ConstantsExtension',
'nette' => 'Nette\Bridges\Framework\NetteExtension',
'database' => 'Nette\Bridges\DatabaseDI\DatabaseExtension',
'extensions' => 'Nette\DI\Extensions\ExtensionsExtension',
);
/** @var array */
protected $parameters;
/** @var array */
protected $files = array();
public function __construct()
{
$this->parameters = $this->getDefaultParameters();
}
/**
* Set parameter %debugMode%.
* @param bool|string|array
* @return self
*/
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.
* @return self
*/
public function setTempDirectory($path)
{
$this->parameters['tempDir'] = $path;
return $this;
}
/**
* Adds new parameters. The %params% will be expanded.
* @return self
*/
public function addParameters(array $params)
{
$this->parameters = DI\Config\Helpers::merge($params, $this->parameters);
return $this;
}
/**
* @return array
*/
protected function getDefaultParameters()
{
$trace = debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE);
$debugMode = static::detectDebugMode();
return array(
'appDir' => isset($trace[1]['file']) ? dirname($trace[1]['file']) : NULL,
'wwwDir' => isset($_SERVER['SCRIPT_FILENAME'])
? dirname(realpath($_SERVER['SCRIPT_FILENAME']))
: NULL,
'debugMode' => $debugMode,
'productionMode' => !$debugMode,
'environment' => $debugMode ? 'development' : 'production',
'consoleMode' => PHP_SAPI === 'cli',
'container' => array(
'class' => 'SystemContainer',
'parent' => 'Nette\DI\Container',
),
);
}
/**
* @param string error log directory
* @param string administrator 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')) {
throw new Nette\NotSupportedException('RobotLoader not found, do you have `nette/robot-loader` package installed?');
}
$loader = new Nette\Loaders\RobotLoader;
$loader->setCacheStorage(new Nette\Caching\Storages\FileStorage($this->getCacheDirectory()));
$loader->autoRebuild = $this->parameters['debugMode'];
return $loader;
}
/**
* Adds configuration file.
* @return self
*/
public function addConfig($file, $section = NULL)
{
if ($section === NULL && is_string($file) && $this->parameters['debugMode']) { // back compatibility
try {
$loader = new DI\Config\Loader;
$loader->load($file, $this->parameters['environment']);
trigger_error("Config file '$file' has sections, call addConfig() with second parameter Configurator::AUTO.", E_USER_WARNING);
$section = $this->parameters['environment'];
} catch (\Exception $e) {
}
}
$this->files[] = array($file, $section === self::AUTO ? $this->parameters['environment'] : $section);
return $this;
}
/**
* Returns system DI container.
* @return \Nette\DI\Container
*/
public function createContainer()
{
$container = $this->createContainerFactory()->create();
$container->initialize();
if (class_exists('Nette\Environment')) {
Nette\Environment::setContext($container); // back compatibility
}
return $container;
}
/**
* @return DI\ContainerFactory
*/
protected function createContainerFactory()
{
$factory = new DI\ContainerFactory(NULL);
$factory->autoRebuild = $this->parameters['debugMode'] ? TRUE : 'compat';
$factory->class = $this->parameters['container']['class'];
$factory->config = array('parameters' => $this->parameters);
$factory->configFiles = $this->files;
$factory->tempDirectory = $this->getCacheDirectory() . '/Nette.Configurator';
if (!is_dir($factory->tempDirectory)) {
@mkdir($factory->tempDirectory); // @ - directory may already exist
}
$me = $this;
$factory->onCompile[] = function (DI\ContainerFactory $factory, DI\Compiler $compiler, $config) use ($me) {
foreach ($me->defaultExtensions as $name => $class) {
if (class_exists($class)) {
$compiler->addExtension($name, new $class);
}
}
$factory->parentClass = $config['parameters']['container']['parent'];
$me->onCompile($me, $compiler);
};
return $factory;
}
protected function getCacheDirectory()
{
if (empty($this->parameters['tempDir'])) {
throw new Nette\InvalidStateException('Set path to temporary directory using setTempDirectory().');
}
$dir = $this->parameters['tempDir'] . '/cache';
if (!is_dir($dir)) {
@mkdir($dir); // @ - directory may already exist
}
return $dir;
}
/********************* tools ****************d*g**/
/**
* Detects debug mode by IP address.
* @param string|array IP addresses or computer names whitelist detection
* @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'])) {
$list[] = '127.0.0.1';
$list[] = '::1';
}
return in_array($addr, $list, TRUE) || in_array("$secret@$addr", $list, TRUE);
}
}

View File

@ -1,204 +0,0 @@
<?php
# source: https://github.com/nette/di/blob/b36d041847f3a3f54251029ba60485aebf4889dd/src/DI/Container.php
namespace Nette\DI;
class Container
{
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;
}
public function getParameters(): array
{
return $this->parameters;
}
/**
* Adds the service to the container.
* @param object $service
* @return static
*/
public function addService(string $name, $service)
{
if (!$name) {
throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($name)));
}
$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.
*/
public function removeService(string $name): void
{
$name = $this->meta[self::ALIASES][$name] ?? $name;
unset($this->registry[$name]);
}
/**
* Gets the service object by name.
* @return object
* @throws MissingServiceException
*/
public function getService(string $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.
* @throws MissingServiceException
*/
public function getServiceType(string $name): string
{
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?
*/
public function hasService(string $name): bool
{
$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?
*/
public function isCreated(string $name): bool
{
if (!$this->hasService($name)) {
throw new MissingServiceException("Service '$name' not found.");
}
$name = $this->meta[self::ALIASES][$name] ?? $name;
return isset($this->registry[$name]);
}
/**
* Creates new instance of the service.
* @return object
* @throws MissingServiceException
*/
public function createService(string $name, array $args = [])
{
$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 bool $throw exception if service doesn't exist?
* @return object service or null
* @throws MissingServiceException
*/
public function getByType(string $type, bool $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]);
}
throw new MissingServiceException("Multiple services of type $type found: " . implode(', ', $names) . '.');
} elseif ($throw) {
throw new MissingServiceException("Service of type $type not found.");
}
}
/**
* Gets the service names of the specified type.
* @return string[]
*/
public function findByType(string $type): array
{
$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.
* @return array of [service name => tag attributes]
*/
public function findByTag(string $tag): array
{
return $this->meta[self::TAGS][$tag] ?? [];
}
/********************* autowiring ****************d*g**/
/**
* Creates new instance using autowiring.
* @return object
* @throws Nette\InvalidArgumentException
*/
public function createInstance(string $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 $service
*/
public function callInjects($service): void
{
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));
}
public static function getMethodName(string $name): string
{
$uname = ucfirst($name);
return 'createService' . ($name === $uname ? '__' : '') . str_replace('.', '__', $uname);
}
}

View File

@ -1,6 +1,8 @@
<?php declare(strict_types=1);
$container = new Nette\DI\Container;
use Rector\Tests\Rector\MagicDisclosure\GetAndSetToMethodCallRector\Source\SomeContainer;
$container = new SomeContainer();
$someService = $container->getService('someService');
$parameters = $container->parameters;

View File

@ -1,6 +1,8 @@
<?php declare(strict_types=1);
$container = new Nette\DI\Container;
use Rector\Tests\Rector\MagicDisclosure\GetAndSetToMethodCallRector\Source\SomeContainer;
$container = new SomeContainer();
$container->addService('someService', new SomeService);
$parameters = $container->parameters;

View File

@ -0,0 +1,18 @@
<?php declare(strict_types=1);
namespace Rector\Tests\Rector\MagicDisclosure\GetAndSetToMethodCallRector\Source;
final class SomeContainer
{
public $parameters;
public function addService($name, $service)
{
}
public function getService($name)
{
}
}

View File

@ -1,6 +1,8 @@
<?php declare(strict_types=1);
$container = new Nette\DI\Container;
use Rector\Tests\Rector\MagicDisclosure\GetAndSetToMethodCallRector\Source\SomeContainer;
$container = new SomeContainer();
$someService = $container->someService;
$parameters = $container->parameters;

View File

@ -1,6 +1,8 @@
<?php declare(strict_types=1);
$container = new Nette\DI\Container;
use Rector\Tests\Rector\MagicDisclosure\GetAndSetToMethodCallRector\Source\SomeContainer;
$container = new SomeContainer();
$container->someService = new SomeService;
$parameters = $container->parameters;

View File

@ -1,6 +1,6 @@
services:
Rector\Rector\MagicDisclosure\GetAndSetToMethodCallRector:
$typeToMethodCalls:
'Nette\DI\Container':
'Rector\Tests\Rector\MagicDisclosure\GetAndSetToMethodCallRector\Source\SomeContainer':
'get': 'getService'
'set': 'addService'