1+ <?php
2+
3+ namespace Cache \DoctrineCacheBundle \DependencyInjection \CompilerPass ;
4+
5+ use Symfony \Component \Config \Definition \Exception \InvalidConfigurationException ;
6+ use Symfony \Component \DependencyInjection \Compiler \CompilerPassInterface ;
7+ use Symfony \Component \DependencyInjection \ContainerBuilder ;
8+ use Symfony \Component \DependencyInjection \Definition ;
9+ use Symfony \Component \DependencyInjection \Reference ;
10+
11+ class ServiceBuilderPass implements CompilerPassInterface
12+ {
13+ /**
14+ * Array of types, and their options
15+ *
16+ * @var array $types
17+ */
18+ protected static $ types = [
19+ 'memcache ' => [
20+ 'class ' => 'Memcache ' ,
21+ 'connect ' => 'addServer '
22+ ],
23+ 'memcached ' => [
24+ 'class ' => 'Aequasi\Bundle\CacheBundle\Cache\Memcached ' ,
25+ 'connect ' => 'addServer '
26+ ],
27+ 'redis ' => [
28+ 'class ' => 'Redis ' ,
29+ 'connect ' => 'connect '
30+ ]
31+ ];
32+
33+ /**
34+ *For each configured instance, build a service
35+ *
36+ * @param ContainerBuilder $container
37+ */
38+ public function process (ContainerBuilder $ container )
39+ {
40+ $ instances = $ container ->getParameter ('doctrine_cache.instance ' );
41+
42+ foreach ($ instances as $ name => $ instance ) {
43+ $ typeId = 'doctrine_cache.abstract. ' .$ instance ['type ' ];
44+ if (!$ container ->findDefinition ($ typeId )) {
45+ throw new InvalidConfigurationException (
46+ sprintf (
47+ "`%s` is not a valid cache type. If you are using a custom type, make sure to add your service. " ,
48+ $ instance ['type ' ]
49+ )
50+ );
51+ }
52+
53+ $ service = $ this ->buildService ($ container , $ typeId , $ name , $ instance );
54+ $ this ->prepareCacheClass ($ container , $ service , $ name , $ instance );
55+ }
56+ }
57+
58+ /**
59+ * @param string $typeId
60+ * @param string $name
61+ * @param array $instance
62+ *
63+ * @return Definition
64+ */
65+ private function buildService (ContainerBuilder $ container , $ typeId , $ name , array $ instance )
66+ {
67+ $ namespace = is_null ($ instance ['namespace ' ]) ? $ name : $ instance ['namespace ' ];
68+ $ serviceId = 'doctrine_cache.instance. ' .$ name ;
69+
70+ // Modify the core doctrine cache class
71+ $ doctrine = $ container ->getDefinition ($ typeId );
72+ $ doctrine ->addMethodCall ('setNamespace ' , [$ namespace ])
73+ ->setPublic (false );
74+
75+ // Register the CacheItemPoolInterface definition
76+ $ def = $ container ->setDefinition (
77+ $ serviceId ,
78+ \Cache \Doctrine \CachePoolItem::class
79+ );
80+ $ def ->addArgument (0 , new Reference ($ typeId ));
81+
82+ //TODO add alias
83+
84+ return $ doctrine ;
85+ }
86+
87+ /**
88+ * We need to prepare the doctrine cache providers
89+ *
90+ * @param Definition $service
91+ * @param string $name
92+ * @param array $instance
93+ *
94+ * @return Boolean
95+ */
96+ private function prepareCacheClass (ContainerBuilder $ container , Definition $ service , $ name , array $ instance )
97+ {
98+ $ type = $ instance ['type ' ];
99+ $ id = sprintf ("doctrine_cache.instance.%s.cache_instance " , $ name );
100+ switch ($ type ) {
101+ case 'memcache ' :
102+ case 'memcached ' :
103+ case 'redis ' :
104+ return $ this ->createCacheInstance ($ container , $ service , $ type , $ id , $ instance );
105+ case 'file_system ' :
106+ case 'php_file ' :
107+ $ directory = '%kernel.cache_dir%/doctrine/cache ' ;
108+ if (null !== $ instance ['directory ' ]) {
109+ $ directory = $ instance ['directory ' ];
110+ }
111+ $ extension = is_null ($ instance ['extension ' ]) ? null : $ instance ['extension ' ];
112+
113+ $ service ->setArguments ([$ directory , $ extension ]);
114+
115+ return true ;
116+ case 'mongo ' :
117+ case 'sqlite3 ' :
118+ case 'sqlite ' :
119+ case 'riak ' :
120+ case 'chain ' :
121+ return false ;
122+ default :
123+ return true ;
124+ }
125+ }
126+
127+ /**
128+ * Creates a cache instance
129+ *
130+ * @param Definition $service
131+ * @param string $type
132+ * @param string $id
133+ * @param array $instance
134+ *
135+ * @return Boolean
136+ */
137+ public function createCacheInstance (ContainerBuilder $ container , Definition $ service , $ type , $ id , array $ instance )
138+ {
139+ if (empty ($ instance ['id ' ])) {
140+ $ cache = new Definition (self ::$ types [$ type ]['class ' ]);
141+
142+ // set memcached options first as they need to be set before the servers are added.
143+ if ($ type === 'memcached ' ) {
144+ if (!empty ($ instance ['options ' ]['memcached ' ])) {
145+ foreach ($ instance ['options ' ]['memcached ' ] as $ option => $ value ) {
146+ switch ($ option ) {
147+ case 'serializer ' :
148+ case 'hash ' :
149+ case 'distribution ' :
150+ $ value = constant (
151+ sprintf ('\Memcached::%s_%s ' , strtoupper ($ option ), strtoupper ($ value ))
152+ );
153+ break ;
154+ }
155+ $ cache ->addMethodCall (
156+ 'setOption ' ,
157+ [constant (sprintf ('\Memcached::OPT_%s ' , strtoupper ($ option ))), $ value ]
158+ );
159+ }
160+ }
161+ }
162+
163+ if (isset ($ instance ['persistent ' ]) && $ instance ['persistent ' ] !== false ) {
164+ if ($ instance ['persistent ' ] !== true ) {
165+ $ persistentId = $ instance ['persistent ' ];
166+ } else {
167+ $ persistentId = substr (md5 (serialize ($ instance ['hosts ' ])), 0 , 5 );
168+ }
169+ if ($ type === 'memcached ' ) {
170+ $ cache ->setArguments ([$ persistentId ]);
171+ }
172+ if ($ type === 'redis ' ) {
173+ self ::$ types [$ type ]['connect ' ] = 'pconnect ' ;
174+ }
175+ }
176+
177+ foreach ($ instance ['hosts ' ] as $ config ) {
178+ $ arguments = [
179+ 'host ' => empty ($ config ['host ' ]) ? 'localhost ' : $ config ['host ' ],
180+ 'port ' => empty ($ config ['port ' ]) ? 11211 : $ config ['port ' ]
181+ ];
182+ if ($ type === 'memcached ' ) {
183+ $ arguments [] = is_null ($ config ['weight ' ]) ? 0 : $ config ['weight ' ];
184+ } else {
185+ $ arguments [] = is_null ($ config ['timeout ' ]) ? 0 : $ config ['timeout ' ];
186+ if (isset ($ persistentId )) {
187+ $ arguments [] = $ persistentId ;
188+ }
189+ }
190+
191+ $ cache ->addMethodCall (self ::$ types [$ type ]['connect ' ], $ arguments );
192+ }
193+ unset($ config );
194+
195+ if ($ type === 'redis ' ) {
196+ if (isset ($ instance ['auth_password ' ]) && null !== $ instance ['auth_password ' ]) {
197+ $ cache ->addMethodCall ('auth ' , [$ instance ['auth_password ' ]]);
198+ }
199+ if (isset ($ instance ['database ' ])) {
200+ $ cache ->addMethodCall ('select ' , [$ instance ['database ' ]]);
201+ }
202+ }
203+
204+ $ container ->setDefinition ($ id , $ cache );
205+ } else {
206+ $ id = $ instance ['id ' ];
207+ }
208+ $ service ->addMethodCall (sprintf ('set%s ' , ucwords ($ type )), [new Reference ($ id )]);
209+
210+ return true ;
211+ }
212+ }
0 commit comments