/lib/outlet/0.7/OutletConfig.php

https://github.com/thenobody/mkLogic · PHP · 433 lines · 301 code · 75 blank · 57 comment · 54 complexity · 1ddf7c75ea814381940b1fee07f3e996 MD5 · raw file

  1. <?php
  2. class OutletConfig {
  3. public $conf;
  4. private $con;
  5. private $entities;
  6. function __construct (array $conf) {
  7. // validate config
  8. if (!isset($conf['connection'])) throw new OutletConfigException('Element [connection] not found in configuration');
  9. if (!isset($conf['connection']['dsn'])) throw new OutletConfigException('Element [connection][dsn] not found in configuration');
  10. if (!isset($conf['connection']['dialect'])) throw new OutletConfigException('Element [connection][dialect] not found in configuration');
  11. if (!isset($conf['classes'])) throw new OutletConfigException('Element [classes] missing in configuration');
  12. $this->conf = $conf;
  13. }
  14. /**
  15. * @return OutletConnection
  16. */
  17. function getConnection () {
  18. if (!$this->con) {
  19. $conn = $this->conf['connection'];
  20. $dsn = $conn['dsn'];
  21. $driver = substr($dsn, 0, strpos($dsn, ':'));
  22. $pdo = new PDO($conn['dsn'], @$conn['username'], @$conn['password']);
  23. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  24. $this->con = new OutletConnection($pdo, $driver, $conn['dialect']);
  25. }
  26. return $this->con;
  27. }
  28. /**
  29. * @return array
  30. */
  31. function getEntities () {
  32. if (is_null($this->entities)) {
  33. $this->entities = array();
  34. foreach ($this->conf['classes'] as $key=>$cls) {
  35. $this->entities[$key] = new OutletEntityConfig($this, $key, $cls);
  36. }
  37. }
  38. return $this->entities;
  39. }
  40. /**
  41. * @param string $cls
  42. * @return OutletEntityConfig
  43. */
  44. function getEntity ($cls) {
  45. if (is_null($this->entities)) $this->getEntities();
  46. if (!isset($this->entities[$cls])) throw new OutletException('Entity ['.$cls.'] has not been defined in the configuration');
  47. return $this->entities[$cls];
  48. }
  49. function useGettersAndSetters () {
  50. return isset($this->conf['useGettersAndSetters']) ? $this->conf['useGettersAndSetters'] : false;
  51. }
  52. }
  53. class OutletEntityConfig {
  54. private $data;
  55. private $config;
  56. private $clazz;
  57. private $props;
  58. private $associations;
  59. private $sequenceName = '';
  60. private $useGettersAndSetters;
  61. function __construct (OutletConfig $config, $entity, array $conf) {
  62. $this->config = $config;
  63. if (!isset($conf['table'])) throw new OutletConfigException('Mapping for entity ['.$entity.'] is missing element [table]');
  64. if (!isset($conf['props'])) throw new OutletConfigException('Mapping for entity ['.$entity.'] is missing element [props]');
  65. // i need to leave this for for the outletgen script
  66. //if (!class_exists($entity)) throw new OutletConfigException('Class does not exist for mapped entity ['.$entity.']');
  67. // validate that there's a pk
  68. foreach ($conf['props'] as $p=>$f) {
  69. if (@$f[2]['pk']) {
  70. $pk = $p;
  71. break;
  72. }
  73. }
  74. if (!isset($pk)) throw new OutletConfigException("Entity [$entity] must have at least one column defined as a primary key in the configuration");
  75. // save basic data
  76. $this->table = $conf['table'];
  77. $this->clazz = $entity;
  78. $this->props = $conf['props'];
  79. $this->sequenceName = isset($conf['sequenceName']) ? $conf['sequenceName'] : '';
  80. $this->useGettersAndSetters = isset($conf['useGettersAndSetters']) ? $conf['useGettersAndSetters'] : $config->useGettersAndSetters();
  81. // Adjusts sequence name for postgres if it is not specified
  82. if (($config->getConnection()->getDialect() == 'pgsql') && ($this->sequenceName == ''))
  83. {
  84. foreach ($this->props as $key=>$d) {
  85. // Property needs to be primary key and auto increment
  86. if ((isset($d[2]['pk']) && $d[2]['pk']) && (isset($d[2]['autoIncrement']) && $d[2]['autoIncrement'])){
  87. // default name for sequence = {table}_{column}_seq
  88. $this->sequenceName = $this->table.'_'.$d[0].'_seq';
  89. break;
  90. }
  91. }
  92. }
  93. }
  94. function getClass () {
  95. return $this->clazz;
  96. }
  97. function getTable () {
  98. return $this->table;
  99. }
  100. /**
  101. * @return array
  102. */
  103. function getProperties () {
  104. return $this->props;
  105. }
  106. /**
  107. * @return array Primary key columns for this entity
  108. */
  109. function getPkColumns () {
  110. // get the pk column in order to check the map
  111. $pk = array();
  112. foreach ($this->props as $key=>$d) {
  113. if (isset($d[2]['pk']) && $d[2]['pk']) $pk[] = $d[0];
  114. }
  115. return $pk;
  116. }
  117. /**
  118. * @return array OutletAssociationConfig collection
  119. */
  120. function getAssociations () {
  121. if (is_null($this->associations)) {
  122. $this->associations = array();
  123. $conf = $this->config->conf['classes'][$this->clazz];
  124. if (isset($conf['associations'])) {
  125. foreach ($conf['associations'] as $assoc) {
  126. switch ($assoc[0]) {
  127. case 'one-to-many':
  128. $a = new OutletOneToManyConfig($this->config, $this->getClass(), $assoc[1], $assoc[2]);
  129. break;
  130. case 'many-to-one':
  131. $a = new OutletManyToOneConfig($this->config, $this->getClass(), $assoc[1], $assoc[2]);
  132. break;
  133. case 'many-to-many':
  134. $a = new OutletManyToManyConfig($this->config, $this->getClass(), $assoc[1], $assoc[2]);
  135. break;
  136. case 'one-to-one':
  137. $a = new OutletOneToOneConfig($this->config, $this->getClass(), $assoc[1], $assoc[2]);
  138. break;
  139. default:
  140. $a = new OutletAssociationConfig($this->config, $assoc[0], $this->getClass(), $assoc[1], $assoc[2]);
  141. }
  142. $this->associations[] = $a;
  143. }
  144. }
  145. }
  146. return $this->associations;
  147. }
  148. /**
  149. * @param string $name
  150. * @return OutletAssociationConfig
  151. */
  152. function getAssociation ($name) {
  153. foreach ($this->getAssociations() as $assoc) {
  154. //$assoc = new OutletAssociationConfig();
  155. if ($assoc->getForeignName() == $name) return $assoc;
  156. }
  157. }
  158. function getPkFields () {
  159. $fields = array();
  160. foreach ($this->props as $prop=>$def) {
  161. if (@$def[2]['pk']) $fields[] = $prop;
  162. }
  163. return $fields;
  164. }
  165. function getSequenceName(){
  166. return $this->sequenceName;
  167. }
  168. function useGettersAndSetters () {
  169. return $this->useGettersAndSetters;
  170. }
  171. }
  172. abstract class OutletAssociationConfig {
  173. protected $config;
  174. protected $local;
  175. protected $pk;
  176. protected $foreign;
  177. protected $type;
  178. protected $key;
  179. protected $localUseGettersAndSetters;
  180. protected $foreignUseGettersAndSetters;
  181. /**
  182. * @param OutletConfig $config
  183. * @param string $type Type of association: one-to-many, many-to-one, etc
  184. * @param string $local Name of the entity where the association is defined
  185. * @param string $foreign Name of the entity that is referenced by the association
  186. * @param array $options
  187. */
  188. function __construct (OutletConfig $config, $local, $foreign, array $options) {
  189. $this->config = $config;
  190. $this->local = $local;
  191. $this->foreign = $foreign;
  192. $this->options = $options;
  193. $this->localUseGettersAndSetters = $this->config->getEntity($local)->useGettersAndSetters();
  194. $this->foreignUseGettersAndSetters = $this->config->getEntity($foreign)->useGettersAndSetters();
  195. }
  196. function getForeignUseGettersAndSetters(){
  197. return $this->foreignUseGettersAndSetters;
  198. }
  199. function getLocalUseGettersAndSetters(){
  200. return $this->localUseGettersAndSetters;
  201. }
  202. function getLocal () {
  203. return $this->local;
  204. }
  205. function getType () {
  206. return $this->type;
  207. }
  208. function isOptional () {
  209. return (isset($this->options['optional']) && $this->options['optional']);
  210. }
  211. /**
  212. * @return string Foreign entity name
  213. */
  214. function getForeign () {
  215. return $this->foreign;
  216. }
  217. function getGetter () {
  218. switch ($this->type) {
  219. case 'many-to-one':
  220. case 'one-to-one':
  221. return "get".$this->getForeignName();
  222. default:
  223. return "get".$this->getForeignPlural();
  224. }
  225. }
  226. /**
  227. * @return string
  228. */
  229. function getSetter () {
  230. switch ($this->type) {
  231. case 'many-to-one':
  232. case 'one-to-one':
  233. return "set".$this->getForeignName();
  234. default:
  235. return "set".$this->getForeignPlural();
  236. }
  237. }
  238. /**
  239. * @return string Name of the association
  240. */
  241. function getForeignName () {
  242. if (isset($this->options['name'])) {
  243. $name = $this->options['name'];
  244. } else {
  245. $name = $this->foreign;
  246. }
  247. return $name;
  248. }
  249. function getForeignPlural () {
  250. // if this association has a name
  251. if (isset($this->options['name'])) {
  252. // if this association has a plural, use that
  253. // else use the name plus an 's'
  254. if (isset($this->options['plural'])) $plural = $this->options['plural'];
  255. else $plural = $this->options['name'].'s';
  256. // else check the entity definition
  257. } else {
  258. if (!isset($this->config->conf['classes'][$this->foreign]))
  259. throw new OutletConfigException("Entity [{$this->foreign}] not found in configuration");
  260. $foreign_def = $this->config->conf['classes'][$this->foreign];
  261. // if there's a plural defined at the foreign entity
  262. // else use the entity plus an 's'
  263. if (isset($foreign_def['plural'])) $plural = $foreign_def['plural'];
  264. else $plural = $this->foreign.'s';
  265. }
  266. return $plural;
  267. }
  268. }
  269. class OutletOneToManyConfig extends OutletAssociationConfig {
  270. protected $type = 'one-to-many';
  271. public function __construct (OutletConfig $config, $local, $foreign, array $options) {
  272. // one-to-many requires a key
  273. if (!isset($options['key'])) throw new OutletConfigException("Entity $local, association with $foreign: You must specify a 'key' when defining a one-to-many relationship");
  274. parent::__construct($config, $local, $foreign, $options);
  275. }
  276. public function getKey() {
  277. return $this->options['key'];
  278. }
  279. function getRefKey () {
  280. if (isset($this->options['refKey'])) {
  281. return $this->options['refKey'];
  282. } else {
  283. return current($this->config->getEntity($this->local)->getPkFields());
  284. }
  285. }
  286. }
  287. class OutletManyToOneConfig extends OutletAssociationConfig {
  288. protected $type = 'many-to-one';
  289. public function __construct (OutletConfig $config, $local, $foreign, array $options) {
  290. // many-to-one requires a key
  291. if (!isset($options['key'])) throw new OutletConfigException("Entity $local, association with $foreign: You must specify a 'key' when defining a many-to-one relationship");
  292. parent::__construct($config, $local, $foreign, $options);
  293. }
  294. public function getKey() {
  295. return $this->options['key'];
  296. }
  297. function getRefKey () {
  298. if (isset($this->options['refKey'])) {
  299. return $this->options['refKey'];
  300. } else {
  301. return current($this->config->getEntity($this->foreign)->getPkFields());
  302. }
  303. }
  304. }
  305. class OutletOneToOneConfig extends OutletAssociationConfig {
  306. protected $type = 'one-to-one';
  307. public function __construct (OutletConfig $config, $local, $foreign, array $options) {
  308. if (!isset($options['key'])) throw new OutletConfigException("Entity $local, association with $foreign: You must specify a 'key' when defining a one-to-one relationship");
  309. parent::__construct($config, $local, $foreign, $options);
  310. }
  311. public function getKey () {
  312. return $this->options['key'];
  313. }
  314. function getRefKey () {
  315. if (isset($this->options['refKey'])) {
  316. return $this->options['refKey'];
  317. } else {
  318. return current($this->config->getEntity($this->local)->getPkFields());
  319. }
  320. }
  321. }
  322. class OutletManyToManyConfig extends OutletAssociationConfig {
  323. protected $type = 'many-to-many';
  324. protected $table;
  325. protected $tableKeyLocal;
  326. protected $tableKeyForeign;
  327. public function __construct (OutletConfig $config, $local, $foreign, array $options) {
  328. if (!isset($options['table'])) throw new OutletConfigException("Entity $local, association with $foreign: You must specify a table when defining a many-to-many relationship");
  329. $this->table = $options['table'];
  330. $this->tableKeyLocal = $options['tableKeyLocal'];
  331. $this->tableKeyForeign = $options['tableKeyForeign'];
  332. parent::__construct($config, $local, $foreign, $options);
  333. }
  334. public function getTableKeyLocal () {
  335. return $this->tableKeyLocal;
  336. }
  337. public function getTableKeyForeign () {
  338. return $this->tableKeyForeign;
  339. }
  340. public function getLinkingTable () {
  341. return $this->table;
  342. }
  343. function getKey () {
  344. if (isset($this->options['key'])) {
  345. return $this->options['key'];
  346. } else {
  347. return current($this->config->getEntity($this->foreign)->getPkFields());
  348. }
  349. }
  350. function getRefKey () {
  351. if (isset($this->options['refKey'])) {
  352. return $this->options['refKey'];
  353. } else {
  354. return current($this->config->getEntity($this->local)->getPkFields());
  355. }
  356. }
  357. }
  358. class OutletConfigException extends OutletException {}