Context.php

Provides the Provision_Context class.

Classes

Namesort descending Description
Provision_Context Base context class.

File

Provision/Context.php
View source
  1. <?php
  2. /**
  3. * @file
  4. * Provides the Provision_Context class.
  5. */
  6. /**
  7. * Base context class.
  8. *
  9. * Contains magic getter/setter functions
  10. */
  11. class Provision_Context {
  12. /**
  13. * Name for saving aliases and referencing.
  14. */
  15. public $name = NULL;
  16. /**
  17. * 'server', 'platform', or 'site'.
  18. */
  19. public $type = NULL;
  20. /**
  21. * Properties that will be persisted by provision-save. Access as object
  22. * members, $evironment->property_name. __get() and __set handle this. In
  23. * init(), set defaults with setProperty().
  24. */
  25. protected $properties = array();
  26. /**
  27. * Keeps track of properites that are names of Provision_Context objects.
  28. * Set with is_oid().
  29. */
  30. protected $oid_map = array();
  31. protected $service_subs = array();
  32. protected $parent_key = NULL;
  33. /**
  34. * Retrieve value from $properties array if property does not exist in class
  35. * proper. Properties that refer to Provision_Context objects will be run
  36. * through d(), see is_oid().
  37. *
  38. * TODO: consider returning a reference to the value, so we can do things like:
  39. * `$this->options['option'] = 'value'` and it will correctly set it in the
  40. * drush context cache.
  41. */
  42. function __get($name) {
  43. if ($name == 'options') {
  44. return array_merge(provision_sitealias_get_record($this->name), array_filter(drush_get_context('stdin')), array_filter(drush_get_context('options')), array_filter(drush_get_context('cli')));
  45. }
  46. if (array_key_exists($name, $this->properties)) {
  47. if (isset($this->oid_map[$name]) && !empty($this->properties[$name])) {
  48. $service = d($this->properties[$name], FALSE, FALSE);
  49. if (!is_null($service)) {
  50. return $service;
  51. }
  52. }
  53. else {
  54. return $this->properties[$name];
  55. }
  56. }
  57. }
  58. /**
  59. * Specify that a property contains a named context.
  60. */
  61. function is_oid($name) {
  62. $this->oid_map[$name] = TRUE;
  63. }
  64. /**
  65. * Store value in properties array if the property does not exist in class proper.
  66. */
  67. function __set($name, $value) {
  68. if (!property_exists($this, $name)) {
  69. $this->properties[$name] = $value;
  70. }
  71. else {
  72. $this->$name = $value;
  73. }
  74. }
  75. /**
  76. * Check the properties array if the property does not exist in the class proper.
  77. */
  78. function __isset($name) {
  79. return isset($this->properties[$name]) || property_exists($this, $name);
  80. }
  81. /**
  82. * Remove the value from the properties array if the property does not exist
  83. * in the class proper.
  84. */
  85. function __unset($name) {
  86. if (isset($this->properties[$name])) {
  87. unset($this->properties[$name]);
  88. }
  89. elseif (property_exists($this, $name)) {
  90. unset($this->$name);
  91. }
  92. }
  93. /**
  94. * Implement the __call magic method.
  95. *
  96. * This implementation is really simple. It simply return NULL if the
  97. * method doesn't exist.
  98. *
  99. * This is used so that we can create methods for drush commands, and
  100. * can fail safely.
  101. */
  102. function __call($name, $args) {
  103. return $this->method_invoke($name, $args);
  104. }
  105. /**
  106. * Execute a method on the object and all of it's associated
  107. * services.
  108. */
  109. function method_invoke($func, $args = array(), $services = TRUE) {
  110. provision::method_invoke($this, $func, $args);
  111. // Services will be invoked regardless of the existence of a
  112. // implementation in the context class.
  113. if ($services) {
  114. $this->services_invoke($func, $args);
  115. }
  116. }
  117. /**
  118. * Execute the method for the current object type.
  119. *
  120. * This function is used to avoid having to conditionally
  121. * check the context objects type to execute the correct code.
  122. *
  123. * This will generate a function call like : $method_$type,
  124. * ie: $this->init_server().
  125. *
  126. * Additionally it will dispatch this function call to
  127. * all the currently enabled services.
  128. */
  129. function type_invoke($name, $args = array()) {
  130. $this->method_invoke("{$name}_{$this->type}");
  131. }
  132. /**
  133. * Allow a server to plug into a drush command that has been called.
  134. *
  135. * This method provides a general case for extending drush commands.
  136. * This allows the developer to not have to conditionally check the
  137. * context object type in all his methods, and reduces the need
  138. * to define drush_hook_$command methods for a lot of cases.
  139. *
  140. * This will generate a function call like : $method_$type_cmd.
  141. */
  142. function command_invoke($command, $args = array()) {
  143. $this->method_invoke("{$command}_{$this->type}_cmd");
  144. }
  145. /**
  146. * Constructor for the context.
  147. */
  148. function __construct($name) {
  149. $this->name = $name;
  150. }
  151. /**
  152. * Init stub function.
  153. */
  154. function init() {
  155. preg_match("/^Provision_Context_(.*)$/", get_class($this), $matches);
  156. $this->type = $matches[1];
  157. $this->setProperty('context_type', $this->type);
  158. // Set up the parent of this context object.
  159. if (!is_null($this->parent_key)) {
  160. $this->setProperty($this->parent_key);
  161. $this->is_oid($this->parent_key);
  162. }
  163. // $this->server is always @server_master
  164. $this->server = '@server_master';
  165. $this->is_oid('server');
  166. // Set up subscriptions for the available services.
  167. $service_list = drush_command_invoke_all('provision_services');
  168. foreach ($service_list as $service => $default) {
  169. $class = "Provision_Service_{$service}";
  170. $func = "subscribe_{$this->type}";
  171. if (method_exists($class, $func)) {
  172. call_user_func(array($class, $func), $this);
  173. }
  174. }
  175. return true;
  176. }
  177. /**
  178. * Check the $options property for a field, saving to the properties array.
  179. */
  180. function setProperty($field, $default = NULL, $array = FALSE, $force = FALSE) {
  181. // If the options already has the $field...
  182. if (isset($this->options[$field])) {
  183. // If the options property is null, or property is being forced, used default value.
  184. if ($this->options[$field] === 'null' || $force) {
  185. $this->$field = $default;
  186. }
  187. // If options property is supposed to be an array but has comma separated values, explode it.
  188. elseif ($array && !is_array($this->options[$field])) {
  189. $this->$field = explode(',', $this->options[$field]);
  190. }
  191. // Otherwise use options array value for the $field property.
  192. else {
  193. $this->$field = $this->options[$field];
  194. }
  195. }
  196. // If the options doesn't have the field, use default value.
  197. else {
  198. $this->$field = $default;
  199. }
  200. }
  201. /**
  202. * Write out this named context to an alias file.
  203. */
  204. function write_alias() {
  205. $config = new Provision_Config_Drushrc_Alias($this->name, $this->properties);
  206. $config->write();
  207. }
  208. /**
  209. * Subscribe a service handler.
  210. *
  211. * All future calls to $this->service($service) will be redirected
  212. * to the context object of #name you specify.
  213. */
  214. function service_subscribe($service, $name) {
  215. $this->service_subs[$service] = $name;
  216. }
  217. /**
  218. * Return a service object for the specific service type.
  219. *
  220. * This will return a specifically subscribed service object when one has
  221. * been registered with service_subscribe, otherwise it will return the value
  222. * specified by the property specified by $this->parent_key.
  223. *
  224. * @param $service
  225. * Service type, such as 'http' or 'db'
  226. * @param $name
  227. * Override service owner with a context name as accepted by d().
  228. *
  229. * @return
  230. * A Provision_Service object.
  231. */
  232. function service($service, $name = NULL) {
  233. if (isset($this->service_subs[$service])) {
  234. return d($this->service_subs[$service])->service($service, ($name) ? $name : $this->name);
  235. }
  236. elseif (!is_null($this->parent_key)) {
  237. return $this->{$this->parent_key}->service($service, ($name) ? $name : $this->name);
  238. }
  239. else {
  240. return new Provision_Service_null($this->name);
  241. }
  242. }
  243. /**
  244. * Call method $callback on each of the context's service objects.
  245. *
  246. * @param $callback
  247. * A Provision_Service method.
  248. * @return
  249. * An array of return values from method implementations.
  250. */
  251. function services_invoke($callback, $args = array()) {
  252. $results = array();
  253. // fetch the merged list of services.
  254. // These may be on different servers entirely.
  255. $services = $this->get_services();
  256. foreach (array_keys($services) as $service) {
  257. $results[$service] = provision::method_invoke($this->service($service), $callback, $args);
  258. }
  259. return $results;
  260. }
  261. /**
  262. * Return the merged list of services and the associated servers supplying them.
  263. *
  264. * This function will check with the parent_key to retrieve any service subscription
  265. * it may have, and will add any additional subscriptions.
  266. *
  267. * Once the call chain reaches the @server_master object, it will provide the fallbacks
  268. * if no subscriptions were available.
  269. */
  270. function get_services() {
  271. $services = array();
  272. if (!is_null($this->parent_key)) {
  273. $services = $this->{$this->parent_key}->get_services();
  274. }
  275. if (sizeof($this->service_subs)) {
  276. foreach ($this->service_subs as $service => $server) {
  277. $services[$service] = $server;
  278. }
  279. }
  280. return $services;
  281. }
  282. /**
  283. * Return context-specific configuration options for help.
  284. *
  285. * @return
  286. * array('option' => 'description')
  287. */
  288. static function option_documentation() {
  289. return array();
  290. }
  291. }