public function registerRuntimeField($name, $fieldInfo) { $field = $this->init_entity->initializeField($name, $fieldInfo); $chain = new QueryChain(); $chain->addElement(new QueryChainElement($this->init_entity)); $chain->addElement(new QueryChainElement($field)); // add $this->registerChain('runtime', $chain); return $this; }
public static function getChainByDefinition(Base $init_entity, $definition) { $chain = new QueryChain(); $chain->addElement(new QueryChainElement($init_entity)); $def_elements = explode('.', $definition); $def_elements_size = count($def_elements); $prev_entity = $init_entity; $i = 0; foreach ($def_elements as &$def_element) { $is_first_elem = $i == 0; $is_last_elem = ++$i == $def_elements_size; $not_found = false; // all elements should be a Reference field or Entity // normal (scalar) field can only be the last element if ($prev_entity->hasField($def_element)) { // field has been found at current entity $field = $prev_entity->getField($def_element); if ($field instanceof ReferenceField) { $prev_entity = $field->getRefEntity(); } elseif ($field instanceof ExpressionField) { // expr can be in the middle too } elseif (!$is_last_elem) { throw new \Exception(sprintf('Normal fields can be only the last in chain, `%s` %s is not the last.', $field->getName(), get_class($field))); } if ($is_last_elem && $field instanceof ExpressionField) { // we should have own copy of build_from_chains to set join aliases there $field = clone $field; } $chain->addElement(new QueryChainElement($field)); } elseif ($prev_entity->hasUField($def_element)) { // extend chain with utm/uts entity $ufield = $prev_entity->getUField($def_element); $u_entity = null; if ($ufield->isMultiple()) { // add utm entity user.utm:source_object (1:N) $utm_entity = Base::getInstance($prev_entity->getNamespace() . 'Utm' . $prev_entity->getName()); $u_entity = $utm_entity; $chain->addElement(new QueryChainElement(array($utm_entity, $utm_entity->getField('SOURCE_OBJECT')), array('ufield' => $ufield))); if ($ufield->getTypeId() == 'iblock_section' && substr($ufield->getName(), -3) == '_BY' && $prev_entity->hasUField(substr($ufield->getName(), 0, -3))) { // connect next entity $utm_fname = $ufield->getName(); $prev_entity = Base::getInstance('Bitrix\\Iblock\\Section'); } else { $utm_fname = $ufield->getValueFieldName(); } $chain->addElement(new QueryChainElement($utm_entity->getField($utm_fname), array('ufield' => $ufield))); } else { // uts table - single value // add uts entity user.uts (1:1) $uts_entity = Base::getInstance($prev_entity->getNamespace() . 'Uts' . $prev_entity->getName()); $u_entity = $uts_entity; $chain->addElement(new QueryChainElement($prev_entity->getField('UTS_OBJECT'))); // add `value` field $chain->addElement(new QueryChainElement($uts_entity->getField($def_element))); } } elseif (Base::isExists($def_element) && Base::getInstance($def_element)->getReferencesCountTo($prev_entity->getName()) == 1) { // def_element is another entity with only 1 reference to current entity // need to identify Reference field $ref_entity = Base::getInstance($def_element); $field = end($ref_entity->getReferencesTo($prev_entity->getName())); $prev_entity = $ref_entity; $chain->addElement(new QueryChainElement(array($ref_entity, $field))); } elseif (($pos_wh = strpos($def_element, ':')) > 0) { $ref_entity_name = substr($def_element, 0, $pos_wh); if (strpos($ref_entity_name, '\\') === false) { // if reference has no namespace, then it'is in the namespace of previous entity $ref_entity_name = $prev_entity->getNamespace() . $ref_entity_name; } if (Base::isExists($ref_entity_name) && Base::getInstance($ref_entity_name)->hasField($ref_field_name = substr($def_element, $pos_wh + 1)) && Base::getInstance($ref_entity_name)->getField($ref_field_name)->getRefEntity()->getName() == $prev_entity->getName()) { // chain element is another entity with >1 references to current entity // def like NewsArticle:AUTHOR, NewsArticle:LAST_COMMENTER // NewsArticle - entity, AUTHOR and LAST_COMMENTER - Reference fields $chain->addElement(new QueryChainElement(array(Base::getInstance($ref_entity_name), Base::getInstance($ref_entity_name)->getField($ref_field_name)))); $prev_entity = Base::getInstance($ref_entity_name); } else { $not_found = true; } } elseif ($def_element == '*' && $is_last_elem) { continue; } else { // unknown chain $not_found = true; } if ($not_found) { throw new \Exception(sprintf('Unknown field definition `%s` (%s) for %s Entity.', $def_element, $definition, $prev_entity->getName()), 100); } } return $chain; }