Find a related recordset.

@param Garp_Model $model The model that spawned this data
@param Garp_Db_Row $row The row object
@param Garp_Util_Configuration $options Various relation options
@return string The name of the method.
516916
protected function _getRelatedRowset(
        Garp_Model $model, Garp_Db_Table_Row $row, Garp_Util_Configuration $options
    ) {
        /**
         * An optional passed SELECT object will be passed by reference after every query.
         * This results in an error when 'clone' is not used, because correlation names will be
         * used twice (since they were set during the first iteration). Using 'clone' makes sure
         * a brand new SELECT object is used every time that hasn't been soiled by a possible
         * previous query.
         */
        $conditions = is_null($options['conditions']) ? null : clone $options['conditions'];
        $otherModel = $options['modelClass'];
        if (!$otherModel instanceof Zend_Db_Table_Abstract) {
            $otherModel = new $otherModel();
        }
        // Bound models should respect the CMS context settings of the root model
        $otherModel->setCmsContext($model->isCmsContext());
        /**
         * Do not cache related queries. The "outside" query should be the only
         * query that's cached.
         */
        $originalCacheQueriesFlag = $otherModel->getCacheQueries();
        $otherModel->setCacheQueries(false);
        $modelName = get_class($otherModel);
        $relatedRowset = null;

        // many to many
        if (!empty($options['bindingModel'])) {
            $relatedRowset = $row->findManyToManyRowset(
                $otherModel,
                $options['bindingModel'],
                $options['rule2'],
                $options['rule'],
                $conditions
            );
        } else {
            /**
             * 'mode' is used to clear ambiguity with homophilic relationships. For example,
             * a Model_Doc can have have child Docs and one parent Doc.
             * The conditionals below can never tell which method to call
             * (findParentRow or findDependentRowset) from the referenceMap.
             *
             * Therefore, we can help the decision-making by passing "mode". This can either be
             * "parent" or "dependent", which will then force a call to
             * findParentRow and findDependentRowset, respectively.
             */
            if (is_null($options['mode'])) {
                // belongs to
                try {
                    $model->getReference($modelName, $options['rule']);
                    $relatedRowset = $row->findParentRow(
                        $otherModel, $options['rule'], $conditions
                    );
                } catch(Exception $e) {
                    if (!Garp_Content_Relation_Manager::isInvalidReferenceException($e)) {
                        throw $e;
                    }
                    try {
                        // one to many - one to one
                        // The following line triggers an exception if no reference is available
                        $otherModel->getReference(get_class($model), $options['rule']);
                        $relatedRowset = $row->findDependentRowset(
                            $otherModel,
                            $options['rule'],
                            $conditions
                        );
                    } catch (Exception $e) {
                        if (!Garp_Content_Relation_Manager::isInvalidReferenceException($e)) {
                            throw $e;
                        }
                        $bindingModel = $model->getBindingModel($modelName);
                        $relatedRowset = $row->findManyToManyRowset(
                            $otherModel,
                            $bindingModel,
                            $options['rule2'],
                            $options['rule'],
                            $conditions
                        );
                    }
                }
            } else {
                switch ($options['mode']) {
                case 'parent':
                    $relatedRowset = $row->findParentRow(
                        $otherModel,
                        $options['rule'],
                        $conditions
                    );
                    break;
                case 'dependent':
                    $relatedRowset = $row->findDependentRowset(
                        $otherModel,
                        $options['rule'],
                        $conditions
                    );
                    break;
                default:
                    throw new Garp_Model_Exception(
                        'Invalid value for "mode" given. Must be either "parent" or ' .
                            '"dependent", but "' . $options['mode'] . '" was given.'
                    );
                    break;
                }
            }
        }
        // Reset the cacheQueries value. It's a static property,
        // so leaving it FALSE will affect all future fetch() calls to this
        // model. Not good.
        $otherModel->setCacheQueries($originalCacheQueriesFlag);
        return $relatedRowset;
    }
1157516
public static function getModelClass($model): string
    {
        if (!isset(self::$modelClassMap[$model])) {
            // try to detect
            $className = '\\Application\\' . $model . '\\Table';

            if (!class_exists($className)) {
                throw new RelationNotFoundException("Related class for model `$model` not found");
            }
            self::$modelClassMap[$model] = $className;
        }
        return self::$modelClassMap[$model];
    }
892650
public function matchRelation($model, $results) {
        $data = [];
        foreach ($results as $item) {
            if (!$this->isMatchRelation($model, $item)) {
                continue;
            }
            if ($this->type == self::TYPE_ONE) {
                return $item;
            }
            $data[] = $item;
        }
        return $data;
    }
744701
protected function getNestedRelation(Model $model, $relationArray)
    {
        $relation = null;
        foreach ($relationArray as $relation) {
            /** @var Relation $relation */
            $relation = $model->newQuery()->getRelation($relation);
            if ($relation) {
                $model = $relation->getRelated();
            }
        }

        return $relation;
    }
775793
protected static function getHasManyRelationField($model, $relation, $activeRelation)
    {
        $widgetOptions = self::getRelationWidgetOptions($model, $relation, $activeRelation, true);
        return static::getRelationWidget($model, $relation, $activeRelation, $widgetOptions);
    }
283924
protected static function getNextIndex(ActiveRecordInterface $row)
    {
        $where = null;
        if ($row->getRoleField('tree-parent')) {
            $where = QueryCriteria::createAND([[$row->getRoleField('tree-parent'), '=', $row->getRoleValue('tree-parent')]]);
        }
        $values = $row::query()->select(['max_sort_value' => QueryExpression::max($row->getRoleField('sort-index'))])
            ->where($where)->execute()->fetch();
        if (!isset($values['max_sort_value'])) $values['max_sort_value'] = 0;
        return intval($values['max_sort_value']) + 1;
    }
1331779
public function urlFieldRow(IFormModel $model, $property, array $options = [])
    {
        $element = $this->getField($model, $property);
        $options['id'] = $element['id'];

        return Html::openTag('div', $this->getBlock('block', $options)).
        Html::label($model->getLabel($property), $element['id'], $this->getBlock('label', $options)).
        $this->urlField($model, $property, $options).
        Html::closeTag('div');
    }
594612
public function findByID($model_or_id, $options=null) {
        $id = $this->extractID($model_or_id);
        return $this->findOne(['id' => $id], null, $options);
    }
22736
public function getCellValue(Model $row, $decorator)
    {
        return \Rhubarb\Crown\String\Template::parseTemplate($this->template, ($decorator != null) ? $decorator : $row);
    }
919139
protected function getRelatedModels(Model $model)
    {
        // Store the class name
        $modelClass = get_class($model);

        // Check if we already know the related models for this model
        if (!isset($this->relatedModels[$modelClass]))
        {
            $relatedModels = [];

            $methods = with(new \ReflectionClass($model))->getMethods();

            // Iterate all class methods
            foreach ($methods as $method)
            {
                // Check if this method returns an Eloquent relation
                if ($method->class == $modelClass &&
                    preg_match('/@return\s+\\\\Illuminate\\\\Database\\\\Eloquent\\\\Relations/', $method->getDocComment())
                )
                {
                    // Get the method name, so that we can call it on the model
                    $relationMethod = $method->name;

                    // Find the relation
                    $relation = $model->$relationMethod();

                    if ($relation instanceof Relation)
                    {
                        // Find the related model
                        $related = $relation->getRelated();

                        // Store the method to help build the inverse path
                        $this->relationClassMethods[$modelClass][get_class($related)] = $relationMethod;

                        $relatedModels[] = ['model' => $related, 'method' => $method];
                    }
                }
            }

            // Cache related models for this model
            $this->relatedModels[$modelClass] = $relatedModels;

            // Return the related models
            return $relatedModels;
        } else
        {
            // Return from cache
            return $this->relatedModels[$modelClass];
        }
    }
797403
public function afterSave(Garp_Model_Db $model, $primaryKey) {
        if (is_array($primaryKey)) {
            throw new Exception(self::ERROR_PRIMARY_KEY_CANNOT_BE_ARRAY);
        }

        $boundModel = new Garp_Service_Elasticsearch_Db_BoundModel($model);
        $row = $boundModel->fetchRow($primaryKey);

        if (!$row) {
            /* This is not supposed to happen,
            but due to concurrency it theoretically might. */
            return;
        }

        if (!$this->getRootable()) {
            /* This record should not appear directly in the index,
            *  but only as related records.
            */
            return;
        }

        $rowFilter          = new Garp_Service_Elasticsearch_Db_RowFilter($model);
        $columns            = $this->getColumns();
        $filteredRow        = $rowFilter->filter($row, $columns);

        $elasticModel       = $this->_getElasticModel($model);
        $pkMash             = $this->_mashPrimaryKey($primaryKey);
        $filteredRow['id']  = $pkMash;

        $elasticModel->save($filteredRow);
    }
618982
public function save(Garp_Model $model, array $mapping, array $options) {
        $excelReader = $this->_getReader();
        $worksheet = $excelReader->getActiveSheet();
        $pks = array();
        $iterator = $worksheet->getRowIterator();
        foreach ($iterator as $i => $row) {
            // workaround cause those PHPExcel assholes start their arrays at index 1
            $n = $i-1;
            if ($n < $options['firstRow']) {
                continue;
            }

            $cellData = array();
            $cellIterator = $row->getCellIterator();
            $cellIterator->setIterateOnlyExistingCells(false);
            foreach ($cellIterator as $j => $cell) {
                $cellData[] = $cell->getValue();
            }
            try {
                // Sanity check: do not insert completely empty rows
                $check = implode('', $cellData);
                $check = trim($check);
                if (!$check) {
                    continue;
                }
                $primaryKey = $this->_insert($model, $cellData, $mapping);
                $pks[] = $primaryKey;
            } catch (Exception $e) {
                if (!$options['ignoreErrors']) {
                    $this->rollback($model, $pks);
                }
                throw $e;
            }
        }
        return true;
    }
748098
public function format(Garp_Model $model, array $rowset) {
        $html = parent::format($model, $rowset);
        $dompdf = new Dompdf\Dompdf();
        $dompdf->load_html($html);
        $dompdf->set_paper('a4', 'portrait');
        $dompdf->render();
        $out = $dompdf->output();
        return $out;
    }
1227694
public function findHighestWeight(Garp_Model $model, $foreignKey, array $modelRelationConfig) {
        $foreignKeyColumn = $model->getAdapter()->quoteIdentifier($modelRelationConfig[self::FOREIGN_KEY_COLUMN_KEY]);
        $weightColumn     = $model->getAdapter()->quoteIdentifier($modelRelationConfig[self::WEIGHT_COLUMN_KEY]);
        $select = $model->select()
                        ->from($model->getName(), array('max' => 'MAX('.$weightColumn.')'))
                        ->where($foreignKeyColumn.' = ?', $foreignKey)
                        ;

        $result = $model->fetchRow($select);
        if ($result && $result->max) {
            return $result->max;
        }
        return 0;
    }
1129553
public function unrelate(array $options) {
        $this->_checkAcl('relate');

        extract($options);
        if (!isset($primaryKey) || !isset($model) || !isset($foreignKeys)) {
            throw new Garp_Content_Exception(
                'Not enough options. "primaryKey", "model" and "foreignKeys" are required.'
            );
        }
        $model         = Garp_Content_Api::modelAliasToClass($model);
        $primaryKey    = (array)$primaryKey;
        $foreignKeys   = (array)$foreignKeys;
        $rule          = isset($rule) ? $rule : null;
        $rule2         = isset($rule2) ? $rule2 : null;
        $bindingModel  = isset($bindingModel) ? 'Model_' . $bindingModel : null;
        $bidirectional = isset($bidirectional) ? $bidirectional : null;

        Garp_Content_Relation_Manager::unrelate(
            array(
                'modelA'        => $this->_model,
                'modelB'        => $model,
                'keyA'          => $primaryKey,
                'keyB'          => $foreignKeys,
                'rule'          => $rule,
                'ruleB'         => $rule2,
                'bindingModel'  => $bindingModel,
                'bidirectional' => $bidirectional,
            )
        );
    }
70668
public static function writeQueryCache(Garp_Model_Db $model, $key, $results) {
        $cache = new Garp_Cache_Store_Versioned($model->getName() . '_version');
        $cache->write($key, $results);
    }
997677
protected function join($row)
    {
        $keys['local']   = $this->keys['local'];
        $keys['foreign'] = $this->keys['foreign'];

        if ($this->relationType == 'hasAndBelongsToMany')
        {
            $join = Database::table($this->getJunction())
                    ->groupBy($this->tables['local'] . '_id')
                    ->where($this->tables['local'] . '_id', '=', $row->{$keys['local']})
                    ->findAll()
                    ->asArray(null, $this->tables['foreign'] . '_id');


            if (empty($join))
                return [];

            return Database::table($this->tables['foreign'])
                            ->where($keys['foreign'], 'IN', $join[$row->{$keys['local']}]);
        }

        return Database::table($this->tables['foreign'])
                        ->where($keys['foreign'], '=', $row->{$keys['local']});
    }