%PDF- %PDF-
Direktori : /home/bitrix/www/bitrix/modules/main/lib/orm/fields/relations/ |
Current File : //home/bitrix/www/bitrix/modules/main/lib/orm/fields/relations/manytomany.php |
<?php /** * Bitrix Framework * @package bitrix * @subpackage main * @copyright 2001-2018 Bitrix */ namespace Bitrix\Main\ORM\Fields\Relations; use Bitrix\Main\ArgumentException; use Bitrix\Main\ORM\Entity; use Bitrix\Main\ORM\Fields\FieldTypeMask; use Bitrix\Main\ORM\Query\Query; use Bitrix\Main\ORM\Fields\Relations\Reference; use Bitrix\Main\SystemException; /** * Performs many to many relation through mediator entity * @package bitrix * @subpackage main */ class ManyToMany extends Relation { /** @var string */ protected $mediatorEntityName; /** @var Entity */ protected $mediatorEntity; /** @var string Used when mediator is a virtual entity */ protected $mediatorTableName; /** @var string[] Stores owner entity primary => mediator primary */ protected $localPrimaryNames; /** @var string Name of reference from mediator to owner entity */ protected $localReferenceName; /** @var string[] Stores target entity primary => mediator primary */ protected $remotePrimaryNames; /** @var string Name of reference from mediator to target entity */ protected $remoteReferenceName; /** * @param string $name * @param string|Entity $referenceEntity * * @throws SystemException */ public function __construct($name, $referenceEntity) { if ($referenceEntity instanceof Entity) { $this->refEntity = $referenceEntity; $this->refEntityName = $referenceEntity->getFullName(); } else { // this one could be without leading backslash and/or with Table-postfix $this->refEntityName = Entity::normalizeName($referenceEntity); } parent::__construct($name); } public function getTypeMask() { return FieldTypeMask::MANY_TO_MANY; } /** * Explicit mediator entity. By default will be generated automatically. * * @param string|Entity $entity * * @return $this */ public function configureMediatorEntity($entity) { if ($entity instanceof Entity) { $this->mediatorEntity = $entity; $this->mediatorEntityName = $entity->getFullName(); } else { // this one could be without leading backslash and/or with Table-postfix $this->mediatorEntityName = Entity::normalizeName($entity); } return $this; } /** * In case of auto-generated mediator, sets the custom table name. * * @param $name * * @return $this */ public function configureMediatorTableName($name) { $this->mediatorTableName = $name; return $this; } /** * Short alias for configureMediatorTableName() * * @param $name * * @return $this */ public function configureTableName($name) { return $this->configureMediatorTableName($name); } /** * In case of auto-generated mediator, sets the custom ID field name that stores owner entity ID. * * @param $fieldName * @param $mediatorFieldName * * @return $this */ public function configureLocalPrimary($fieldName, $mediatorFieldName) { $this->localPrimaryNames[$fieldName] = $mediatorFieldName; return $this; } /** * In case of auto-generated mediator, sets the custom reference field name that points to owner entity. * * @param $name * * @return $this */ public function configureLocalReference($name) { $this->localReferenceName = $name; return $this; } /** * In case of auto-generated mediator, sets the custom ID field name that stores target entity ID. * * @param $fieldName * @param $mediatorFieldName * * @return $this */ public function configureRemotePrimary($fieldName, $mediatorFieldName) { $this->remotePrimaryNames[$fieldName] = $mediatorFieldName; return $this; } /** * In case of auto-generated mediator, sets the custom reference field name that points to target entity. * * @param $name * * @return $this */ public function configureRemoteReference($name) { $this->remoteReferenceName = $name; return $this; } /** * @return Entity * @throws ArgumentException * @throws SystemException */ public function getRemoteEntity() { return $this->getRefEntity(); } /** * @return Entity * @throws ArgumentException * @throws SystemException */ public function getMediatorEntity() { if ($this->mediatorEntity === null) { if (!empty($this->mediatorEntityName) && class_exists($this->mediatorEntityName)) { $this->mediatorEntity = Entity::getInstance($this->mediatorEntityName); } else { // there is no described mediator entity // check table_name first, entity can not exist without it if (empty($this->mediatorTableName)) { throw new ArgumentException(sprintf( 'Table Name for mediator entity of relation `%s` between %s and %s was not found', $this->name, $this->getEntity()->getObjectClass(), $this->getRefEntity()->getObjectClass() )); } // generate mediator entity runtime if (empty($this->mediatorEntityName)) { $localEntityName = $this->getEntity()->getName(); $remoteEntityName = $this->getRefEntity()->getName(); $fieldToClassName = Entity::snake2camel($this->name); // each field has its own entity in case of ManyToMany definitions will be different $this->mediatorEntityName = "MediatorFrom{$localEntityName}To{$remoteEntityName}Via{$fieldToClassName}Table"; } // fields of mediator entity $fields = []; // local entity primary $localReferenceConditions = Query::filter(); foreach ($this->getEntity()->getPrimaryArray() as $primaryName) { if (isset($this->localPrimaryNames[$primaryName])) { $mediatorPrimaryName = $this->localPrimaryNames[$primaryName]; } else { $mediatorPrimaryName = $this->getLocalReferenceName().'_'.$primaryName; } $fieldType = get_class($this->getEntity()->getField($primaryName)); /** @var \Bitrix\Main\ORM\Fields\ScalarField $mediatorPrimary */ $mediatorPrimary = new $fieldType($mediatorPrimaryName); $mediatorPrimary->configurePrimary(true); $fields[] = $mediatorPrimary; // save join condition for reference $localReferenceConditions->whereColumn('this.'.$mediatorPrimaryName, 'ref.'.$primaryName); } // local reference $localReference = (new Reference($this->getLocalReferenceName(), $this->getEntity(), $localReferenceConditions)) ->configureJoinType('inner'); $fields[] = $localReference; // remote entity primary $remoteReferenceConditions = Query::filter(); foreach ($this->getRefEntity()->getPrimaryArray() as $primaryName) { if (isset($this->remotePrimaryNames[$primaryName])) { $mediatorPrimaryName = $this->remotePrimaryNames[$primaryName]; } else { $mediatorPrimaryName = $this->getRemoteReferenceName().'_'.$primaryName; } $fieldType = get_class($this->getRefEntity()->getField($primaryName)); /** @var \Bitrix\Main\ORM\Fields\ScalarField $mediatorPrimary */ $mediatorPrimary = new $fieldType($mediatorPrimaryName); $mediatorPrimary->configurePrimary(true); $fields[] = $mediatorPrimary; // save join condition for reference $remoteReferenceConditions->whereColumn('this.'.$mediatorPrimaryName, 'ref.'.$primaryName); } // remote reference $remoteReference = (new Reference($this->getRemoteReferenceName(), $this->getRefEntity(), $remoteReferenceConditions)) ->configureJoinType('inner'); $fields[] = $remoteReference; // set table name $parameters = ['table_name' => $this->mediatorTableName]; // finalize $this->mediatorEntity = Entity::compileEntity($this->mediatorEntityName, $fields, $parameters); } } return $this->mediatorEntity; } /** * @return string */ public function getLocalReferenceName() { if (empty($this->localReferenceName)) { $this->localReferenceName = strtoupper(Entity::camel2snake($this->getEntity()->getName())); } return $this->localReferenceName; } /** * Returns reference from mediator to owner entity * * @return \Bitrix\Main\ORM\Fields\Relations\Reference|\Bitrix\Main\ORM\Fields\Field * @throws ArgumentException * @throws SystemException */ public function getLocalReference() { return $this->getMediatorEntity()->getField($this->getLocalReferenceName()); } /** * @return string * @throws ArgumentException * @throws SystemException */ public function getRemoteReferenceName() { if (empty($this->remoteReferenceName)) { $this->remoteReferenceName = strtoupper(Entity::camel2snake($this->getRefEntity()->getName())); } return $this->remoteReferenceName; } /** * Returns reference from mediator to target entity * * @return \Bitrix\Main\ORM\Fields\Relations\Reference|\Bitrix\Main\ORM\Fields\Field * @throws ArgumentException * @throws SystemException */ public function getRemoteReference() { return $this->getMediatorEntity()->getField($this->getRemoteReferenceName()); } }