Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksip committed Jul 13, 2016
2 parents 51fdd96 + 3d395ba commit 0c48feb
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 143 deletions.
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Data Transform Plugin for Pattern Lab PHP
# Data Transform Plugin for Pattern Lab

This plugin now only works with Twig PatternEngine. You can use old 0.x versions of the plugin for Mustache PatternEngine.


## Installation

Expand All @@ -13,12 +16,12 @@ composer require aleksip/plugin-data-transform

### Pattern-specific data file support for included patterns

Pattern Lab currently only supports global data files and a pattern-specific data file for the main pattern. This plugin adds pattern-specific data file support for included patterns. This feature only works with Twig PatternEngine.
Pattern Lab core only supports global data files and a pattern-specific data file for the main pattern. This plugin adds pattern-specific data file support for included patterns.


### Data transform functions

Currently the plugin provides 3 transform functions for the data read by Pattern Lab. The examples provided are in JSON but Pattern Lab supports YAML too! These functions should work with both Twig and Mustache PatternEngines.
Currently the plugin provides 3 transform functions for the data read by Pattern Lab. The examples provided are in JSON but Pattern Lab supports YAML too!


#### Include pattern files
Expand Down Expand Up @@ -87,6 +90,11 @@ The value of `key` will be replaced with the joined strings. Note that in the ex
The value of `key` will be replaced with an [Attribute object](https://www.drupal.org/node/2513632).


## Global data and includes

Please note that global data from the `_data` directory is considered to be pattern-specific data and will overwrite data inherited from a parent pattern. If you want to override data of an included pattern you can use the `with` keyword.


## More examples

All features provided by this plugin are used extensively in [Shila Drupal Theme StarterKit](https://github.com/aleksip/starterkit-shila-drupal-theme).
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
},
"require": {
"php": ">=5.5.9",
"pattern-lab/core": "^2.6.3",
"pattern-lab/patternengine-twig": "^2.0.0"
}
}
165 changes: 165 additions & 0 deletions src/aleksip/DataTransformPlugin/DataTransformer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?php

namespace aleksip\DataTransformPlugin;

use Drupal\Core\Template\Attribute;
use PatternLab\Data;
use PatternLab\PatternData;
use PatternLab\PatternEngine;

class DataTransformer
{
protected $env;
protected $reservedKeys;
protected $patternDataStore;
protected $processed;

public function __construct(\Twig_Environment $env)
{
$this->env = $env;
// TODO: Add an accessor function for $reservedKeys to the Data class?
$this->reservedKeys = array("cacheBuster","link","patternSpecific","patternLabHead","patternLabFoot");
$this->patternDataStore = PatternData::get();
$this->processed = array();
}

public function run()
{
// Process global data.
$dataStore = $this->processData(Data::get());
Data::replaceStore($dataStore);
// Process pattern specific data.
foreach (array_keys($this->patternDataStore) as $pattern) {
$this->processPattern($pattern);
}
}

protected function isProcessed($pattern)
{
return isset($this->processed[$pattern]);
}

protected function setProcessed($pattern)
{
$this->processed[$pattern] = true;
}

protected function processPattern($pattern)
{
if (
$this->isProcessed($pattern)
|| !isset($this->patternDataStore[$pattern])
|| $this->patternDataStore[$pattern]['category'] != 'pattern'
) {
return;
}
$patternSpecificData =
$this->processData(Data::getPatternSpecificData($pattern))
;
$dataStore = Data::get();
foreach (array_keys($patternSpecificData) as $key) {
if (!isset($dataStore['patternSpecific'][$pattern]['data'][$key])) {
// Value is default global data.
if (is_object($dataStore[$key])) {
$patternSpecificData[$key] = clone $dataStore[$key];
}
}
}
Data::initPattern($pattern);
Data::setPatternData($pattern, $patternSpecificData);
$this->setProcessed($pattern);
}

protected function processData($data)
{
foreach (array_keys($data) as $key) {
if (!in_array($key, $this->reservedKeys)) {
$data = $this->processKey($data, $key);
}
}

return $data;
}

protected function processKey($data, $key)
{
$value = $data[$key];
if (is_array($value)) {
foreach (array_keys($value) as $subKey) {
$value = $this->processKey($value, $subKey);
}
if (isset($value['Attribute()']) && is_array($value['Attribute()'])) {
$data[$key] = new Attribute($value['Attribute()']);
}
elseif (isset($value['include()']) && is_array($value['include()']) && isset($value['include()']['pattern'])) {
$pattern = $value['include()']['pattern'];
if (is_string($pattern) && isset($this->patternDataStore[$pattern])) {
if (!isset($value['include()']['with']) || !is_array($value['include()']['with'])) {
if (!isset($value['include()']['only'])) {
$patternData = $this->getProcessedPatternSpecificData($pattern);
}
else {
$patternData = array();
}
}
elseif (!isset($value['include()']['only'])) {
$patternData = $this->getProcessedPatternSpecificData($pattern, $value['include()']['with']);
}
else {
$patternData = $value['include()']['with'];
}
$data[$key] = $this->renderPattern($pattern, $patternData);
}
}
elseif (isset($value['join()']) && is_array($value['join()'])) {
$data[$key] = join($value['join()']);
}
else {
$data[$key] = $value;
}
}
elseif (is_string($value) && isset($this->patternDataStore[$value]) && $key !== 'pattern') {
$data[$key] = $this->renderPattern($value, $this->getProcessedPatternSpecificData($value));
}

return $data;
}

public function getProcessedPatternSpecificData($pattern, $extraData = array())
{
$this->processPattern($pattern);

return Data::getPatternSpecificData($pattern, $extraData);
}

protected function renderPattern($pattern, $data)
{
if (isset($this->patternDataStore[$pattern]['patternRaw'])) {
foreach (array_keys($data) as $key) {
$data = $this->cloneObjects($data, $key);
}
$pattern = $this->env->render(
$this->patternDataStore[$pattern]['patternRaw'],
$data
);
}

return $pattern;
}

protected function cloneObjects($data, $key)
{
$value = $data[$key];
if (is_array($value)) {
foreach (array_keys($value) as $subKey) {
$value = $this->cloneObjects($value, $subKey);
}
$data[$key] = $value;
}
elseif (is_object($value)) {
$data[$key] = clone $value;
}

return $data;
}
}
124 changes: 0 additions & 124 deletions src/aleksip/DataTransformPlugin/Helper.php

This file was deleted.

24 changes: 10 additions & 14 deletions src/aleksip/DataTransformPlugin/PatternLabListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,24 @@

use aleksip\DataTransformPlugin\Twig\PatternDataNodeVisitor;
use PatternLab\Listener;
use PatternLab\PatternData\Event;
use PatternLab\PatternEngine\Twig\TwigUtil;

class PatternLabListener extends Listener
{
public function __construct()
{
$this->addListener('patternData.codeHelperStart', 'runHelper');
$this->addListener('twigPatternLoader.customize', 'addNodeVisitor');
$this->addListener(
'twigPatternLoader.customize',
'twigPatternLoaderCustomize'
);
}

public function runHelper(Event $event)
public function twigPatternLoaderCustomize()
{
$options = $event->getOptions();
$helper = new Helper($options);
$helper->run();
}

public function addNodeVisitor()
{
$instance = TwigUtil::getInstance();
$instance->addNodeVisitor(new PatternDataNodeVisitor());
TwigUtil::setInstance($instance);
$env = TwigUtil::getInstance();
$dt = new DataTransformer($env);
$env->addNodeVisitor(new PatternDataNodeVisitor($dt));
TwigUtil::setInstance($env);
$dt->run();
}
}
Loading

0 comments on commit 0c48feb

Please sign in to comment.