1: <?php
2:
3: namespace Alchemy\dialect;
4:
5: class Compiler {
6:
7: protected static $default_tag = 'sql.compile';
8:
9: private $config = array();
10:
11: protected $defaults = array();
12:
13:
14: public function __construct($config = array()) {
15: $this->pushConfig($config + $this->defaults);
16: }
17:
18:
19: 20: 21: 22: 23: 24: 25:
26: public function compile($obj = null, $config = null) {
27: $result = '';
28:
29: if ($config) {
30: $this->pushConfig($config);
31: }
32:
33: if (is_array($obj)) {
34: $result = $this->map('compile', $obj);
35: } elseif (is_object($obj)) {
36: $fn = $this->getFunction($obj, static::$default_tag, '', true);
37: $result = call_user_func($fn, $obj);
38: }
39:
40: if ($config) {
41: $this->popConfig();
42: }
43:
44: return $result;
45: }
46:
47:
48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62:
63: public function format($format = '', $subject = '') {
64: if (!is_array($subject)) {
65: $subject = array($subject);
66: }
67:
68: while (preg_match("/.*?(%(?:(\d+).)?(\d+)?(\p{P})([^\g4]*?)\g4([^\g4]*?)\g4)/", $format, $matches)) {
69: list(,$token, $pos, $start, $p, $subfmt, $delim) = $matches;
70: $start = ((int) $start ?: 1) - 1;
71: $pos = ((int) $pos ?: 1) - 1;
72: $tail = array_slice($pos ? $subject[$pos] : $subject, $start);
73:
74: if ($subfmt) {
75: foreach($tail as &$item) {
76: $item = $this->format($subfmt ?: '%s', $item);
77: }
78: }
79:
80: $subject[] = implode($delim, array_filter($tail));
81: $format = str_replace($token, '%'.count($subject).'$s', $format);
82: }
83:
84: return vsprintf($format, $subject);
85: }
86:
87:
88: public function getConfig($key) {
89: $end = end($this->config);
90: return isset($end[$key]) ? $end[$key] : null;
91: }
92:
93:
94: protected function getFunction($obj, $tag = '', $prefix = '', $strict = false) {
95: $type = $obj->getTag($tag ?: static::$default_tag);
96:
97: if (method_exists($this, "{$prefix}{$type}")) {
98: return array($this, "{$prefix}{$type}");
99: }
100:
101: if ($strict) {
102: throw new \Exception("Compiler method not found with prefix '$prefix' for '$tag' = '$type'");
103: }
104: }
105:
106:
107: public function popConfig() {
108: array_pop($this->config);
109: }
110:
111:
112: public function pushConfig($config) {
113: $end = end($this->config) ?: array();
114: array_push($this->config, array_merge($end, $config));
115: }
116:
117:
118: protected function map($method, $objs) {
119: return array_map(array($this, $method), $objs);
120: }
121: }