PageRenderTime 64ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Adapto/Util/MlSplitter.php

http://github.com/egeniq/adapto
PHP | 357 lines | 205 code | 30 blank | 122 comment | 46 complexity | e3febea1b1e7ddb03bf5dfe3789041a7 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Adapto Toolkit.
  4. * Detailed copyright and licensing information can be found
  5. * in the doc/COPYRIGHT and doc/LICENSE files which should be
  6. * included in the distribution.
  7. *
  8. * @package adapto
  9. * @subpackage utils
  10. *
  11. * @copyright (c)2000-2004 Ibuildings.nl BV
  12. * @license http://www.achievo.org/atk/licensing ATK Open Source License
  13. *
  14. */
  15. /**
  16. * This class is responsible for managing multilanguage entitys which have
  17. * multiple records per occurance.
  18. * It updates/saves or merges multiple records.
  19. * This is used by multilingual atkEntitys. It should generally not be
  20. * necessary to use this class directly.
  21. *
  22. * @author Martin Roest <martin@ibuildings.nl>
  23. * @package adapto
  24. * @subpackage utils
  25. *
  26. */
  27. class Adapto_Util_MlSplitter
  28. {
  29. /**
  30. * Constructor
  31. *
  32. */
  33. function __construct()
  34. {
  35. // constructor
  36. }
  37. /**
  38. * Retrieve the mlsplitter instance
  39. * @return atkOutput The instance.
  40. */
  41. function &getInstance()
  42. {
  43. static $s_mlsplitter = NULL;
  44. if (!is_object($s_mlsplitter)) {
  45. $s_mlsplitter = new Adapto_Util_mlsplitter();
  46. Adapto_Util_Debugger::debug("Created a new Adapto_Util_mlsplitter instance");
  47. }
  48. return $s_mlsplitter;
  49. }
  50. /**
  51. * Get supported languages
  52. *
  53. * @param atkEntity $entity
  54. * @return array Array with supported languages
  55. */
  56. function getLanguages(&$entity)
  57. {
  58. if (method_exists($entity, "getLanguages")) {
  59. return $entity->getLanguages();
  60. }
  61. $lngs = Adapto_Config::getGlobal("supported_languages");
  62. for ($i = 0, $_i = count($lngs); $i < $_i; $i++)
  63. $lngs[$i] = strtoupper($lngs[$i]);
  64. return $lngs;
  65. }
  66. /**
  67. * Update the language field
  68. *
  69. * @param atkEntity $entity
  70. * @param array $record
  71. * @return bool
  72. */
  73. function updateLngField(&$entity, &$record)
  74. {
  75. // blegh
  76. $db = &atkGetDb();
  77. $sql = "UPDATE " . $entity->m_table . " SET " . $entity->m_lngfield . "='" . $entity->m_defaultlanguage . "'
  78. WHERE " . $entity->m_lngfield . "='' AND " . $record["atkprimkey"];
  79. return $db->query($sql);
  80. }
  81. /**
  82. * add/update multiple language records
  83. * because entitys are cached and we have to make some attribute modifications you
  84. * can't pass the entity as a reference!!
  85. *
  86. * @param atkEntity $entity
  87. * @param array $record
  88. * @param string $mode
  89. */
  90. function updateMlRecords($entity, $record, $mode = "add", $excludes = '', $includes = '')
  91. {
  92. Adapto_Util_Debugger::debug("Adapto_Util_mlsplitter::updateMlRecords() for mode $mode");
  93. $excludelist = array();
  94. $relations = array();
  95. foreach ($entity->m_attribList as $attribname => $attrib) {
  96. if (is_subclass_of($entity->m_attribList[$attribname], "atkRelation")) {
  97. // manytoone relations are stored only when adding
  98. // assume all onetomanyrelations are stored in the PRESTORE so we MUST NOT use addDb()
  99. // on this entity if its contains relations to others
  100. // but for 1:n and n:1 we need to save the refkey
  101. if ((is_a($entity->m_attribList[$attribname], "atkManyToOneRelation") || is_a($entity->m_attribList[$attribname], "atkOneToOneRelation"))
  102. && hasFlag($entity->m_attribList[$attribname]->storageType(), ADDTOQUERY)) {
  103. $relations[$attribname] = $entity->m_attribList[$attribname];
  104. $p_attrib = &$entity->m_attribList[$attribname];
  105. $p_attrib->createDestination();
  106. $attribvalue = $p_attrib->m_destInstance->m_attribList[$p_attrib->m_destInstance->primaryKeyField()]->value2db($record[$attribname]);
  107. $record[$p_attrib->fieldName()] = $attribvalue;
  108. $p_attrib = new Adapto_Attribute($attribname);
  109. $p_attrib->m_ownerInstance = &$entity;
  110. $p_attrib->init();
  111. } else
  112. $excludelist[] = $attribname;
  113. }
  114. }
  115. $languages = $this->getLanguages($entity);
  116. $atklngrecordmodes = sessionLoad("atklng_" . $entity->m_type . "_" . atkPrevLevel());
  117. $autoincrementflags = Array();
  118. foreach ($entity->m_primaryKey as $primkey) {
  119. // Make sure we don't increment the primkey
  120. if ($entity->m_attribList[$primkey]->hasFlag(AF_AUTOINCREMENT))
  121. $entity->m_attribList[$primkey]->removeFlag(AF_AUTO_INCREMENT);
  122. $autoincrementflags[] = $primkey;
  123. }
  124. foreach ($languages as $language) {
  125. if ($atklngrecordmodes[$language]["mode"] == "updatelngfield") {
  126. $this->updateLngField($entity, $record);
  127. }
  128. if ($language == $entity->m_defaultlanguage)
  129. continue;
  130. foreach ($entity->m_attribList as $attribname => $attrib) {
  131. if ($entity->m_attribList[$attribname]->hasFlag(AF_ML))
  132. $record[$attribname] = $language;
  133. if ($entity->m_attribList[$attribname]->m_mlattribute) {
  134. // change the language of the attribute
  135. $entity->m_attribList[$attribname]->m_language = $language;
  136. }
  137. }
  138. $record["atkprimkey"] = $entity->primaryKey($record) . " AND " . $entity->m_table . "." . $entity->m_lngfield . "='$language' ";
  139. $editMode = $mode;
  140. if ($atklngrecordmodes[$language]["mode"] == "add") {
  141. $editMode = "add"; // override the mode in case of missing lngrecords
  142. }
  143. // check if we have any locally generated excludes. If needed we merge
  144. // them with the parameter excludes
  145. if (count($excludelist)) {
  146. if (is_array($excludes)) {
  147. $excludes = array_unique(array_merge($excludes, $excludelist));
  148. } else {
  149. $excludes = $excludelist;
  150. }
  151. }
  152. switch ($editMode) {
  153. case "update":
  154. $entity->updateDb($record, true, $excludes, $includes);
  155. break;
  156. default:
  157. $entity->addDb($record, false, $mode, $excludes);
  158. }
  159. $record["atkprimkey"] = $oldprimkey;
  160. }
  161. foreach ($entity->m_attribList as $attribname => $attrib) {
  162. // restore the default language
  163. if ($entity->m_attribList[$attribname]->m_mlattribute) {
  164. $entity->m_attribList[$attribname]->m_language = $entity->m_defaultlanguage;
  165. }
  166. }
  167. foreach ($autoincrementflags as $primkey) {
  168. // restore the attrib flags
  169. $entity->m_attribList[$primkey]->addFlag(AF_AUTO_INCREMENT);
  170. }
  171. foreach ($relations as $attribname => $relation) {
  172. // restore the relations
  173. $entity->m_attribList[$attribname] = $relation;
  174. }
  175. sessionStore("atklng_" . $entity->m_type . "_" . atkPrevLevel(), NULL); // deleting modes
  176. }
  177. /**
  178. * Adds language condition
  179. *
  180. * @param atkQuery $query
  181. * @param atkEntity $entity
  182. * @param string $mode
  183. * @param string $joinalias
  184. */
  185. function addMlCondition(&$query, &$entity, $mode, $joinalias)
  186. {
  187. global $Adapto_VARS;
  188. $lng = (isset($Adapto_VARS["atklng"]) ? $Adapto_VARS["atklng"] : "");
  189. if (!$lng)
  190. $lng = $entity->m_defaultlanguage;
  191. if ($entity->hasFlag(EF_ML) && $mode != "edit" && $mode != "copy") {
  192. $fieldname = $joinalias . "." . $entity->m_lngfield;
  193. $query->addCondition("({$fieldname} = '' OR {$fieldname} IS NULL OR UPPER({$fieldname})='" . strtoupper($lng) . "')");
  194. }
  195. }
  196. /**
  197. * merges multiple multilanguage records to one record with fields containing arrays needed by mlattributes
  198. *
  199. * @param atkEntity $entity
  200. * @param array $recordset
  201. * @param atkQuery $query
  202. */
  203. function combineMlRecordSet(&$entity, &$recordset, $query)
  204. {
  205. $hasrelationwithmlentity = $this->getMlEntitys($entity);
  206. $languages = $this->getLanguages($entity);
  207. if (count($languages) != count($recordset)) {
  208. $recordset = $this->addLngRecords($entity, $recordset);
  209. }
  210. $this->mergeMlRecords($entity, $recordset);
  211. sessionStore("atklng_" . $entity->m_type . "_" . atkLevel(), $recordset[0]["atklngrecordmodes"]);
  212. }
  213. /**
  214. * this is used to find 1:1 relations with multilanguage support
  215. * we need these relation because the recordlist will have them included
  216. * when editting a record we have to combine these records
  217. *
  218. * @param atkEntity $entity
  219. * @return array Array with relationnames
  220. */
  221. function getMlEntitys(&$entity)
  222. {
  223. // we only have to check the 1:1 relations!!
  224. $hasrelationwithmlentity = Array();
  225. if (is_array($entity->m_relations["atkonetoonerelation"])) {
  226. foreach ($entity->m_relations["atkonetoonerelation"] as $attribname => $attribute) {
  227. $p_attrib = &$entity->m_attribList[$attribname];
  228. if ($p_attrib->createDestination() && $p_attrib->m_destInstance->hasFlag(EF_ML)) {
  229. $hasrelationwithmlentity[$attribname] = &$entity->m_attriblist[$attribname];
  230. }
  231. }
  232. }
  233. return $hasrelationwithmlentity;
  234. }
  235. /**
  236. * Has language record?
  237. *
  238. * @param atkEntity $entity
  239. * @param array $recordset
  240. * @param string $lng
  241. * @param int $index
  242. * @return bool
  243. */
  244. function hasLngRecord(&$entity, &$recordset, $lng, &$index)
  245. {
  246. $index = 0;
  247. foreach ($recordset as $record) {
  248. if ($record[$entity->m_lngfield] == $lng)
  249. return true;
  250. $index++;
  251. }
  252. return false;
  253. }
  254. /**
  255. * Add language records
  256. *
  257. * @param atkEntity $entity
  258. * @param array $recordset
  259. * @return array Array with records to add
  260. */
  261. function addLngRecords(&$entity, &$recordset)
  262. {
  263. $newrecordset = Array();
  264. $languages = $this->getLanguages($entity);
  265. Adapto_Util_Debugger::debug("Adapto_Util_mlsplitter adding missings lngrecord for " . $entity->m_type . "!");
  266. for ($i = 0, $max = count($languages); $i < $max; $i++) {
  267. $index = NULL;
  268. if (!$this->hasLngRecord($entity, $recordset, $languages[$i], $index)) {
  269. $recordcount = count($newrecordset);
  270. $newrecordset[$recordcount] = $recordset[0]; // assume that the first record is OK.
  271. $newrecordset[$recordcount][$entity->m_lngfield] = $languages[$i];
  272. if ($languages[$i] != $entity->m_defaultlanguage) // saving atkaction
  273. $newrecordset[$recordcount]["atklngrecordmodes"][$languages[$i]]["mode"] = "add";
  274. else
  275. $newrecordset[$recordcount]["atklngrecordmodes"][$languages[$i]]["mode"] = "updatelngfield";
  276. } else
  277. $newrecordset[] = $recordset[$index];
  278. }
  279. return $newrecordset;
  280. }
  281. /**
  282. * Merge multilanguage records
  283. *
  284. * @param atkEntity $entity
  285. * @param array $recordset
  286. */
  287. function mergeMlRecords(&$entity, &$recordset)
  288. {
  289. $lngattribs = array();
  290. $lngattribvalues = array();
  291. foreach ($entity->m_attribList as $attribname => $attrib) {
  292. if ($entity->m_attribList[$attribname]->m_mlattribute)
  293. $lngattribs[$attribname] = &$entity->m_attribList[$attribname];
  294. }
  295. $i = $this->searchRecordDefaultLanguage($recordset, $entity->m_defaultlanguage);
  296. $ml_record[0] = $recordset[$i]; // assume this is the record with the default language
  297. $ml_record[0]["atklngrecordmodes"] = Array();
  298. for ($i = 0, $max = count($recordset); $i < $max; $i++) {
  299. if (is_array($recordset[$i]["atklngrecordmodes"])) // keep track off atkactions
  300. $ml_record[0]["atklngrecordmodes"] = array_merge($ml_record[0]["atklngrecordmodes"], $recordset[$i]["atklngrecordmodes"]);
  301. foreach ($lngattribs as $lngattribname => $lngattrib) {
  302. $lngattribvalues[$lngattribname][strtoupper($recordset[$i][$entity->m_lngfield])] = $recordset[$i][$lngattribname];
  303. }
  304. }
  305. foreach ($lngattribvalues as $lngattribname => $value) {
  306. $ml_record[0][$lngattribname] = $value;
  307. }
  308. $recordset = $ml_record;
  309. }
  310. /**
  311. * Search the recordset for the default language
  312. *
  313. * @param array $recordset
  314. * @param string $defaultlanguage
  315. * @return int The position in the recordset array where the defaultlanguage is found
  316. */
  317. function searchRecordDefaultLanguage($recordset, $defaultlanguage)
  318. {
  319. for ($i = 0; $i < count($recordset); $i++) {
  320. if ($recordset[$i]["lng"] == $defaultlanguage)
  321. return $i;
  322. }
  323. return 0;
  324. }
  325. }
  326. ?>