@@ -134,53 +134,93 @@ public function getEditor($subtype = NULL,
134134 * Array of metadata objects found.
135135 */
136136 protected function getRawMetadata () {
137- $ id = $ this ->getId ();
138- $ it = new RecursiveDirectoryIterator ($ this ->path );
139- $ filter = array ('json ' );
140- $ metadata = array ();
141- /** @var \SplFileInfo $file */
142- foreach (new RecursiveIteratorIterator ($ it ) as $ file ) {
143- if (!$ file ->isFile ()) {
144- continue ;
145- }
146- $ file_path = $ file ->getPath ();
147- $ dirs = explode (DIRECTORY_SEPARATOR , $ file_path );
148- // All JSON schema must be in an 'api' folder at this time.
149- // @todo Add support for custom setups.
150- // @todo Look at a standard for JSON Schema + JSON Sample data.
151- $ num_dirs = count ($ dirs );
152- if ($ num_dirs < 2
153- || array_pop ($ dirs ) !== 'api ' ) {
154- continue ;
155- }
156- $ file_ext = $ file ->getExtension ();
157- if (!in_array (strtolower ($ file_ext ), $ filter , TRUE )) {
158- continue ;
137+ static $ metadata ;
138+
139+ // Use static pattern to avoid rebuilding multiple times per request.
140+ if (is_null ($ metadata )) {
141+
142+ $ it = new RecursiveDirectoryIterator ($ this ->path );
143+ $ filter = ['json ' , 'twig ' ];
144+ $ metadata = [];
145+ $ components = [];
146+
147+ /** @var \SplFileInfo $file */
148+ foreach (new RecursiveIteratorIterator ($ it ) as $ file ) {
149+ // Skip directories and non-files.
150+ if (!$ file ->isFile ()) {
151+ continue ;
152+ }
153+ $ file_path = $ file ->getPath ();
154+
155+ // Skip tests folders.
156+ if (strpos ($ file_path , '/tests ' ) !== FALSE ) {
157+ continue ;
158+ }
159+
160+ // Get the file extension for the file.
161+ $ file_ext = $ file ->getExtension ();
162+ if (!in_array (strtolower ($ file_ext ), $ filter , TRUE )) {
163+ continue ;
164+ }
165+
166+ // We use file_basename as a unique key, it is required that the
167+ // JSON and twig file share this basename.
168+ $ file_basename = $ file ->getBasename ('. ' . $ file_ext );
169+
170+ // Build an array of all the filenames of interest, keyed by name.
171+ $ components [$ file_basename ][$ file_ext ] = $ file_path ;
159172 }
160- if ($ file_contents = file_get_contents ($ file )) {
161- $ pattern = $ this ->createPattern (json_decode ($ file_contents ));
162- $ file_basename = $ file ->getBasename ('.json ' );
163- $ subtype = "pk_ $ file_basename " ;
164- $ pattern ->subtype = $ subtype ;
165- $ pattern ->url = url ("patternkit/ajax/ $ id/ $ subtype/schema " );
166- $ twig_file = $ file_path
167- . DIRECTORY_SEPARATOR . $ file_basename . '.twig ' ;
168- if (file_exists ($ twig_file )) {
169- $ pattern ->filename = $ twig_file ;
170- $ pattern ->template = file_get_contents ($ twig_file );
173+
174+ foreach ($ components as $ module_name => $ data ) {
175+ // If the component has a json file, create the pattern from it.
176+ if (!empty ($ data ['json ' ]) && $ file_contents = file_get_contents ($ data ['json ' ])) {
177+ $ pattern = $ this ->createPattern (json_decode ($ file_contents ));
178+
179+ $ subtype = "pk_ $ module_name " ;
180+ $ pattern ->subtype = $ subtype ;
181+ // URL is redundant for the twig based components.
182+ $ pattern ->url = $ module_name ;
183+ }
184+ else {
185+ // Create the pattern from defaults.
186+ $ pattern = $ this ->createPattern (
187+ (object ) [
188+ '$schema ' => 'http =>//json-schema.org/draft-04/schema# ' ,
189+ 'category ' => 'atom ' ,
190+ 'title ' => $ module_name ,
191+ 'type ' => 'object ' ,
192+ 'format ' => 'grid ' ,
193+ 'properties ' => (object ) [],
194+ 'required ' => [],
195+ ]
196+ );
197+ }
198+
199+ if (!empty ($ data ['twig ' ])) {
200+ $ twig_file = $ data ['twig ' ]
201+ . DIRECTORY_SEPARATOR . $ module_name . '.twig ' ;
202+ if (file_exists ($ twig_file )) {
203+ $ pattern ->filename = $ twig_file ;
204+ $ pattern ->template = file_get_contents ($ twig_file );
205+ }
171206 }
172- $ metadata [$ file_basename ] = $ pattern ;
207+
208+ $ metadata [$ module_name ] = $ pattern ;
173209 }
174- }
175- foreach ($ metadata as $ pattern_type => $ pattern ) {
176- // Replace any $ref links with relative paths.
177- if (!isset ($ pattern ->schema ->properties )) {
178- continue ;
210+
211+ foreach ($ metadata as $ pattern_type => $ pattern ) {
212+ // Replace any $ref links with relative paths.
213+ if (!isset ($ pattern ->schema ->properties )) {
214+ continue ;
215+ }
216+ $ pattern ->schema ->properties = _patternkit_schema_ref (
217+ $ pattern ->schema ->properties ,
218+ $ metadata
219+ );
220+ $ metadata [$ pattern_type ] = $ pattern ;
179221 }
180- $ pattern ->schema ->properties = _patternkit_schema_ref ($ pattern ->schema ->properties ,
181- $ metadata );
182- $ metadata [$ pattern_type ] = $ pattern ;
183222 }
223+
184224 return $ metadata ;
185225 }
186226
@@ -195,14 +235,115 @@ protected function getRawMetadata() {
195235 * @return string
196236 * The rendered pattern HTML.
197237 */
198- public function getRenderedPatternMarkup (PatternkitPattern $ pattern ,
199- PatternkitEditorConfig $ config ) {
238+ public function getRenderedPatternMarkup (
239+ PatternkitPattern $ pattern ,
240+ PatternkitEditorConfig $ config
241+ ) {
200242 if (empty ($ pattern ->filename ) || empty ($ config ->fields )) {
201243 return '' ;
202244 }
203245 $ template = $ pattern ->filename ;
204246 $ variables = $ config ->fields ;
205- return twig_render_template ($ template , $ variables );
247+
248+ return $ this ->renderTwigTemplate ($ template , $ variables );
249+ }
250+
251+ /**
252+ * Returns a singleton version of the twig template engine.
253+ *
254+ * @return Twig_Environment
255+ * Twig environment object.
256+ *
257+ * @throws \Twig_Error_Loader
258+ * Twig engine instance object.
259+ */
260+ public function getTwigInstance () {
261+ static $ twig_engine ;
262+
263+ if (!is_object ($ twig_engine )) {
264+ // Setup twig environment.
265+ // @TODO: Properly libraryize this.
266+ require_once DRUPAL_ROOT . '/sites/all/libraries/Twig/Autoloader.php ' ;
267+ Twig_Autoloader::register ();
268+
269+ $ loader = new Twig_Loader_Filesystem ();
270+
271+ $ metadata = $ this ->getRawMetadata ();
272+ foreach ($ metadata as $ module_name => $ module ) {
273+ if (!empty ($ module ->filename )) {
274+ $ templatesDirectory = DRUPAL_ROOT . DIRECTORY_SEPARATOR . dirname (
275+ $ module ->filename
276+ );
277+ $ loader ->addPath ($ templatesDirectory );
278+ }
279+ }
280+
281+ $ twig_engine = new Twig_Environment (
282+ $ loader ,
283+ array (
284+ 'autorender ' => (bool ) variable_get ('pktwig_auto_render ' , TRUE ),
285+ 'autoescape ' => (bool ) variable_get ('pktwig_auto_escape ' , FALSE ),
286+ 'auto_reload ' => (bool ) variable_get ('pktwig_auto_reload ' , FALSE ),
287+ 'cache ' => variable_get ('pktwig_template_cache_path ' , '/tmp/twig_compilation_cache ' ),
288+ 'debug ' => (bool ) variable_get ('pktwig_debug ' , FALSE ),
289+ )
290+ );
291+ }
292+
293+ return $ twig_engine ;
294+ }
295+
296+ /**
297+ * Renders a twig template on demand.
298+ *
299+ * @param string $template
300+ * Template filename.
301+ * @param array $variables
302+ * Variables to be assigned to template.
303+ *
304+ * @return string
305+ * Rendered template.
306+ */
307+ public function renderTwigTemplate ($ template , array $ variables = array ()) {
308+
309+ $ content = '' ;
310+ if (file_exists ($ template )) {
311+ try {
312+ $ twig = $ this ->getTwigInstance ();
313+ $ template = $ twig ->loadTemplate (basename ($ template ));
314+ $ content = $ template ->render ($ variables );
315+ }
316+ catch (Exception $ e ) {
317+ $ content = t ('Twig error "!error" ' , array ('!error ' => $ e ->getMessage ()));
318+ watchdog (
319+ 'patternkit ' ,
320+ 'Twig engine failure: @msg ' ,
321+ array (
322+ '@msg ' => $ e ->getMessage (),
323+ ),
324+ WATCHDOG_ERROR
325+ );
326+ }
327+ }
328+ else {
329+ $ content = t (
330+ 'Template (!template) not found ' ,
331+ array (
332+ '!template ' => $ template ,
333+ )
334+ );
335+ watchdog (
336+ 'patternkit ' ,
337+ 'Twig template not found: @msg ' ,
338+ array (
339+ '@msg ' => $ template ,
340+ ),
341+ WATCHDOG_ERROR
342+ );
343+ }
344+
345+ $ content .= "poop " ;
346+ return $ content ;
206347 }
207348
208349}
0 commit comments