1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\DependencyInjection\Compiler; 13 14use Symfony\Component\DependencyInjection\ContainerBuilder; 15use Symfony\Component\DependencyInjection\Exception\EnvParameterException; 16 17/** 18 * This class is used to remove circular dependencies between individual passes. 19 * 20 * @author Johannes M. Schmitt <schmittjoh@gmail.com> 21 */ 22class Compiler 23{ 24 private $passConfig; 25 private $log = []; 26 private $serviceReferenceGraph; 27 28 public function __construct() 29 { 30 $this->passConfig = new PassConfig(); 31 $this->serviceReferenceGraph = new ServiceReferenceGraph(); 32 } 33 34 /** 35 * Returns the PassConfig. 36 * 37 * @return PassConfig The PassConfig instance 38 */ 39 public function getPassConfig() 40 { 41 return $this->passConfig; 42 } 43 44 /** 45 * Returns the ServiceReferenceGraph. 46 * 47 * @return ServiceReferenceGraph The ServiceReferenceGraph instance 48 */ 49 public function getServiceReferenceGraph() 50 { 51 return $this->serviceReferenceGraph; 52 } 53 54 /** 55 * Adds a pass to the PassConfig. 56 * 57 * @param string $type The type of the pass 58 * @param int $priority Used to sort the passes 59 */ 60 public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0) 61 { 62 $this->passConfig->addPass($pass, $type, $priority); 63 } 64 65 /** 66 * @final 67 */ 68 public function log(CompilerPassInterface $pass, string $message) 69 { 70 if (false !== strpos($message, "\n")) { 71 $message = str_replace("\n", "\n".\get_class($pass).': ', trim($message)); 72 } 73 74 $this->log[] = \get_class($pass).': '.$message; 75 } 76 77 /** 78 * Returns the log. 79 * 80 * @return array Log array 81 */ 82 public function getLog() 83 { 84 return $this->log; 85 } 86 87 /** 88 * Run the Compiler and process all Passes. 89 */ 90 public function compile(ContainerBuilder $container) 91 { 92 try { 93 foreach ($this->passConfig->getPasses() as $pass) { 94 $pass->process($container); 95 } 96 } catch (\Exception $e) { 97 $usedEnvs = []; 98 $prev = $e; 99 100 do { 101 $msg = $prev->getMessage(); 102 103 if ($msg !== $resolvedMsg = $container->resolveEnvPlaceholders($msg, null, $usedEnvs)) { 104 $r = new \ReflectionProperty($prev, 'message'); 105 $r->setAccessible(true); 106 $r->setValue($prev, $resolvedMsg); 107 } 108 } while ($prev = $prev->getPrevious()); 109 110 if ($usedEnvs) { 111 $e = new EnvParameterException($usedEnvs, $e); 112 } 113 114 throw $e; 115 } finally { 116 $this->getServiceReferenceGraph()->clear(); 117 } 118 } 119} 120