PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/jelix-legacy/dao/jDaoParser.class.php

http://github.com/jelix/jelix
PHP | 462 lines | 245 code | 47 blank | 170 comment | 47 complexity | bbcd078b1c7f88c8de6dd22475efb89b MD5 | raw file
Possible License(s): BSD-3-Clause, JSON, GPL-3.0, LGPL-3.0, LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. * @package jelix
  4. * @subpackage dao
  5. *
  6. * @author GĂ©rald Croes, Laurent Jouanneau
  7. * @contributor Laurent Jouanneau
  8. *
  9. * @copyright 2001-2005 CopixTeam, 2005-2018 Laurent Jouanneau
  10. * This class was get originally from the Copix project (CopixDAODefinitionV1, Copix 2.3dev20050901, http://www.copix.org)
  11. * Few lines of code are still copyrighted 2001-2005 CopixTeam (LGPL licence).
  12. * Initial authors of this Copix class are Gerald Croes and Laurent Jouanneau,
  13. *
  14. * @see http://www.jelix.org
  15. * @licence http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public Licence, see LICENCE file
  16. */
  17. require_once JELIX_LIB_PATH.'dao/jDaoXmlException.class.php';
  18. require_once JELIX_LIB_PATH.'dao/jDaoProperty.class.php';
  19. require_once JELIX_LIB_PATH.'dao/jDaoMethod.class.php';
  20. require_once JELIX_LIB_PATH.'dao/jDaoGenerator.class.php';
  21. /**
  22. * extract data from a dao xml content.
  23. *
  24. * @package jelix
  25. * @subpackage dao
  26. *
  27. * @see jDaoCompiler
  28. */
  29. class jDaoParser
  30. {
  31. /**
  32. * the properties list.
  33. * keys = field code name.
  34. *
  35. * @var jDaoProperty[]
  36. */
  37. private $_properties = array();
  38. /**
  39. * all tables with their properties, and their own fields
  40. * keys = table code name
  41. * values = array()
  42. * 'name'=> table code name, 'realname'=>'real table name',
  43. * 'pk'=> primary keys list
  44. * 'fk'=> foreign keys list
  45. * 'fields'=>array(list of field code name).
  46. *
  47. * @var array[]
  48. */
  49. private $_tables = array();
  50. /**
  51. * primary table code name.
  52. *
  53. * @var string
  54. */
  55. private $_primaryTable = '';
  56. /**
  57. * code name of foreign table with a outer join.
  58. *
  59. * @var array[] list of array(table code name, 0)
  60. */
  61. private $_ojoins = array();
  62. /**
  63. * code name of foreign table with a inner join.
  64. *
  65. * @var string[] list of table code name
  66. */
  67. private $_ijoins = array();
  68. /**
  69. * @var jDaoMethod[]
  70. */
  71. private $_methods = array();
  72. /**
  73. * list of main events to sent.
  74. */
  75. private $_eventList = array();
  76. public $hasOnlyPrimaryKeys = false;
  77. /**
  78. * selector of the user record class.
  79. *
  80. * @var jSelectorDaoRecord
  81. */
  82. private $_userRecord;
  83. /**
  84. * selector of the imported dao.
  85. *
  86. * @var jSelectorDao[]
  87. */
  88. private $_importedDao;
  89. /**
  90. * @var jSelectorDao
  91. */
  92. public $selector;
  93. /**
  94. * Constructor.
  95. *
  96. * @param jSelectorDao $selector the selector of the DAO file
  97. */
  98. public function __construct(jSelectorDao $selector)
  99. {
  100. $this->selector = $selector;
  101. }
  102. /**
  103. * parse a dao xml content.
  104. *
  105. * @param SimpleXmlElement $xml
  106. * @param jDbTools $tools
  107. * @param int $debug for debug only 0:parse all, 1:parse only datasource+record, 2;parse only datasource
  108. */
  109. public function parse($xml, $tools)
  110. {
  111. $this->import($xml, $tools);
  112. $this->parseDatasource($xml);
  113. $this->parseRecord($xml, $tools);
  114. $this->parseFactory($xml);
  115. }
  116. protected function import($xml, $tools)
  117. {
  118. if (isset($xml['import'])) {
  119. $import = (string) $xml['import'];
  120. jApp::pushCurrentModule($this->selector->module);
  121. // Keep the same driver as current used
  122. $importSel = new jSelectorDaoDb($import, $this->selector->driver, $this->selector->dbType);
  123. jApp::popCurrentModule();
  124. $doc = new DOMDocument();
  125. if (!$doc->load($importSel->getPath())) {
  126. throw new jException('jelix~daoxml.file.unknown', $importSel->getPath());
  127. }
  128. $parser = new jDaoParser($importSel);
  129. $parser->parse(simplexml_import_dom($doc), $tools);
  130. $this->_properties = $parser->getProperties();
  131. $this->_tables = $parser->getTables();
  132. $this->_primaryTable = $parser->getPrimaryTable();
  133. $this->_methods = $parser->getMethods();
  134. $this->_ojoins = $parser->getOuterJoins();
  135. $this->_ijoins = $parser->getInnerJoins();
  136. $this->_eventList = $parser->getEvents();
  137. $this->_userRecord = $parser->getUserRecord();
  138. $this->_importedDao = $parser->getImportedDao();
  139. $this->hasOnlyPrimaryKeys = $parser->hasOnlyPrimaryKeys;
  140. if ($this->_importedDao) {
  141. $this->_importedDao[] = $importSel;
  142. } else {
  143. $this->_importedDao = array($importSel);
  144. }
  145. }
  146. }
  147. protected function parseDatasource($xml)
  148. {
  149. // -- tables
  150. if (isset($xml->datasources, $xml->datasources[0]->primarytable)) {
  151. $previousTables = $this->_tables;
  152. // erase table definitions (in the case where the dao imports an other one)
  153. $this->_tables = array();
  154. $this->_ijoins = array();
  155. $this->_ojoins = array();
  156. $t = $this->_parseTable(0, $xml->datasources[0]->primarytable[0]);
  157. $this->_primaryTable = $t['name'];
  158. if (isset($previousTables[$t['name']])) {
  159. $this->_tables[$t['name']]['fields'] = $previousTables[$t['name']]['fields'];
  160. }
  161. if (isset($xml->datasources[0]->primarytable[1])) {
  162. throw new jDaoXmlException($this->selector, 'table.two.many');
  163. }
  164. foreach ($xml->datasources[0]->foreigntable as $table) {
  165. $t = $this->_parseTable(1, $table);
  166. if (isset($previousTables[$t['name']])) {
  167. $this->_tables[$t['name']]['fields'] = $previousTables[$t['name']]['fields'];
  168. }
  169. }
  170. foreach ($xml->datasources[0]->optionalforeigntable as $table) {
  171. $t = $this->_parseTable(2, $table);
  172. if (isset($previousTables[$t['name']])) {
  173. $this->_tables[$t['name']]['fields'] = $previousTables[$t['name']]['fields'];
  174. }
  175. }
  176. } elseif ($this->_primaryTable === '') { // no imported dao
  177. throw new jDaoXmlException($this->selector, 'datasource.missing');
  178. }
  179. }
  180. /**
  181. * @param simpleXmlElement $xml
  182. * @param jDbTools $tools
  183. *
  184. * @throws jDaoXmlException
  185. */
  186. protected function parseRecord($xml, $tools)
  187. {
  188. //add the record properties
  189. if (isset($xml->record)) {
  190. if (isset($xml->record[0]['extends'])) {
  191. jApp::pushCurrentModule($this->selector->module);
  192. $this->_userRecord = new jSelectorDaoRecord((string) $xml->record[0]['extends']);
  193. jApp::popCurrentModule();
  194. }
  195. if (isset($xml->record[0]->property)) {
  196. // don't append directly new properties into _properties,
  197. // so we can see the differences between imported properties
  198. // and readed properties
  199. $properties = array();
  200. foreach ($xml->record[0]->property as $prop) {
  201. $p = new jDaoProperty($prop->attributes(), $this, $tools);
  202. if (isset($properties[$p->name])) {
  203. throw new jDaoXmlException($this->selector, 'property.already.defined', $p->name);
  204. }
  205. if (!in_array($p->name, $this->_tables[$p->table]['fields'])) { // if this property does not redefined an imported property
  206. $this->_tables[$p->table]['fields'][] = $p->name;
  207. }
  208. $properties[$p->name] = $p;
  209. }
  210. $this->_properties = array_merge($this->_properties, $properties);
  211. }
  212. }
  213. // in the case when there is no defined property and no imported dao
  214. if (count($this->_properties) == 0) {
  215. throw new jDaoXmlException($this->selector, 'properties.missing');
  216. }
  217. // check that properties are attached to a known table. It can be
  218. // wrong if the datasource has been redefined with other table names
  219. $countprop = 0;
  220. foreach ($this->_properties as $p) {
  221. if (!isset($this->_tables[$p->table])) {
  222. throw new jDaoXmlException($this->selector, 'property.imported.unknown.table', $p->name);
  223. }
  224. if ($p->ofPrimaryTable && !$p->isPK) {
  225. $countprop++;
  226. }
  227. }
  228. $this->hasOnlyPrimaryKeys = ($countprop == 0);
  229. }
  230. protected function parseFactory($xml)
  231. {
  232. // get additionnal methods definition
  233. if (isset($xml->factory)) {
  234. if (isset($xml->factory[0]['events'])) {
  235. $events = (string) $xml->factory[0]['events'];
  236. $this->_eventList = preg_split('/[\\s,]+/', $events);
  237. }
  238. if (isset($xml->factory[0]->method)) {
  239. $methods = array();
  240. foreach ($xml->factory[0]->method as $method) {
  241. $m = new jDaoMethod($method, $this);
  242. if (isset($methods[$m->name])) {
  243. throw new jDaoXmlException($this->selector, 'method.duplicate', $m->name);
  244. }
  245. $methods[$m->name] = $m;
  246. }
  247. $this->_methods = array_merge($this->_methods, $methods);
  248. }
  249. }
  250. }
  251. /**
  252. * parse a join definition.
  253. *
  254. * @param int $typetable
  255. * @param simpleXmlElement $tabletag
  256. */
  257. private function _parseTable($typetable, $tabletag)
  258. {
  259. $infos = $this->getAttr($tabletag, array('name', 'realname', 'primarykey', 'onforeignkey'));
  260. if ($infos['name'] === null) {
  261. throw new jDaoXmlException($this->selector, 'table.name');
  262. }
  263. if ($infos['realname'] === null) {
  264. $infos['realname'] = $infos['name'];
  265. }
  266. if ($infos['primarykey'] === null) {
  267. throw new jDaoXmlException($this->selector, 'primarykey.missing');
  268. }
  269. $infos['pk'] = preg_split('/[\\s,]+/', $infos['primarykey']);
  270. unset($infos['primarykey']);
  271. if (count($infos['pk']) == 0 || $infos['pk'][0] == '') {
  272. throw new jDaoXmlException($this->selector, 'primarykey.missing');
  273. }
  274. if ($typetable) { // for the foreigntable and optionalforeigntable
  275. if ($infos['onforeignkey'] === null) {
  276. throw new jDaoXmlException($this->selector, 'foreignkey.missing');
  277. }
  278. $infos['fk'] = preg_split('/[\\s,]+/', $infos['onforeignkey']);
  279. unset($infos['onforeignkey']);
  280. if (count($infos['fk']) == 0 || $infos['fk'][0] == '') {
  281. throw new jDaoXmlException($this->selector, 'foreignkey.missing');
  282. }
  283. if (count($infos['fk']) != count($infos['pk'])) {
  284. throw new jDaoXmlException($this->selector, 'foreignkey.missing');
  285. }
  286. if ($typetable == 1) {
  287. $this->_ijoins[] = $infos['name'];
  288. } else {
  289. $this->_ojoins[] = array($infos['name'], 0);
  290. }
  291. } else {
  292. unset($infos['onforeignkey']);
  293. }
  294. $infos['fields'] = array();
  295. $this->_tables[$infos['name']] = $infos;
  296. return $infos;
  297. }
  298. /**
  299. * Try to read all given attributes.
  300. *
  301. * @param SimpleXmlElement $tag
  302. * @param string[] $requiredattr attributes list
  303. *
  304. * @return string[] attributes and their values
  305. */
  306. public function getAttr($tag, $requiredattr)
  307. {
  308. $res = array();
  309. foreach ($requiredattr as $attr) {
  310. if (isset($tag[$attr]) && trim((string) $tag[$attr]) != '') {
  311. $res[$attr] = (string) $tag[$attr];
  312. } else {
  313. $res[$attr] = null;
  314. }
  315. }
  316. return $res;
  317. }
  318. /**
  319. * just a quick way to retrieve boolean values from a string.
  320. * will accept yes, true, 1 as "true" values
  321. * all other values will be considered as false.
  322. *
  323. * @param mixed $value
  324. *
  325. * @return bool true / false
  326. */
  327. public function getBool($value)
  328. {
  329. return in_array(trim($value), array('true', '1', 'yes'));
  330. }
  331. /**
  332. * the properties list.
  333. * keys = field code name.
  334. *
  335. * @return jDaoProperty[]
  336. */
  337. public function getProperties()
  338. {
  339. return $this->_properties;
  340. }
  341. /**
  342. * all tables with their properties, and their own fields
  343. * keys = table code name
  344. * values = array()
  345. * 'name'=> table code name, 'realname'=>'real table name',
  346. * 'pk'=> primary keys list
  347. * 'fk'=> foreign keys list
  348. * 'fields'=>array(list of field code name).
  349. *
  350. * @return array
  351. */
  352. public function getTables()
  353. {
  354. return $this->_tables;
  355. }
  356. /**
  357. * @return string the primary table code name
  358. */
  359. public function getPrimaryTable()
  360. {
  361. return $this->_primaryTable;
  362. }
  363. /**
  364. * @return jDaoMethod[] list of jDaoMethod objects
  365. */
  366. public function getMethods()
  367. {
  368. return $this->_methods;
  369. }
  370. /**
  371. * list of code name of foreign table with a outer join.
  372. *
  373. * @return array[] list of array(table code name, 0)
  374. */
  375. public function getOuterJoins()
  376. {
  377. return $this->_ojoins;
  378. }
  379. /**
  380. * list of code name of foreign tables with a inner join.
  381. *
  382. * @return string[] the list
  383. */
  384. public function getInnerJoins()
  385. {
  386. return $this->_ijoins;
  387. }
  388. public function getEvents()
  389. {
  390. return $this->_eventList;
  391. }
  392. public function hasEvent($event)
  393. {
  394. return in_array($event, $this->_eventList);
  395. }
  396. /**
  397. * selector of the user record class.
  398. *
  399. * @return jSelectorDaoRecord
  400. */
  401. public function getUserRecord()
  402. {
  403. return $this->_userRecord;
  404. }
  405. /**
  406. * selector of the imported dao. If can return several selector, if
  407. * an imported dao import itself an other dao etc.
  408. *
  409. * @return jSelectorDao[]
  410. */
  411. public function getImportedDao()
  412. {
  413. return $this->_importedDao;
  414. }
  415. }