PageRenderTime 1317ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/app/protected/modules/emailTemplates/adapters/MergeTagsToModelAttributesAdapter.php

https://bitbucket.org/andreustimm/zurmo
PHP | 327 lines | 270 code | 14 blank | 43 comment | 36 complexity | 45ca45b8fa5251415c5930aa6a1792e8 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-3.0, LGPL-2.1, BSD-2-Clause
  1. <?php
  2. /*********************************************************************************
  3. * Zurmo is a customer relationship management program developed by
  4. * Zurmo, Inc. Copyright (C) 2015 Zurmo Inc.
  5. *
  6. * Zurmo is free software; you can redistribute it and/or modify it under
  7. * the terms of the GNU Affero General Public License version 3 as published by the
  8. * Free Software Foundation with the addition of the following permission added
  9. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  10. * IN WHICH THE COPYRIGHT IS OWNED BY ZURMO, ZURMO DISCLAIMS THE WARRANTY
  11. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  12. *
  13. * Zurmo is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  15. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License along with
  19. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  20. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  21. * 02110-1301 USA.
  22. *
  23. * You can contact Zurmo, Inc. with a mailing address at 27 North Wacker Drive
  24. * Suite 370 Chicago, IL 60606. or at email address contact@zurmo.com.
  25. *
  26. * The interactive user interfaces in original and modified versions
  27. * of this program must display Appropriate Legal Notices, as required under
  28. * Section 5 of the GNU Affero General Public License version 3.
  29. *
  30. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  31. * these Appropriate Legal Notices must retain the display of the Zurmo
  32. * logo and Zurmo copyright notice. If the display of the logo is not reasonably
  33. * feasible for technical reasons, the Appropriate Legal Notices must display the words
  34. * "Copyright Zurmo Inc. 2015. All rights reserved".
  35. ********************************************************************************/
  36. /*
  37. * This class is responsible from converting merge tags to relevant attribute values,
  38. * apply any language translations and returning the final value.
  39. */
  40. class MergeTagsToModelAttributesAdapter
  41. {
  42. const PROPERTY_NOT_FOUND = "!MERGETAG-TO-ATTR-FAILED";
  43. const ERROR_ON_FIRST_INVALID_TAG = 1;
  44. const DO_NOT_ERROR_ON_FIRST_INVALID_TAG = 0;
  45. const SUPPRESS_INVALID_TAG_ERRORS_REPLACE_WITH_EMPTY = -1;
  46. const SUPPRESS_INVALID_TAG_ERRORS_KEEP_TAG = -2;
  47. public static function resolveMergeTagsArrayToAttributesFromModel(& $mergeTags, $model,
  48. & $invalidTags = array(), $language,
  49. $errorOnFirstMissing = self::DO_NOT_ERROR_ON_FIRST_INVALID_TAG,
  50. $params = array())
  51. {
  52. assert('$language == null || is_string($language)');
  53. if ($language == null)
  54. {
  55. $language = Yii::app()->language;
  56. }
  57. $resolvedMergeTags = array();
  58. foreach ($mergeTags as $mergeTag)
  59. {
  60. $attributeAccessorString = static::resolveStringToAttributeAccessor($mergeTag);
  61. $timeQualifier = static::stripTimeDelimiterAndReturnQualifier($attributeAccessorString);
  62. $resolvedValue = static::resolveMergeTagToStandardOrRelatedAttribute(
  63. $attributeAccessorString,
  64. $model,
  65. $language,
  66. $timeQualifier,
  67. $errorOnFirstMissing,
  68. $params);
  69. if ($resolvedValue === static::PROPERTY_NOT_FOUND)
  70. {
  71. if ($errorOnFirstMissing === static::ERROR_ON_FIRST_INVALID_TAG)
  72. {
  73. return false;
  74. }
  75. if ($errorOnFirstMissing === static::SUPPRESS_INVALID_TAG_ERRORS_KEEP_TAG)
  76. {
  77. $resolvedMergeTags[$mergeTag] = MergeTagsUtil::TAG_PREFIX . $mergeTag . MergeTagsUtil::TAG_SUFFIX;
  78. }
  79. $invalidTags[] = $mergeTag;
  80. }
  81. else
  82. {
  83. $resolvedMergeTags[$mergeTag] = $resolvedValue;
  84. }
  85. }
  86. $mergeTags = $resolvedMergeTags;
  87. if ($errorOnFirstMissing === static::DO_NOT_ERROR_ON_FIRST_INVALID_TAG)
  88. {
  89. return (empty($invalidTags));
  90. }
  91. //$errorOnFirstMissing === SUPPRESS_INVALID_TAG_ERRORS_REPLACE_WITH_EMPTY OR SUPPRESS_INVALID_TAG_ERRORS_KEEP_TAG
  92. return true;
  93. }
  94. protected static function stripTimeDelimiterAndReturnQualifier(& $mergeTag)
  95. {
  96. $timeDelimiterIndex = strpos($mergeTag, MergeTagsUtil::TIME_DELIMITER);
  97. if ($timeDelimiterIndex !== false)
  98. {
  99. $timeQualifier = substr($mergeTag, 0, $timeDelimiterIndex);
  100. $mergeTag = substr($mergeTag, $timeDelimiterIndex + 1);
  101. return $timeQualifier;
  102. }
  103. else
  104. {
  105. return null;
  106. }
  107. }
  108. protected static function resolveMergeTagToStandardOrRelatedAttribute($attributeAccessorString, $model,
  109. $language, $timeQualifier,
  110. $errorOnFirstMissing, $params)
  111. {
  112. $attributeName = strtok($attributeAccessorString, '->');
  113. if (SpecialMergeTagsAdapter::isSpecialMergeTag($attributeName, $timeQualifier))
  114. {
  115. return SpecialMergeTagsAdapter::resolve($attributeName, $model, $errorOnFirstMissing, $params);
  116. }
  117. else
  118. {
  119. if (!isset($model))
  120. {
  121. return static::PROPERTY_NOT_FOUND;
  122. }
  123. elseif (!method_exists($model, 'isAttribute') || !$model->isAttribute($attributeName))
  124. {
  125. if ($model instanceof Activity)
  126. {
  127. $metadata = $model::getMetadata();
  128. $activityItemsModelClassNamesData = $metadata['Activity']['activityItemsModelClassNames'];
  129. foreach ($model->activityItems as $activityItem)
  130. {
  131. if (ucfirst($attributeName) == get_class($activityItem))
  132. {
  133. $attributeAccessorString = str_replace($attributeName . '->', '', $attributeAccessorString);
  134. return static::resolveMergeTagToStandardOrRelatedAttribute(
  135. $attributeAccessorString,
  136. $activityItem,
  137. $language,
  138. $timeQualifier,
  139. $errorOnFirstMissing,
  140. $params);
  141. }
  142. if (get_class($activityItem) == 'Item' && array_search(ucfirst($attributeName), $activityItemsModelClassNamesData) !== false)
  143. {
  144. try
  145. {
  146. $modelDerivationPathToItem = RuntimeUtil::getModelDerivationPathToItem(ucfirst($attributeName));
  147. $castedDownModel = $activityItem->castDown(array($modelDerivationPathToItem));
  148. if (ucfirst($attributeName) == get_class($castedDownModel))
  149. {
  150. $attributeAccessorString = str_replace($attributeName . '->', '', $attributeAccessorString);
  151. return static::resolveMergeTagToStandardOrRelatedAttribute(
  152. $attributeAccessorString,
  153. $castedDownModel,
  154. $language,
  155. $timeQualifier,
  156. $errorOnFirstMissing,
  157. $params);
  158. }
  159. }
  160. catch (NotFoundException $e)
  161. {
  162. //Do nothing
  163. }
  164. }
  165. unset($activityItemsModelClassNamesData[get_class($activityItem)]);
  166. }
  167. foreach ($activityItemsModelClassNamesData as $relationModelClassName)
  168. {
  169. if (ucfirst($attributeName) == $relationModelClassName)
  170. {
  171. $model = new $relationModelClassName();
  172. $attributeAccessorString = str_replace($attributeName . '->', '', $attributeAccessorString);
  173. return static::resolveMergeTagToStandardOrRelatedAttribute(
  174. $attributeAccessorString,
  175. $model,
  176. $language,
  177. $timeQualifier,
  178. $errorOnFirstMissing,
  179. $params);
  180. }
  181. }
  182. }
  183. return static::PROPERTY_NOT_FOUND;
  184. }
  185. elseif ($model->$attributeName instanceof CustomField)
  186. {
  187. $value = static::getAttributeValue($model->$attributeName, 'value', $timeQualifier);
  188. // TODO: @Shoaibi/@Jason: Low: need to apply localizations(Date/time/currency formats, ...) here besides translation
  189. if ($value)
  190. {
  191. $value = Zurmo::t($model::getModuleClassName(), $value, array(), null, $language);
  192. }
  193. return $value;
  194. }
  195. elseif ($model->isRelation($attributeName))
  196. {
  197. $model = $model->$attributeName;
  198. if ($attributeName === $attributeAccessorString) // We have name of relation, don't have a property requested, like $object->owner
  199. {
  200. $attributeAccessorString = null;
  201. }
  202. else
  203. {
  204. $attributeAccessorString = str_replace($attributeName . '->', '', $attributeAccessorString);
  205. }
  206. if (empty($attributeAccessorString))
  207. {
  208. // If a user specific a relation merge tag but not a property, we assume he meant "value" property.
  209. if (empty($timeQualifier))
  210. {
  211. return strval($model);
  212. }
  213. else
  214. {
  215. return static::PROPERTY_NOT_FOUND;
  216. }
  217. }
  218. if ($model instanceof RedBeanModels)
  219. {
  220. $modelClassName = $model->getModelClassName();
  221. if ($attributeAccessorString == lcfirst($modelClassName))
  222. {
  223. $values = array();
  224. foreach ($model as $relatedModel)
  225. {
  226. $values[] = strval($relatedModel);
  227. }
  228. return ArrayUtil::stringify($values);
  229. }
  230. }
  231. return static::resolveMergeTagToStandardOrRelatedAttribute($attributeAccessorString, $model,
  232. $language, $timeQualifier,
  233. $errorOnFirstMissing, $params);
  234. }
  235. else
  236. {
  237. $attributeType = ModelAttributeToMixedTypeUtil::getType($model, $attributeName);
  238. //We don't have any accessor operator after the attributeName e.g. its the last in list
  239. if ($attributeName === $attributeAccessorString)
  240. {
  241. $content = static::getAttributeValue($model, $attributeName, $timeQualifier);
  242. if ($attributeType == 'DateTime')
  243. {
  244. $content .= ' GMT';
  245. }
  246. return $content;
  247. }
  248. else
  249. {
  250. return static::PROPERTY_NOT_FOUND;
  251. }
  252. }
  253. }
  254. }
  255. protected static function resolveModelUrlByModel($model)
  256. {
  257. $modelClassName = get_class($model);
  258. $moduleClassName = $modelClassName::getModuleClassName();
  259. $moduleId = $moduleClassName::getDirectoryName();
  260. return Yii::app()->createAbsoluteUrl('/' . $moduleId . '/default/details/', array('id' => $model->id));
  261. }
  262. protected static function getAttributeValue($model, $attributeName, $timeQualifier)
  263. {
  264. if (empty($timeQualifier))
  265. {
  266. return static::getAttributeCurrentValue($model, $attributeName);
  267. }
  268. else
  269. {
  270. return static::getAttributePreviousValue($model, $attributeName);
  271. }
  272. }
  273. protected static function getAttributeCurrentValue($model, $attributeName)
  274. {
  275. if (isset($model->$attributeName))
  276. {
  277. return $model->$attributeName;
  278. }
  279. else
  280. {
  281. return null;
  282. }
  283. }
  284. protected static function getAttributePreviousValue($model, $attributeName)
  285. {
  286. if (property_exists($model, 'originalAttributeValues') || $model->isAttribute('originalAttributeValues'))
  287. {
  288. if (isset($model->originalAttributeValues[$attributeName]))
  289. {
  290. return $model->originalAttributeValues[$attributeName];
  291. }
  292. else
  293. {
  294. if (isset($model->$attributeName))
  295. {
  296. return $model->$attributeName;
  297. }
  298. }
  299. }
  300. else
  301. {
  302. return static::PROPERTY_NOT_FOUND;
  303. }
  304. return null;
  305. }
  306. protected static function resolveStringToAttributeAccessor($string)
  307. {
  308. return StringUtil::camelize(str_replace(MergeTagsUtil::PROPERTY_DELIMITER, '->', strtolower($string)),
  309. false,
  310. MergeTagsUtil::CAPITAL_DELIMITER);
  311. }
  312. }
  313. ?>