1<?php
2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3//
4// All Rights Reserved. See copyright.txt for details and a complete list of authors.
5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
6// $Id$
7
8namespace Tracker\Tabular\Schema;
9
10class Column
11{
12	const HEADER_PATTERN = '/\[(\*?)(\w+):([^\]]+)\]$/';
13
14	private $permName;
15	private $label;
16	private $mode;
17	private $isPrimary = false;
18	private $isReadOnly = false;
19	private $isExportOnly = false;
20	private $isUniqueKey = false;
21	private $displayAlign = 'left';
22	private $renderTransform;
23	private $parseIntoTransform;
24	private $querySources = [];
25	private $incompatibilities = [];
26	private $plainReplacement = null;
27
28	function __construct($permName, $mode)
29	{
30		$this->permName = $permName;
31		$this->mode = $mode;
32		$this->parseIntoTransform = function (& $info, $value) {
33		};
34	}
35
36	function getLabel()
37	{
38		return $this->label;
39	}
40
41	function setLabel($label)
42	{
43		$this->label = $label;
44		return $this;
45	}
46
47	function getDisplayAlign()
48	{
49		return $this->displayAlign;
50	}
51
52	function setDisplayAlign($align)
53	{
54		$this->displayAlign = $align;
55		return $this;
56	}
57
58	function addIncompatibility($field, $mode)
59	{
60		$this->incompatibilities[] = [$field, $mode];
61		return $this;
62	}
63
64	function setRenderTransform(callable $transform)
65	{
66		$this->renderTransform = $transform;
67		return $this;
68	}
69
70	function setParseIntoTransform(callable $transform)
71	{
72		$this->parseIntoTransform = $transform;
73		return $this;
74	}
75
76	function setPrimaryKey($pk)
77	{
78		$this->isPrimary = (bool) $pk;
79		return $this;
80	}
81
82	function setReadOnly($readOnly)
83	{
84		$this->isReadOnly = (bool) $readOnly;
85		return $this;
86	}
87
88	function setExportOnly($exportOnly)
89	{
90		$this->isExportOnly = (bool) $exportOnly;
91		return $this;
92	}
93
94	function setUniqueKey($uniqueKey)
95	{
96		$this->isUniqueKey = (bool) $uniqueKey;
97		return $this;
98	}
99
100	function setPlainReplacement($replacement)
101	{
102		$this->plainReplacement = $replacement;
103		return $this;
104	}
105
106	function is($field, $mode)
107	{
108		return $field == $this->permName && $mode == $this->mode;
109	}
110
111	function isPrimaryKey()
112	{
113		return $this->isPrimary;
114	}
115
116	function isReadOnly()
117	{
118		return $this->isReadOnly;
119	}
120
121	function isExportOnly()
122	{
123		return $this->isExportOnly;
124	}
125
126	function isUniqueKey()
127	{
128		return $this->isUniqueKey;
129	}
130
131	function getField()
132	{
133		return $this->permName;
134	}
135
136	function getMode()
137	{
138		return $this->mode;
139	}
140
141	function getEncodedHeader()
142	{
143		if ($this->isReadOnly) {
144			return $this->label;
145		} else {
146			$pk = $this->isPrimary ? '*' : '';
147			return "{$this->label} [$pk{$this->permName}:{$this->mode}]";
148		}
149	}
150
151	function getPlainReplacement()
152	{
153		return $this->plainReplacement;
154	}
155
156	function render($value)
157	{
158		return call_user_func_array($this->renderTransform, func_get_args());
159	}
160
161	function parseInto(& $info, $value)
162	{
163		$c = $this->parseIntoTransform;
164		if (! $this->isReadOnly) {
165			$c($info, $value);
166		}
167	}
168
169	function addQuerySource($name, $field)
170	{
171		$this->querySources[$name] = $field;
172		return $this;
173	}
174
175	function getQuerySources()
176	{
177		return $this->querySources;
178	}
179
180	function validateAgainst(\Tracker\Tabular\Schema $schema)
181	{
182		if ($this->isPrimary && $this->isReadOnly) {
183			throw new \Exception(tr('Primary Key fields cannot be read-only.'));
184		}
185
186		$selfCount = 0;
187
188		foreach ($schema->getColumns() as $column) {
189			if ($column->is($this->permName, $this->mode)) {
190				$selfCount++;
191			}
192
193			foreach ($this->incompatibilities as $entry) {
194				list($field, $mode) = $entry;
195
196				if ($column->is($field, $mode)) {
197					// Skip incompatibility if either field is read-only
198					if ($this->isReadOnly() || $column->isReadOnly()) {
199						continue;
200					}
201
202					throw new \Exception(tr(
203						'Column "%0" cannot co-exist with "%1".',
204						$column->getEncodedHeader(),
205						$this->getEncodedHeader()
206					));
207				}
208			}
209		}
210
211		if ($selfCount > 1) {
212			throw new \Exception(tr('Column "%0:%1" found multiple times.', $this->permName, $this->mode));
213		}
214	}
215
216	function withWrappedRenderTransform(callable $callback)
217	{
218		$column = new self($this->permName, $this->mode);
219		$column->label = $this->label;
220		$column->isPrimary = $this->isPrimary;
221		$column->isReadOnly = $this->isReadOnly;
222		$column->isExportOnly = $this->isExportOnly;
223		$column->isUniqueKey = $this->isUniqueKey;
224		$column->displayAlign = $this->displayAlign;
225		$column->parseIntoTransform = $this->parseIntoTransform;
226		$column->querySources = $this->querySources;
227		$column->incompatibilities = $this->incompatibilities;
228		$column->plainReplacement = $this->plainReplacement;
229
230		$column->renderTransform = function () use ($callback) {
231			$value = call_user_func_array($this->renderTransform, func_get_args());
232			return $callback($value);
233		};
234
235		return $column;
236	}
237}
238