PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/library/Shanty/Mongo.php

https://bitbucket.org/ilyabazhenov/speakplace
PHP | 344 lines | 173 code | 55 blank | 116 comment | 31 complexity | 6c1cb19c8a16d724ba3354f853613d3b MD5 | raw file
  1. <?php
  2. require_once 'Shanty/Mongo/Validate/Array.php';
  3. require_once 'Shanty/Mongo/Validate/Class.php';
  4. require_once 'Shanty/Mongo/Validate/StubTrue.php';
  5. require_once 'Shanty/Mongo/Connection/Group.php';
  6. /**
  7. * @category Shanty
  8. * @package Shanty_Mongo
  9. * @copyright Shanty Tech Pty Ltd
  10. * @license New BSD License
  11. * @author Coen Hyde
  12. */
  13. class Shanty_Mongo
  14. {
  15. protected static $_connectionGroups = array();
  16. protected static $_requirements = array();
  17. protected static $_requirementCreators = array();
  18. protected static $_validOperations = array('$set', '$unset', '$push', '$pushAll', '$pull', '$pullAll', '$addToSet', '$pop', '$inc');
  19. protected static $_initialised = false;
  20. /**
  21. * Initialise Shanty_Mongo. In particular all the requirements.
  22. */
  23. public static function init()
  24. {
  25. // If requirements are not empty then we have already initialised requirements
  26. if (static::$_initialised) return;
  27. // Custom validators
  28. static::storeRequirement('Validator:Array', new Shanty_Mongo_Validate_Array());
  29. static::storeRequirement('Validator:MongoId', new Shanty_Mongo_Validate_Class('MongoId'));
  30. static::storeRequirement('Validator:MongoDate', new Shanty_Mongo_Validate_Class('MongoDate'));
  31. static::storeRequirement('Document', new Shanty_Mongo_Validate_Class('Shanty_Mongo_Document'));
  32. static::storeRequirement('DocumentSet', new Shanty_Mongo_Validate_Class('Shanty_Mongo_DocumentSet'));
  33. // Stubs
  34. static::storeRequirement('Required', new Shanty_Mongo_Validate_StubTrue());
  35. static::storeRequirement('AsReference', new Shanty_Mongo_Validate_StubTrue());
  36. // Requirement creator for validators
  37. static::storeRequirementCreator('/^Validator:([A-Za-z]+[\w\-:]*)$/', function($data, $options = null) {
  38. $instanceClass = 'Zend_Validate_'.$data[1];
  39. if (!class_exists($instanceClass)) return null;
  40. if (!is_null($options)) $validator = new $instanceClass($options);
  41. else $validator = new $instanceClass();
  42. if (!($validator instanceof Zend_Validate_Interface)) return null;
  43. return $validator;
  44. });
  45. // Requirement creator for filters
  46. static::storeRequirementCreator('/^Filter:([A-Za-z]+[\w\-:]*)$/', function($data, $options = null) {
  47. $instanceClass = 'Zend_Filter_'.$data[1];
  48. if (!class_exists($instanceClass)) return null;
  49. if (!is_null($options)) $validator = new $instanceClass($options);
  50. else $validator = new $instanceClass();
  51. if (!($validator instanceof Zend_Filter_Interface)) return null;
  52. return $validator;
  53. });
  54. // Creates requirements to match classes
  55. $classValidator = function($data) {
  56. if (!class_exists($data[1])) return null;
  57. return new Shanty_Mongo_Validate_Class($data[1]);
  58. };
  59. static::storeRequirementCreator('/^Document:([A-Za-z]+[\w\-]*)$/', $classValidator);
  60. static::storeRequirementCreator('/^DocumentSet:([A-Za-z]+[\w\-]*)$/', $classValidator);
  61. static::$_initialised = true;
  62. }
  63. /**
  64. * Add connections Shanty Mongo
  65. *
  66. * @param array $options
  67. */
  68. public static function addConnections($options)
  69. {
  70. if ($options instanceof Zend_Config) {
  71. $options = $options->toArray();
  72. }
  73. $blurbs = array('host', 'master', 'masters', 'slaves', 'slave', 'hosts');
  74. $intersection = array_intersect(array_keys($options), $blurbs);
  75. $connectionGroups = array();
  76. if (!empty($intersection)) $connectionGroups['default'] = $options;
  77. else $connectionGroups = $options;
  78. foreach ($connectionGroups as $connectionGroupName => $connectionGroupOptions) {
  79. static::getConnectionGroup($connectionGroupName)->addConnections($connectionGroupOptions);
  80. }
  81. }
  82. /**
  83. * Get the requirement matching the name provided
  84. *
  85. * @param $name String Name of requirement
  86. * @return mixed
  87. **/
  88. public static function retrieveRequirement($name, $options = null)
  89. {
  90. // Requirement is already initialised return it
  91. if (array_key_exists($name, static::$_requirements)) {
  92. // If requirement does not have options, returned cached instance
  93. if (is_null($options)) return static::$_requirements[$name];
  94. $requirementClass = get_class(static::$_requirements[$name]);
  95. return new $requirementClass($options);
  96. }
  97. // Attempt to create requirement
  98. if (!$requirement = static::createRequirement($name, $options)) {
  99. require_once 'Shanty/Mongo/Exception.php';
  100. throw new Shanty_Mongo_Exception("No requirement exists for '{$name}'");
  101. }
  102. // Requirement found. Store it for later use
  103. if (!is_null($options)) {
  104. static::storeRequirement($name, $requirement);
  105. }
  106. return $requirement;
  107. }
  108. /**
  109. * Add requirements to use in validation of document properties
  110. *
  111. * @param $name String Name of requirement
  112. * @param $requirement mixed
  113. **/
  114. public static function storeRequirement($name, $requirement)
  115. {
  116. // Ensure $name is a string
  117. $name = (string) $name;
  118. static::$_requirements[$name] = $requirement;
  119. }
  120. /**
  121. * Add a creator of requirements
  122. *
  123. * @param String Regex to match this requirement producer
  124. * @param Closure Function to create requirement
  125. **/
  126. public static function storeRequirementCreator($regex, Closure $function)
  127. {
  128. static::$_requirementCreators[$regex] = $function;
  129. }
  130. /**
  131. * Create a requirement
  132. *
  133. * @param $name String Name of requirement
  134. * @return mixed
  135. **/
  136. public static function createRequirement($name, $options = null)
  137. {
  138. // Match requirement name against regex's
  139. $requirements = array_reverse(static::$_requirementCreators);
  140. foreach ($requirements as $regex => $function) {
  141. $matches = array();
  142. preg_match($regex, $name, $matches);
  143. if (!empty($matches)) {
  144. return $function($matches, $options);
  145. }
  146. }
  147. return null;
  148. }
  149. /**
  150. * Remove all requirements
  151. */
  152. public static function removeRequirements()
  153. {
  154. static::$_requirements = array();
  155. }
  156. /**
  157. * Remove all requirement creators
  158. */
  159. public static function removeRequirementCreators()
  160. {
  161. static::$_requirementCreators = array();
  162. }
  163. /**
  164. * Deterimine if an operation is valid
  165. *
  166. * @param string $operation
  167. */
  168. public static function isValidOperation($operation)
  169. {
  170. return in_array($operation, static::$_validOperations);
  171. }
  172. /**
  173. * Determine if a connection group exists
  174. *
  175. * @param string $name The name of the connection group
  176. */
  177. public static function hasConnectionGroup($name)
  178. {
  179. return array_key_exists($name, static::$_connectionGroups);
  180. }
  181. /**
  182. * Set a connection group
  183. *
  184. * @param string $name
  185. * @param Shanty_Mongo_Connection_Group $connectionGroup
  186. */
  187. public static function setConnectionGroup($name, Shanty_Mongo_Connection_Group $connectionGroup)
  188. {
  189. static::$_connectionGroups[$name] = $connectionGroup;
  190. }
  191. /**
  192. * Get a connection group. If it doesn't already exist, create it
  193. *
  194. * @param string $name The name of the connection group
  195. * @return Shanty_Mongo_Connection_Group
  196. */
  197. public static function getConnectionGroup($name)
  198. {
  199. if (!static::hasConnectionGroup($name)) {
  200. static::setConnectionGroup($name, new Shanty_Mongo_Connection_Group());
  201. }
  202. return static::$_connectionGroups[$name];
  203. }
  204. /**
  205. * Get a list of all connection groups
  206. *
  207. * @return array
  208. */
  209. public static function getConnectionGroups()
  210. {
  211. return static::$_connectionGroups;
  212. }
  213. /**
  214. * Remove all connection groups
  215. */
  216. public static function removeConnectionGroups()
  217. {
  218. static::$_connectionGroups = array();
  219. }
  220. /**
  221. * Add a connection to a master server
  222. *
  223. * @param Shanty_Mongo_Connection $connection
  224. * @param int $weight
  225. */
  226. public static function addMaster(Shanty_Mongo_Connection $connection, $weight = 1, $connectionGroup = 'default')
  227. {
  228. static::getConnectionGroup($connectionGroup)->addMaster($connection, $weight);
  229. }
  230. /**
  231. * Add a connection to a slaver server
  232. *
  233. * @param $connection
  234. * @param $weight
  235. */
  236. public static function addSlave(Shanty_Mongo_Connection $connection, $weight = 1, $connectionGroup = 'default')
  237. {
  238. static::getConnectionGroup($connectionGroup)->addSlave($connection, $weight);
  239. }
  240. /**
  241. * Get a write connection
  242. *
  243. * @param string $connectionGroupName The connection group name
  244. * @return Shanty_Mongo_Connection
  245. */
  246. public static function getWriteConnection($connectionGroupName = 'default')
  247. {
  248. $connectionGroup = static::getConnectionGroup($connectionGroupName);
  249. if ($connectionGroupName == 'default' && count($connectionGroup->getMasters()) === 0) {
  250. // Add a connection to localhost if no connections currently exist for the default connection group
  251. $connectionGroup->addMaster(new Shanty_Mongo_Connection('127.0.0.1'));
  252. }
  253. if (!$connection = $connectionGroup->getWriteConnection($connectionGroupName)) {
  254. require_once 'Shanty/Mongo/Exception.php';
  255. throw new Shanty_Mongo_Exception("No write connection available for the '{$connectionGroupName}' connection group");
  256. }
  257. return $connection;
  258. }
  259. /**
  260. * Get a read connection
  261. *
  262. * @param string $connectionGroupName The connection group name
  263. * @return Shanty_Mongo_Connection
  264. */
  265. public static function getReadConnection($connectionGroupName = 'default')
  266. {
  267. $connectionGroup = static::getConnectionGroup($connectionGroupName);
  268. if ($connectionGroupName == 'default' && count($connectionGroup->getSlaves()) === 0 && count($connectionGroup->getMasters()) === 0) {
  269. // Add a connection to localhost if no connections currently exist for the default connection group
  270. $connectionGroup->addMaster(new Shanty_Mongo_Connection('127.0.0.1'));
  271. }
  272. if (!$connection = $connectionGroup->getReadConnection($connectionGroupName)) {
  273. require_once 'Shanty/Mongo/Exception.php';
  274. throw new Shanty_Mongo_Exception("No read connection available for the '{$connectionGroupName}' connection group");
  275. }
  276. return $connection;
  277. }
  278. /**
  279. * Return Shanty_Mongo to pre-init status
  280. */
  281. public static function makeClean()
  282. {
  283. static::removeConnectionGroups();
  284. static::removeRequirements();
  285. static::removeRequirementCreators();
  286. static::$_initialised = false;
  287. }
  288. }
  289. Shanty_Mongo::init();