PageRenderTime 45ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/core/Build/BuilderElement.php

http://cintient.googlecode.com/
PHP | 322 lines | 232 code | 12 blank | 78 comment | 35 complexity | e40a10c3d445234f992ce414f9bca9ca MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /*
  3. *
  4. * Cintient, Continuous Integration made simple.
  5. * Copyright (c) 2010, 2011, Pedro Mata-Mouros Fonseca
  6. *
  7. * This file is part of Cintient.
  8. *
  9. * Cintient is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * Cintient is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with Cintient. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. /**
  24. * Builder element base class from which all builder elements must
  25. * derive. It features commodity methods for easily accessing specific
  26. * nodes. It also automagically handles exporting deriving elements to
  27. * a specific connector.
  28. *
  29. * @package Build
  30. * @author Pedro Mata-Mouros Fonseca <pedro.matamouros@gmail.com>
  31. * @copyright 2010-2011, Pedro Mata-Mouros Fonseca.
  32. * @license http://www.gnu.org/licenses/gpl-3.0.html GNU GPLv3 or later.
  33. * @version $LastChangedRevision: 363 $
  34. * @link $HeadURL: http://cintient.googlecode.com/svn/trunk/src/core/Build/BuilderElement.php $
  35. * Changed by $LastChangedBy: pedro.matamouros $
  36. * Changed on $LastChangedDate: 2011-09-26 01:32:38 +0200 (Mon, 26 Sep 2011) $
  37. */
  38. class Build_BuilderElement extends Framework_BaseObject
  39. {
  40. protected $_active; // Indicates if this builder element should be considered executable
  41. protected $_deletable; // Special system builder elements might not be deleted by the user. Not user setable.
  42. protected $_editable; // Special system builder elements might not be editable by the user. Not user setable.
  43. protected $_failOnError;
  44. protected $_internalId;
  45. protected $_specialTask; // This element is a special task and this is a reference to the special task class.
  46. protected $_visible; // Special system builder elements might not be visible by the user. Not user setable.
  47. public function __construct()
  48. {
  49. $this->_active = true;
  50. $this->_deletable = true;
  51. $this->_editable = true;
  52. $this->_failOnError = true;
  53. $this->_internalId = Utility::generateRandomString() . uniqid();
  54. $this->_specialTask = false;
  55. $this->_visible = true;
  56. }
  57. static protected function _expandStr($str, Array &$context = array())
  58. {
  59. return preg_replace_callback('/\$\{(\w*)\}/', function($matches) use (&$context) {
  60. if (isset($context['properties'][$matches[1]])) {
  61. return $context['properties'][$matches[1]];
  62. } else {
  63. SystemEvent::raise(SystemEvent::INFO, "Couldn't expand user variable {$matches[0]}, no such property was found. Assumed value '{$matches[1]}'.", __METHOD__);
  64. return $matches[1];
  65. }
  66. }, $str);
  67. }
  68. /**
  69. * Helper function for centralizing all Builder Element's title HTML
  70. *
  71. * @param Array $params
  72. */
  73. public function getHtmlTitle(Array $params = array())
  74. {
  75. $o = $this;
  76. h::div(array('class' => 'builderElementTitle'), function() use ($o, $params) {
  77. h::p(array('class' => 'title'), $params['title']);
  78. h::ul(array('class' => 'options'), function() use ($o) {
  79. if ($o->isEditable()) {
  80. h::li(function() {h::a('save', '#', array('class' => 'submit'));});
  81. }
  82. if ($o->isDeletable()) {
  83. h::li(function() {h::a('delete', '#', array('class' => 'delete'));});
  84. }
  85. });
  86. });
  87. }
  88. public function getElement($id)
  89. {
  90. if ($id == $this->_internalId) {
  91. return $this;
  92. }
  93. $internalId = null;
  94. $attributes = get_object_vars($this);
  95. foreach ($attributes as $attribute) {
  96. if (is_object($attribute)) { // Go to the next nested level
  97. $internalId = $attribute->getElement($id);
  98. } elseif (is_array($attribute)) { // Tear down the array
  99. if (!function_exists('f')) {
  100. //
  101. // Tears down an array until an element or the end is found
  102. //
  103. function f($array, $id)
  104. {
  105. $internalId = null;
  106. foreach ($array as $attribute) {
  107. if (is_object($attribute)) {
  108. $internalId = $attribute->getElement($id); // Go down one level
  109. } elseif (is_array($attribute)) {
  110. $internalId = f($attribute, $id); // Tear down the array
  111. }
  112. if (!empty($internalId)) {
  113. break;
  114. }
  115. }
  116. return $internalId;
  117. }
  118. }
  119. $internalId = f($attribute, $id);
  120. }
  121. if (!empty($internalId)) {
  122. break;
  123. }
  124. }
  125. return $internalId;
  126. }
  127. /**
  128. * I'm pretty sure I will one day look at this method and either cry or laugh...
  129. * Don't publicly call this with the second parameter set. It's for
  130. * internal purposes only... Oh my...
  131. *
  132. */
  133. public function getParent($id, &$parentElement = null)
  134. {
  135. if ($id == $this->_internalId) {
  136. return $this;
  137. }
  138. $attributes = get_object_vars($this);
  139. $currentElement = $this;
  140. $oldParent = $parentElement;
  141. foreach ($attributes as $attribute) {
  142. if (is_object($attribute)) { // Go to the next nested level
  143. $parentElement = $currentElement;
  144. $res = $attribute->getParent($id, $parentElement);
  145. } elseif (is_array($attribute)) { // Tear down the array
  146. //
  147. // Tears down an array until an element or the end is found
  148. //
  149. $f = function ($array, $id) use (&$parentElement)
  150. {
  151. $res = null;
  152. foreach ($array as $attribute) {
  153. if (is_object($attribute)) {
  154. $res = $attribute->getParent($id, $parentElement); // Go down one level
  155. } elseif (is_array($attribute)) {
  156. $res = call_user_func(__FUNCTION__, $attribute, $id); // Tear down the array
  157. }
  158. if (!empty($res)) {
  159. return $res;
  160. }
  161. }
  162. return false;
  163. };
  164. $parentElement = $currentElement;
  165. $res = $f($attribute, $id);
  166. }
  167. if (!empty($res)) {
  168. return $parentElement;
  169. } else {
  170. $parentElement = $oldParent;
  171. }
  172. }
  173. return false;
  174. }
  175. /**
  176. * Deletes an element with a given ID from the current builder elements
  177. * hierarchical tree, wherever it may be. It actually implements a
  178. * step by step slow copy of the whole tree, leaving out only the
  179. * element referenced by the given id.
  180. */
  181. public function deleteElement($id)
  182. {
  183. $class = get_class($this);
  184. $dest = new $class();
  185. $attributes = get_object_vars($this);
  186. //
  187. // Closure for drilling down on an array
  188. //
  189. $f = function ($array, $id)
  190. {
  191. $ret = array();
  192. foreach ($array as $attributeName => $attribute) {
  193. if (is_object($attribute) && $attribute->getInternalId() == $id) {
  194. continue;
  195. } elseif (is_array($attribute)) {
  196. array_push($ret, call_user_func(__FUNCTION__, $attribute, $id));
  197. } elseif (is_object($attribute)) {
  198. array_push($ret, $attribute->deleteElement($id));
  199. } else {
  200. array_push($ret, $attribute);
  201. }
  202. }
  203. return $ret;
  204. };
  205. //
  206. // This foreach processes this element's attributes and delegates
  207. // work on whatever is found:
  208. // . an array attribute is delivered to the above closure
  209. // . an object is delivered recursively to this method again
  210. // . a simple type is copied directly
  211. //
  212. foreach ($attributes as $attributeName => $attribute) {
  213. if (is_object($attribute) && $attribute->getInternalId() == $id) {
  214. continue;
  215. } elseif (is_array($attribute)) {
  216. $dest->$attributeName = $f($attribute, $id);
  217. } elseif (is_object($attribute)) {
  218. $dest->$attributeName = $attribute->deleteElement($id);
  219. } else {
  220. $dest->$attributeName = $attribute;
  221. }
  222. }
  223. return $dest;
  224. }
  225. public function sortElements(Array $orderedIds, Array &$elements = array())
  226. {
  227. $s = function (Array $unorderedElements, Array $orderedIds, Array &$orderedElements)
  228. {
  229. $orderedElements = array();
  230. foreach ($orderedIds as $id) {
  231. foreach ($unorderedElements as $element) {
  232. if ($element->getInternalId() == $id) {
  233. $orderedElements[] = $element;
  234. $element = null;
  235. unset($element);
  236. break;
  237. }
  238. }
  239. }
  240. };
  241. $id = $orderedIds[0];
  242. if ($id == $this->_internalId) {
  243. return $this;
  244. }
  245. $internalId = null;
  246. $attributes = get_object_vars($this);
  247. foreach ($attributes as $name => $attribute) {
  248. if (is_object($attribute)) { // Go to the next nested level
  249. $internalId = $attribute->sortElements($orderedIds, $elements);
  250. if (!empty($elements)) {
  251. return $elements;
  252. } elseif (!empty($internalId)) {
  253. $s($attributes, $orderedIds, $elements);
  254. //return $elements;
  255. }
  256. } elseif (is_array($attribute)) { // Tear down the array
  257. //
  258. // Tears down an array until an element or the end is found
  259. //
  260. $f = function ($array, $id, &$elements) use ($orderedIds, $s)
  261. {
  262. $internalId = null;
  263. foreach ($array as $attribute) {
  264. if (is_object($attribute)) {
  265. $internalId = $attribute->sortElements($orderedIds, $elements); // Go down one level
  266. if (!empty($elements)) {
  267. return $elements;
  268. } elseif (!empty($internalId)) {
  269. $s($array, $orderedIds, $elements);
  270. //return $elements;
  271. }
  272. } elseif (is_array($attribute)) {
  273. $internalId = call_user_func(__FUNCTION__, $attribute, $id, $elements); // Tear down the array
  274. }
  275. }
  276. };
  277. $internalId = $f($attribute, $id, $elements);
  278. }
  279. }
  280. return $elements;
  281. }
  282. /**
  283. * Abstract the external lib call, so that we only have to require it
  284. * here. It will still get called from each builder element, but the
  285. * actual require code is only written once here.
  286. */
  287. public function toHtml()
  288. {
  289. require_once 'lib/lib.htmlgen.php';
  290. }
  291. /**
  292. * Utility method for centralizing the Fail On Error attribute, that
  293. * will be pretty much used by every build element.
  294. */
  295. public function toHtmlFailOnError()
  296. {
  297. $o = $this;
  298. h::div(array('class' => 'label tooltip',
  299. 'title' => 'Check this if you wish the integration'
  300. . ' builder to immediately stop when this task generates an error.'), 'Fail on error?');
  301. h::div(array('class' => 'checkboxContainer'), function() use ($o) {
  302. $params = array('class' => 'checkbox', 'type' => 'checkbox', 'name' => 'failOnError',);
  303. if ($o->getFailOnError()) {
  304. $params['checked'] = 'checked';
  305. }
  306. h::input($params);
  307. });
  308. }
  309. }