use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
-use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
+use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
*/
private $definitions = array();
- /**
- * @var Definition[]
- */
- private $obsoleteDefinitions = array();
-
/**
* @var Alias[]
*/
*/
private $usedTags = array();
+ /**
+ * @var string[][] a map of env var names to their placeholders
+ */
+ private $envPlaceholders = array();
+
+ /**
+ * @var int[] a map of env vars to their resolution counter
+ */
+ private $envCounters = array();
+
/**
* Sets the track resources flag.
*
/**
* Adds a compiler pass.
*
- * @param CompilerPassInterface $pass A compiler pass
- * @param string $type The type of compiler pass
+ * @param CompilerPassInterface $pass A compiler pass
+ * @param string $type The type of compiler pass
+ * @param int $priority Used to sort the passes
*
* @return $this
*/
- public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
+ public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, $priority = 0*/)
{
- $this->getCompiler()->addPass($pass, $type);
+ if (func_num_args() >= 3) {
+ $priority = func_get_arg(2);
+ } else {
+ if (__CLASS__ !== get_class($this)) {
+ $r = new \ReflectionMethod($this, __FUNCTION__);
+ if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
+ @trigger_error(sprintf('Method %s() will have a third `$priority = 0` argument in version 4.0. Not defining it is deprecated since 3.2.', __METHOD__), E_USER_DEPRECATED);
+ }
+ }
+
+ $priority = 0;
+ }
+
+ $this->getCompiler()->addPass($pass, $type, $priority);
$this->addObjectResource($pass);
return $this->compiler;
}
- /**
- * Returns all Scopes.
- *
- * @return array An array of scopes
- *
- * @deprecated since version 2.8, to be removed in 3.0.
- */
- public function getScopes($triggerDeprecationError = true)
- {
- if ($triggerDeprecationError) {
- @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
- }
-
- return $this->scopes;
- }
-
- /**
- * Returns all Scope children.
- *
- * @return array An array of scope children
- *
- * @deprecated since version 2.8, to be removed in 3.0.
- */
- public function getScopeChildren($triggerDeprecationError = true)
- {
- if ($triggerDeprecationError) {
- @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
- }
-
- return $this->scopeChildren;
- }
-
/**
* Sets a service.
*
- * Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
- *
* @param string $id The service identifier
* @param object $service The service instance
- * @param string $scope The scope
*
* @throws BadMethodCallException When this ContainerBuilder is frozen
*/
- public function set($id, $service, $scope = self::SCOPE_CONTAINER)
+ public function set($id, $service)
{
$id = strtolower($id);
- $set = isset($this->definitions[$id]);
- if ($this->isFrozen() && ($set || isset($this->obsoleteDefinitions[$id])) && !$this->{$set ? 'definitions' : 'obsoleteDefinitions'}[$id]->isSynthetic()) {
+ if ($this->isFrozen() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) {
// setting a synthetic service on a frozen container is alright
- throw new BadMethodCallException(sprintf('Setting service "%s" on a frozen container is not allowed.', $id));
- }
-
- if ($set) {
- $this->obsoleteDefinitions[$id] = $this->definitions[$id];
+ throw new BadMethodCallException(sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a frozen container is not allowed.', $id));
}
unset($this->definitions[$id], $this->aliasDefinitions[$id]);
- parent::set($id, $service, $scope);
-
- if (isset($this->obsoleteDefinitions[$id]) && $this->obsoleteDefinitions[$id]->isSynchronized(false)) {
- $this->synchronize($id);
- }
+ parent::set($id, $service);
}
/**
return $service;
}
- if (!array_key_exists($id, $this->definitions) && isset($this->aliasDefinitions[$id])) {
+ if (!isset($this->definitions[$id]) && isset($this->aliasDefinitions[$id])) {
return $this->get((string) $this->aliasDefinitions[$id], $invalidBehavior);
}
try {
$service = $this->createService($definition, $id);
- } catch (\Exception $e) {
+ } finally {
unset($this->loading[$id]);
-
- if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
- return;
- }
-
- throw $e;
- } catch (\Throwable $e) {
- unset($this->loading[$id]);
-
- throw $e;
}
- unset($this->loading[$id]);
-
return $service;
}
$this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
}
+
+ if ($this->getParameterBag() instanceof EnvPlaceholderParameterBag && $container->getParameterBag() instanceof EnvPlaceholderParameterBag) {
+ $this->getParameterBag()->mergeEnvPlaceholders($container->getParameterBag());
+ }
+
+ foreach ($container->envCounters as $env => $count) {
+ if (!isset($this->envCounters[$env])) {
+ $this->envCounters[$env] = $count;
+ } else {
+ $this->envCounters[$env] += $count;
+ }
+ }
}
/**
$compiler->compile($this);
- if ($this->trackResources) {
- foreach ($this->definitions as $definition) {
- if ($definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
- $this->addClassResource(new \ReflectionClass($class));
- }
+ foreach ($this->definitions as $id => $definition) {
+ if ($this->trackResources && $definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
+ $this->addClassResource(new \ReflectionClass($class));
}
}
$this->extensionConfigs = array();
+ $bag = $this->getParameterBag();
parent::compile();
+
+ $this->envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : array();
}
/**
*/
public function hasDefinition($id)
{
- return array_key_exists(strtolower($id), $this->definitions);
+ return isset($this->definitions[strtolower($id)]);
}
/**
{
$id = strtolower($id);
- if (!array_key_exists($id, $this->definitions)) {
+ if (!isset($this->definitions[$id])) {
throw new ServiceNotFoundException($id);
}
*
* @return object The service described by the service definition
*
- * @throws RuntimeException When the scope is inactive
* @throws RuntimeException When the factory definition is incomplete
* @throws RuntimeException When the service is a synthetic service
* @throws InvalidArgumentException When configure callable is not callable
- *
- * @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code
*/
- public function createService(Definition $definition, $id, $tryProxy = true)
+ private function createService(Definition $definition, $id, $tryProxy = true)
{
if ($definition instanceof DefinitionDecorator) {
throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
}
if ($tryProxy && $definition->isLazy()) {
- $container = $this;
-
$proxy = $this
->getProxyInstantiator()
->instantiateProxy(
- $container,
+ $this,
$definition,
- $id, function () use ($definition, $id, $container) {
- return $container->createService($definition, $id, false);
+ $id, function () use ($definition, $id) {
+ return $this->createService($definition, $id, false);
}
);
$this->shareService($definition, $proxy, $id);
@trigger_error(sprintf('The "%s" service relies on the deprecated "%s" factory class. It should either be deprecated or its factory upgraded.', $id, $r->name), E_USER_DEPRECATED);
}
}
- } elseif (null !== $definition->getFactoryMethod(false)) {
- if (null !== $definition->getFactoryClass(false)) {
- $factory = $parameterBag->resolveValue($definition->getFactoryClass(false));
- } elseif (null !== $definition->getFactoryService(false)) {
- $factory = $this->get($parameterBag->resolveValue($definition->getFactoryService(false)));
- } else {
- throw new RuntimeException(sprintf('Cannot create service "%s" from factory method without a factory service or factory class.', $id));
- }
-
- $service = call_user_func_array(array($factory, $definition->getFactoryMethod(false)), $arguments);
} else {
$r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
return $this->expressionLanguageProviders;
}
+ /**
+ * Resolves env parameter placeholders in a string or an array.
+ *
+ * @param mixed $value The value to resolve
+ * @param string|null $format A sprintf() format to use as replacement for env placeholders or null to use the default parameter format
+ * @param array &$usedEnvs Env vars found while resolving are added to this array
+ *
+ * @return string The string with env parameters resolved
+ */
+ public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs = null)
+ {
+ if (null === $format) {
+ $format = '%%env(%s)%%';
+ }
+
+ if (is_array($value)) {
+ $result = array();
+ foreach ($value as $k => $v) {
+ $result[$this->resolveEnvPlaceholders($k, $format, $usedEnvs)] = $this->resolveEnvPlaceholders($v, $format, $usedEnvs);
+ }
+
+ return $result;
+ }
+
+ if (!is_string($value)) {
+ return $value;
+ }
+
+ $bag = $this->getParameterBag();
+ $envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : $this->envPlaceholders;
+
+ foreach ($envPlaceholders as $env => $placeholders) {
+ foreach ($placeholders as $placeholder) {
+ if (false !== stripos($value, $placeholder)) {
+ $value = str_ireplace($placeholder, sprintf($format, $env), $value);
+ $usedEnvs[$env] = $env;
+ $this->envCounters[$env] = isset($this->envCounters[$env]) ? 1 + $this->envCounters[$env] : 1;
+ }
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Get statistics about env usage.
+ *
+ * @return int[] The number of time each env vars has been resolved
+ */
+ public function getEnvCounters()
+ {
+ $bag = $this->getParameterBag();
+ $envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : $this->envPlaceholders;
+
+ foreach ($envPlaceholders as $env => $placeholders) {
+ if (!isset($this->envCounters[$env])) {
+ $this->envCounters[$env] = 0;
+ }
+ }
+
+ return $this->envCounters;
+ }
+
/**
* Returns the Service Conditionals.
*
return $this->proxyInstantiator;
}
- /**
- * Synchronizes a service change.
- *
- * This method updates all services that depend on the given
- * service by calling all methods referencing it.
- *
- * @param string $id A service id
- *
- * @deprecated since version 2.7, will be removed in 3.0.
- */
- private function synchronize($id)
- {
- if ('request' !== $id) {
- @trigger_error('The '.__METHOD__.' method is deprecated in version 2.7 and will be removed in version 3.0.', E_USER_DEPRECATED);
- }
-
- foreach ($this->definitions as $definitionId => $definition) {
- // only check initialized services
- if (!$this->initialized($definitionId)) {
- continue;
- }
-
- foreach ($definition->getMethodCalls() as $call) {
- foreach ($call[1] as $argument) {
- if ($argument instanceof Reference && $id == (string) $argument) {
- $this->callMethod($this->get($definitionId), $call);
- }
- }
- }
- }
- }
-
private function callMethod($service, $call)
{
$services = self::getServiceConditionals($call[1]);
* @param Definition $definition
* @param mixed $service
* @param string|null $id
- *
- * @throws InactiveScopeException
*/
private function shareService(Definition $definition, $service, $id)
{
- if (null !== $id && $definition->isShared() && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
- if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
- throw new InactiveScopeException($id, $scope);
- }
-
- $this->services[$lowerId = strtolower($id)] = $service;
-
- if (self::SCOPE_CONTAINER !== $scope) {
- $this->scopedServices[$scope][$lowerId] = $service;
- }
+ if (null !== $id && $definition->isShared()) {
+ $this->services[strtolower($id)] = $service;
}
}