Account Suspended
Account Suspended
This Account has been suspended.
Contact your hosting provider for more information.
 All Data Structures Functions Variables Pages
BeanModel.php
1 <?php
2  /*********************************************************************************
3  * Zurmo is a customer relationship management program developed by
4  * Zurmo, Inc. Copyright (C) 2017 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. 2017. All rights reserved".
35  ********************************************************************************/
36 
40  abstract class BeanModel extends ObservableComponent
41  {
48  const HAS_ONE_BELONGS_TO = 0;
49 
59 
64  const HAS_ONE = 2;
65 
71  const HAS_MANY = 3;
72 
78  const MANY_MANY = 4;
79 
87  const OWNED = true;
88 
93  const NOT_OWNED = false;
94 
95  const CACHE_IDENTIFIER = 'BeanModelMapping';
96 
104  const LINK_TYPE_ASSUMPTIVE = 0;
105 
113  const LINK_TYPE_SPECIFIC = 1;
114 
122  const LINK_TYPE_POLYMORPHIC = 2;
123 
127  protected static $lastClassInBeanHeirarchy = 'BeanModel';
128 
132  private static $attributeNamesToClassNames;
133 
137  private static $relationNameToRelationTypeModelClassNameAndOwns;
138 
142  private static $attributeNamesNotBelongsToOrManyMany;
143 
147  private static $derivedRelationNameToTypeModelClassNameAndOppposingRelation;
148 
154  private static $canHaveBean = true;
155 
159  public static function getCanHaveBean()
160  {
161  return self::$canHaveBean;
162  }
163 
168  public static function getMetadata()
169  {
170  throw new NotImplementedException();
171  }
172 
178  public static function isAnAttribute($attributeName)
179  {
180  assert('is_string($attributeName)');
181  assert('$attributeName != ""');
182  return $attributeName == 'id' || array_key_exists($attributeName, self::getAttributeNamesToClassNamesForModel());
183  }
184 
191  public static function resolveAttributeModelClassName($attributeName)
192  {
193  assert('is_string($attributeName)');
194  if ($attributeName == 'id')
195  {
196  return get_called_class();
197  }
198  return self::getAttributeModelClassName($attributeName);
199  }
200 
208  public static function getAttributeModelClassName($attributeName)
209  {
210  assert('self::isAnAttribute($attributeName)');
211  $attributeNamesToClassNames = self::getAttributeNamesToClassNamesForModel();
212  return $attributeNamesToClassNames[$attributeName];
213  }
214 
220  public static function isRelation($attributeName)
221  {
222  assert('is_string($attributeName)');
223  return array_key_exists($attributeName, static::getRelationNameToRelationTypeModelClassNameAndOwnsForModel());
224  }
225 
231  public static function isOwnedRelation($attributeName)
232  {
233  assert('is_string($attributeName)');
234  $relationAndOwns = static::getRelationNameToRelationTypeModelClassNameAndOwnsForModel();
235  return array_key_exists($attributeName, $relationAndOwns) &&
236  $relationAndOwns[$attributeName][2];
237  }
238 
243  public static function getRelationType($relationName)
244  {
245  assert('self::isRelation($relationName)');
246  $relationAndOwns = static::getRelationNameToRelationTypeModelClassNameAndOwnsForModel();
247  return $relationAndOwns[$relationName][0];
248  }
249 
256  public static function getRelationModelClassName($relationName)
257  {
258  assert('self::isRelation($relationName)');
259  $relationAndOwns = static::getRelationNameToRelationTypeModelClassNameAndOwnsForModel();
260  return $relationAndOwns[$relationName][1];
261  }
262 
267  public static function getRelationLinkType($relationName)
268  {
269  assert('self::isRelation($relationName)');
270  $relationAndOwns = static::getRelationNameToRelationTypeModelClassNameAndOwnsForModel();
271  return $relationAndOwns[$relationName][3];
272  }
273 
279  public static function getRelationLinkName($relationName)
280  {
281  assert('self::isRelation($relationName)');
282  $relationAndOwns = static::getRelationNameToRelationTypeModelClassNameAndOwnsForModel();
283  return $relationAndOwns[$relationName][4];
284  }
285 
290  public static function isRelationTypeAHasManyVariant($relationName)
291  {
292  assert('self::isRelation($relationName)');
293  if (static::getRelationType($relationName) == RedBeanModel::HAS_MANY ||
294  static::getRelationType($relationName) == RedBeanModel::HAS_ONE_BELONGS_TO)
295  {
296  return true;
297  }
298  return false;
299  }
300 
305  public static function isRelationTypeAHasOneVariant($relationName)
306  {
307  assert('self::isRelation($relationName)');
308  if (static::getRelationType($relationName) == RedBeanModel::HAS_MANY_BELONGS_TO ||
309  static::getRelationType($relationName) == RedBeanModel::HAS_ONE)
310  {
311  return true;
312  }
313  return false;
314  }
315 
320  public static function isADerivedRelationViaCastedUpModel($relationName)
321  {
322  $derivedRelations = static::getDerivedRelationNameToTypeModelClassNameAndOppposingRelationForModel();
323  if (array_key_exists($relationName, $derivedRelations))
324  {
325  return true;
326  }
327  return false;
328  }
329 
335  public static function getDerivedRelationType($relationName)
336  {
337  assert("self::isADerivedRelationViaCastedUpModel('$relationName')");
338  $derivedRelations = static::getDerivedRelationNameToTypeModelClassNameAndOppposingRelationForModel();
339  return $derivedRelations[$relationName][0];
340  }
341 
347  public static function getDerivedRelationModelClassName($relationName)
348  {
349  assert("self::isADerivedRelationViaCastedUpModel('$relationName')");
350  $derivedRelations = static::getDerivedRelationNameToTypeModelClassNameAndOppposingRelationForModel();
351  return $derivedRelations[$relationName][1];
352  }
353 
358  public static function getDerivedRelationViaCastedUpModelOpposingRelationName($relationName)
359  {
360  assert("self::isADerivedRelationViaCastedUpModel('$relationName')");
361  $derivedRelations = static::getDerivedRelationNameToTypeModelClassNameAndOppposingRelationForModel();
362  return $derivedRelations[$relationName][2];
363  }
364 
369  public static function getInferredRelationModelClassNamesForRelation($relation)
370  {
371  assert('is_string($relation)');
372  $metadata = static::getMetadata();
373  foreach ($metadata as $modelClassName => $modelClassMetadata)
374  {
375  if (isset($metadata[$modelClassName][$relation . 'ModelClassNames']))
376  {
377  return $metadata[$modelClassName][$relation . 'ModelClassNames'];
378  }
379  }
380  }
381 
387  public static function getColumnNameByAttribute($attributeName)
388  {
389  assert('is_string($attributeName)');
390  if (self::isRelation($attributeName))
391  {
392  $modelClassName = get_called_class();
393  $columnName = $modelClassName::getForeignKeyName($modelClassName, $attributeName);
394  }
395  else
396  {
397  $columnName = strtolower($attributeName);
398  }
399  return $columnName;
400  }
401 
405  public static function getAttributeNames()
406  {
407  return array_keys(static::getAttributeNamesToClassNamesForModel());
408  }
409 
413  public static function generateAnAttributeLabel($attributeName)
414  {
415  return ucfirst(preg_replace('/([A-Z0-9])/', ' \1', $attributeName));
416  }
417 
424  public static function getAbbreviatedAttributeLabel($attributeName)
425  {
426  assert('is_string($attributeName)');
427  $labels = static::translatedAbbreviatedAttributeLabels(Yii::app()->language);
428  if (isset($labels[$attributeName]))
429  {
430  return ZurmoHtml::tag('span', array('title' => static::generateAnAttributeLabel($attributeName)),
431  $labels[$attributeName]);
432  }
433  else
434  {
435  return null;
436  }
437  }
438 
444  public static function getTranslatedAttributeLabels($language)
445  {
446  return static::translatedAttributeLabels($language);
447  }
448 
452  protected static function translatedAbbreviatedAttributeLabels($language)
453  {
454  return array();
455  }
456 
457  protected static function translatedAttributeLabels($language)
458  {
459  return Yii::app()->custom->resolveCustomTranslatedAttributeLabelsByModelClassName(get_called_class(), $language);
460  }
461 
465  public static function getMixedInModelClassNames()
466  {
467  return array();
468  }
469 
473  protected static function getAttributeNamesToClassNamesForModel()
474  {
475  if (!PHP_CACHING_ON || !isset(self::$attributeNamesToClassNames[get_called_class()]))
476  {
477  self::resolveCacheAndMapMetadataForAllClassesInHeirarchy();
478  }
479  return self::$attributeNamesToClassNames[get_called_class()];
480  }
481 
486  {
487  if (!PHP_CACHING_ON || !isset(self::$attributeNamesNotBelongsToOrManyMany[get_called_class()]))
488  {
489  self::resolveCacheAndMapMetadataForAllClassesInHeirarchy();
490  }
491  return self::$attributeNamesNotBelongsToOrManyMany[get_called_class()];
492  }
493 
498  {
499  if (!PHP_CACHING_ON || !isset(self::$relationNameToRelationTypeModelClassNameAndOwns[get_called_class()]))
500  {
501  self::resolveCacheAndMapMetadataForAllClassesInHeirarchy();
502  }
503  return self::$relationNameToRelationTypeModelClassNameAndOwns[get_called_class()];
504  }
505 
510  {
511  if (!PHP_CACHING_ON || !isset(self::$derivedRelationNameToTypeModelClassNameAndOppposingRelation[get_called_class()]))
512  {
513  self::resolveCacheAndMapMetadataForAllClassesInHeirarchy();
514  }
515  return self::$derivedRelationNameToTypeModelClassNameAndOppposingRelation[get_called_class()];
516  }
517 
521  protected static function forgetBeanModel($modelClassName)
522  {
523  if (isset(self::$attributeNamesToClassNames[$modelClassName]))
524  {
525  unset(self::$attributeNamesToClassNames[$modelClassName]);
526  }
527  if (isset(self::$relationNameToRelationTypeModelClassNameAndOwns[$modelClassName]))
528  {
529  unset(self::$relationNameToRelationTypeModelClassNameAndOwns[$modelClassName]);
530  }
531  if (isset(self::$derivedRelationNameToTypeModelClassNameAndOppposingRelation[$modelClassName]))
532  {
533  unset(self::$derivedRelationNameToTypeModelClassNameAndOppposingRelation[$modelClassName]);
534  }
535  if (isset(self::$attributeNamesNotBelongsToOrManyMany[$modelClassName]))
536  {
537  unset(self::$attributeNamesNotBelongsToOrManyMany[$modelClassName]);
538  }
539  BeanModelCache::forgetEntry(self::CACHE_IDENTIFIER . get_called_class());
540  }
541 
542  protected static function forgetAllBeanModels()
543  {
544  self::$attributeNamesToClassNames = null;
545  self::$relationNameToRelationTypeModelClassNameAndOwns = null;
546  self::$derivedRelationNameToTypeModelClassNameAndOppposingRelation = null;
547  self::$attributeNamesNotBelongsToOrManyMany = null;
548  BeanModelCache::forgetAll();
549  }
550 
551  protected static function resolveCacheAndMapMetadataForAllClassesInHeirarchy()
552  {
553  try
554  {
555  // not using default value to save cpu cycles on requests that follow the first exception.
556  $cachedData = BeanModelCache::getEntry(self::CACHE_IDENTIFIER . get_called_class());
557  static::resolveCachedMetadataForIntegrity($cachedData);
558  self::$attributeNamesToClassNames[get_called_class()] =
559  $cachedData['attributeNamesToClassNames'][get_called_class()];
560  self::$attributeNamesNotBelongsToOrManyMany[get_called_class()] =
561  $cachedData['attributeNamesNotBelongsToOrManyMany'][get_called_class()];
562  self::$relationNameToRelationTypeModelClassNameAndOwns[get_called_class()] =
563  $cachedData['relationNameToRelationTypeModelClassNameAndOwns'][get_called_class()];
564  self::$derivedRelationNameToTypeModelClassNameAndOppposingRelation[get_called_class()] =
565  $cachedData['derivedRelationNameToTypeModelClassNameAndOppposingRelation'][get_called_class()];
566  }
567  catch (NotFoundException $e)
568  {
569  self::mapMetadataForAllClassesInHeirarchy();
570  $cachedData = array();
571  $cachedData['attributeNamesToClassNames'][get_called_class()] =
572  self::$attributeNamesToClassNames[get_called_class()];
573  $cachedData['attributeNamesNotBelongsToOrManyMany'][get_called_class()] =
574  self::$attributeNamesNotBelongsToOrManyMany[get_called_class()];
575  $cachedData['relationNameToRelationTypeModelClassNameAndOwns'][get_called_class()] =
576  self::$relationNameToRelationTypeModelClassNameAndOwns[get_called_class()];
577  $cachedData['derivedRelationNameToTypeModelClassNameAndOppposingRelation'][get_called_class()] =
578  self::$derivedRelationNameToTypeModelClassNameAndOppposingRelation[get_called_class()];
579  BeanModelCache::cacheEntry(self::CACHE_IDENTIFIER . get_called_class(), $cachedData);
580  }
581  }
582 
590  protected static function resolveCachedMetadataForIntegrity($cachedData)
591  {
592  }
593 
597  private static function mapMetadataForAllClassesInHeirarchy()
598  {
599  self::$attributeNamesToClassNames[get_called_class()] = array();
600  self::$relationNameToRelationTypeModelClassNameAndOwns[get_called_class()] = array();
601  self::$derivedRelationNameToTypeModelClassNameAndOppposingRelation[get_called_class()] = array();
602  self::$attributeNamesNotBelongsToOrManyMany[get_called_class()] = array();
603  foreach (array_reverse(RuntimeUtil::getClassHierarchy(get_called_class(), static::$lastClassInBeanHeirarchy)) as $modelClassName)
604  {
605  if ($modelClassName::getCanHaveBean())
606  {
607  self::mapMetadataByModelClassName($modelClassName);
608  }
609  }
610  foreach (static::getMixedInModelClassNames() as $modelClassName)
611  {
612  if ($modelClassName::getCanHaveBean())
613  {
614  self::mapMetadataByModelClassName($modelClassName);
615  }
616  }
617  }
618 
623  private static function mapMetadataByModelClassName($modelClassName)
624  {
625  assert('is_string($modelClassName)');
626  assert('$modelClassName != ""');
627  $metadata = static::getMetadata();
628  if (isset($metadata[$modelClassName]))
629  {
630  if (isset($metadata[$modelClassName]['members']))
631  {
632  foreach ($metadata[$modelClassName]['members'] as $memberName)
633  {
634  self::$attributeNamesToClassNames[get_called_class()][$memberName] = $modelClassName;
635  self::$attributeNamesNotBelongsToOrManyMany[get_called_class()][] = $memberName;
636  }
637  }
638  }
639  if (isset($metadata[$modelClassName]['relations']))
640  {
641  foreach ($metadata[$modelClassName]['relations'] as $relationName => $relationTypeModelClassNameAndOwns)
642  {
643  assert('in_array(count($relationTypeModelClassNameAndOwns), array(2, 3, 4, 5))');
644 
645  $relationType = $relationTypeModelClassNameAndOwns[0];
646  $relationModelClassName = $relationTypeModelClassNameAndOwns[1];
647  if ($relationType == self::HAS_MANY_BELONGS_TO &&
648  strtolower($relationName) != strtolower($relationModelClassName))
649  {
650  throw new NotSupportedException(Zurmo::t('Core', 'Relations of type HAS_MANY_BELONGS_TO must have the relation name ' .
651  'the same as the related model class name. Relation: {relationName} ' .
652  'Relation model class name: {relationModelClassName}',
653  array('{relationName}' => $relationName,
654  '{relationModelClassName}' => $relationModelClassName)));
655  }
656  if (count($relationTypeModelClassNameAndOwns) >= 3 &&
657  $relationTypeModelClassNameAndOwns[2] == self::OWNED)
658  {
659  $owns = true;
660  }
661  else
662  {
663  $owns = false;
664  }
665  $linkType = null;
666  $relationLinkName = null;
667  self::resolveLinkTypeAndRelationLinkName($relationTypeModelClassNameAndOwns, $linkType,
668  $relationLinkName);
669  if ($linkType == self::LINK_TYPE_SPECIFIC &&
670  $relationTypeModelClassNameAndOwns[2] == self::NOT_OWNED &&
671  strtolower($relationTypeModelClassNameAndOwns[1]) == strtolower($relationName))
672  {
673  //When a relation is the same as the relatedModelClassName and it is a specific link, this is not
674  //supportive. Either use assumptive or change the relation name.
675  // TODO: @Shoaibi/@Jason: Low: Commented this to allow link type specific for has_one
676  // throw new NotSupportedException();
677  }
678  assert('in_array($relationType, array(self::HAS_ONE_BELONGS_TO, self::HAS_MANY_BELONGS_TO, ' .
679  'self::HAS_ONE, self::HAS_MANY, self::MANY_MANY))');
680  self::$attributeNamesToClassNames[get_called_class()][$relationName] = $modelClassName;
681  self::$relationNameToRelationTypeModelClassNameAndOwns[get_called_class()][$relationName] =
682  array($relationType,
683  $relationModelClassName,
684  $owns,
685  $linkType,
686  $relationLinkName);
687  if (!in_array($relationType, array(self::HAS_ONE_BELONGS_TO, self::HAS_MANY_BELONGS_TO, self::MANY_MANY)))
688  {
689  self::$attributeNamesNotBelongsToOrManyMany[get_called_class()][] = $relationName;
690  }
691  }
692  }
693  if (isset($metadata[$modelClassName]['derivedRelationsViaCastedUpModel']))
694  {
695  foreach ($metadata[$modelClassName]['derivedRelationsViaCastedUpModel'] as $relationName =>
696  $relationTypeModelClassNameAndOpposingRelation)
697  {
698  self::$derivedRelationNameToTypeModelClassNameAndOppposingRelation[get_called_class()][$relationName] =
699  $relationTypeModelClassNameAndOpposingRelation;
700  }
701  }
702  }
703 
704  protected static function resolveLinkTypeAndRelationLinkName($relationTypeModelClassNameAndOwns, & $linkType,
705  & $relationLinkName)
706  {
707  if (count($relationTypeModelClassNameAndOwns) == 4 &&
708  $relationTypeModelClassNameAndOwns[3] != self::LINK_TYPE_ASSUMPTIVE)
709  {
710  throw new NotSupportedException();
711  }
712  if (count($relationTypeModelClassNameAndOwns) == 5)
713  {
714  $linkType = $relationTypeModelClassNameAndOwns[3];
715  $relationLinkName = $relationTypeModelClassNameAndOwns[4];
716  }
717  else
718  {
719  $linkType = self::LINK_TYPE_ASSUMPTIVE;
720  $relationLinkName = null;
721  }
722  }
723 
728  public static function isRelationTypeAManyManyVariant($relationName)
729  {
730  assert('self::isRelation($relationName)');
731  if (static::getRelationType($relationName) == RedBeanModel::MANY_MANY)
732  {
733  return true;
734  }
735  return false;
736  }
737  }
738 ?>
static forgetBeanModel($modelClassName)
Definition: BeanModel.php:521
static isRelationTypeAHasManyVariant($relationName)
Definition: BeanModel.php:290
static isAnAttribute($attributeName)
Definition: BeanModel.php:178
static getAbbreviatedAttributeLabel($attributeName)
Definition: BeanModel.php:424
static getAttributeNamesToClassNamesForModel()
Definition: BeanModel.php:473
static getDerivedRelationViaCastedUpModelOpposingRelationName($relationName)
Definition: BeanModel.php:358
static isRelationTypeAHasOneVariant($relationName)
Definition: BeanModel.php:305
static resolveAttributeModelClassName($attributeName)
Definition: BeanModel.php:191
const OWNED
Definition: BeanModel.php:87
static translatedAbbreviatedAttributeLabels($language)
Definition: BeanModel.php:452
const HAS_ONE
Definition: BeanModel.php:64
static isRelationTypeAManyManyVariant($relationName)
Definition: BeanModel.php:728
const HAS_ONE_BELONGS_TO
Definition: BeanModel.php:48
static resolveCachedMetadataForIntegrity($cachedData)
Definition: BeanModel.php:590
static getAttributeModelClassName($attributeName)
Definition: BeanModel.php:208
static getMetadata()
Definition: BeanModel.php:168
static getColumnNameByAttribute($attributeName)
Definition: BeanModel.php:387
static getDerivedRelationType($relationName)
Definition: BeanModel.php:335
static getMixedInModelClassNames()
Definition: BeanModel.php:465
const MANY_MANY
Definition: BeanModel.php:78
static getRelationNameToRelationTypeModelClassNameAndOwnsForModel()
Definition: BeanModel.php:497
static generateAnAttributeLabel($attributeName)
Definition: BeanModel.php:413
static getCanHaveBean()
Definition: BeanModel.php:159
static getClassHierarchy($className, $upToAndNotIncludingClassName)
Definition: RuntimeUtil.php:54
static getDerivedRelationNameToTypeModelClassNameAndOppposingRelationForModel()
Definition: BeanModel.php:509
static getTranslatedAttributeLabels($language)
Definition: BeanModel.php:444
static getInferredRelationModelClassNamesForRelation($relation)
Definition: BeanModel.php:369
const HAS_MANY_BELONGS_TO
Definition: BeanModel.php:58
static getDerivedRelationModelClassName($relationName)
Definition: BeanModel.php:347
const HAS_MANY
Definition: BeanModel.php:71
static getRelationLinkType($relationName)
Definition: BeanModel.php:267
static isRelation($attributeName)
Definition: BeanModel.php:220
static isOwnedRelation($attributeName)
Definition: BeanModel.php:231
static isADerivedRelationViaCastedUpModel($relationName)
Definition: BeanModel.php:320
static getAttributeNames()
Definition: BeanModel.php:405
static $lastClassInBeanHeirarchy
Definition: BeanModel.php:127
static getAttributeNamesNotBelongsToOrManyManyForModel()
Definition: BeanModel.php:485
static getRelationModelClassName($relationName)
Definition: BeanModel.php:256
static getRelationLinkName($relationName)
Definition: BeanModel.php:279
static getRelationType($relationName)
Definition: BeanModel.php:243
Generated on Fri Sep 25 2020 07:10:26
Account Suspended
Account Suspended
This Account has been suspended.
Contact your hosting provider for more information.