PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/utils/class.atkmlsplitter.inc

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