1+ <?php
2+
3+ namespace Propel \Bundle \PropelBundle \DependencyInjection ;
4+
5+ use Propel \Bundle \PropelBundle \DataCollector \PropelDataCollector ;
6+ use Symfony \Component \DependencyInjection \ContainerInterface ;
7+
8+ /**
9+ * Factory to create the 'propel.configuration', 'propel.data_collector', and 'propel.build_properties' services at
10+ * runtime. Services must be configured as synthetic in the bundle configuration, then the factory methods called
11+ * during the PropelBundle::boot() method.
12+ *
13+ * Class PropelConfigurationFactory
14+ *
15+ * @author AMJones <am@jonesiscoding.com>
16+ * @package Propel\Bundle\PropelBundle\DependencyInjection
17+ */
18+ class PropelServiceFactory
19+ {
20+ const CONFIG = 'propel.configuration ' ;
21+ const DATA_COLLECTOR = 'propel.data_collector ' ;
22+ const BUILD_PROPERTIES = 'propel.build_properties ' ;
23+
24+ /**
25+ * Creates a PropelDataCollector object using the 'propel.data_collector' parameter and 'propel.logger' service,
26+ * then injects the object into the container as the 'propel.build_properties' service, replacing the synthetic.
27+ *
28+ * If the container does not already have the 'propel.configuration' service, it will be created and injected into
29+ * the container as well.
30+ *
31+ * @param ContainerInterface $container
32+ *
33+ * @return PropelDataCollector|object
34+ */
35+ public function collector (ContainerInterface $ container ): PropelDataCollector
36+ {
37+ $ name = static ::DATA_COLLECTOR ;
38+ if (!$ container ->has ($ name ))
39+ {
40+ // Make sure that we have a propel.configuration service
41+ $ config = $ this ->config ($ container );
42+ // Get the logger Service
43+ $ logger = $ container ->get ('propel.logger ' );
44+ // Get the class & create object
45+ $ class = $ this ->getClass ($ container , $ name );
46+ $ object = new $ class ($ logger , $ config );
47+
48+ $ container ->set ($ name , $ object );
49+ }
50+
51+ return $ container ->get ($ name );
52+ }
53+
54+ /**
55+ * Creates a \PropelConfiguration object using the 'propel.configuration.class' and 'propel.dbal' parameters,
56+ * then injects the object into the container as the 'propel.configuration' service, replacing the synthetic.
57+ *
58+ * @param ContainerInterface $container
59+ *
60+ * @return \PropelConfiguration|object
61+ */
62+ public function config (ContainerInterface $ container ): \PropelConfiguration
63+ {
64+ $ name = static ::CONFIG ;
65+ if (!$ container ->has ($ name ))
66+ {
67+ $ class = $ this ->getClass ($ container , $ name ) ?? \PropelConfiguration::class;
68+ $ dbal = $ this ->normalizeDbal ($ this ->getArrayParameter ($ container , 'propel.dbal ' ));
69+ $ config = new $ class ($ dbal );
70+
71+ if ($ this ->isPropelLogging ($ container ))
72+ {
73+ $ config ->setParameter ('debugpdo.logging.methods ' , array (
74+ 'PropelPDO::exec ' ,
75+ 'PropelPDO::query ' ,
76+ 'PropelPDO::prepare ' ,
77+ 'DebugPDOStatement::execute ' ,
78+ ), false );
79+
80+ $ config ->setParameter ('debugpdo.logging.details ' , array (
81+ 'time ' => array ('enabled ' => true ),
82+ 'mem ' => array ('enabled ' => true ),
83+ 'connection ' => array ('enabled ' => true ),
84+ ));
85+ }
86+
87+ $ container ->set ($ name , $ config );
88+ }
89+
90+ return $ container ->get ($ name );
91+ }
92+
93+ /**
94+ * Creates a Properties object using the 'propel.build_properties' and 'propel.build_properties.class' parameters,
95+ * then injects the object into the container as the 'propel.build_properties' service, replacing the synthetic.
96+ *
97+ * @param ContainerInterface $container
98+ *
99+ * @return Properties|object
100+ */
101+ public function properties (ContainerInterface $ container ): Properties
102+ {
103+ $ name = static ::BUILD_PROPERTIES ;
104+ if (!$ container ->has ($ name ))
105+ {
106+ $ class = $ this ->getClass ($ container , $ name ) ?? Properties::class;
107+ $ props = $ this ->getArrayParameter ($ container , $ name );
108+ $ obj = new $ class ($ props );
109+
110+ $ container ->set ($ name , $ obj );
111+ }
112+
113+ return $ container ->get ($ name );
114+ }
115+
116+ /**
117+ * Evaluates if the 'logging' option in the propel configuration is set to TRUE.
118+ * Requires that the 'propel.logging' parameter is previously injected into the container,
119+ * typically in PropelExtension.
120+ *
121+ * @param ContainerInterface $container
122+ *
123+ * @return bool
124+ */
125+ public function isPropelLogging (ContainerInterface $ container )
126+ {
127+ return $ container ->hasParameter ('propel.logging ' ) && (bool )$ container ->getParameter ('propel.logging ' );
128+ }
129+
130+ /**
131+ * Normalizes config settings containing the database driver. While this is also done in the configuration at
132+ * compile time, some values may be environment value placeholders, which cannot be normalized.
133+ *
134+ * @param array $dbal
135+ *
136+ * @return array
137+ */
138+ private function normalizeDbal ($ dbal )
139+ {
140+ $ normalizer = new DriverNormalizer ();
141+ $ datasources = $ dbal ['datasources ' ] ?? array ();
142+
143+ foreach ($ datasources as $ name => $ datasource )
144+ {
145+ $ datasources [$ name ] = $ normalizer ->normalizeDatasource ($ datasource );
146+ }
147+
148+ $ dbal ['datasources ' ] = $ datasources ;
149+
150+ return $ dbal ;
151+ }
152+
153+ /**
154+ * Checks for and returns a parameter as an array. Returns an empty array if the parameter
155+ * is not present in the container, or is not an array value.
156+ *
157+ * @param ContainerInterface $container
158+ * @param string $name
159+ *
160+ * @return array
161+ */
162+ private function getArrayParameter (ContainerInterface $ container , string $ name ): array
163+ {
164+ if ($ container ->hasParameter ($ name ))
165+ {
166+ $ props = $ container ->getParameter ($ name );
167+
168+ if (is_array ($ props ))
169+ {
170+ return $ props ;
171+ }
172+ }
173+
174+ return array ();
175+ }
176+
177+ /**
178+ * Gets the fully qualified class name for the given prefix, as long as the parameter is set in the container.
179+ *
180+ * @param ContainerInterface $container The container, which should have the <prefix>.class parameter.
181+ * @param string $prefix The string to put before .class when retrieving the parameter.
182+ *
183+ * @return string|null
184+ */
185+ private function getClass (ContainerInterface $ container , string $ prefix )
186+ {
187+ $ name = $ prefix . '.class ' ;
188+ if ($ container ->hasParameter ($ name ))
189+ {
190+ $ class = $ container ->getParameter ($ name );
191+ if (is_string ($ class ) && class_exists ($ class ))
192+ {
193+ return $ class ;
194+ }
195+ }
196+
197+ return null ;
198+ }
199+ }
0 commit comments