Skip to content
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.

Commit

Permalink
Правки по релейшенам (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
MsNatali authored and arrilot committed Feb 21, 2019
1 parent e47441f commit eaeba72
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 77 deletions.
82 changes: 82 additions & 0 deletions src/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace Arrilot\BitrixModels;

use Arrilot\BitrixModels\Models\BaseBitrixModel;
use Illuminate\Support\Collection;

class Helpers
{
/**
Expand All @@ -15,4 +18,83 @@ public static function startsWith($haystack, $needle)
{
return strncmp($haystack, $needle, strlen($needle)) === 0;
}

/**
* @param Collection|BaseBitrixModel[] $primaryModels первичные модели
* @param Collection|BaseBitrixModel[] $relationModels подгруженные связанные модели
* @param string $primaryKey ключ связи в первичной модели
* @param string $relationKey ключ связи в связанной модели
* @param string $relationName название связи в первичной модели
* @param bool $multiple множественная ли это свзязь
*/
public static function assocModels($primaryModels, $relationModels, $primaryKey, $relationKey, $relationName, $multiple)
{
$buckets = static::buildBuckets($relationModels, $relationKey, $multiple);

foreach ($primaryModels as $i => $primaryModel) {
if ($multiple && is_array($keys = $primaryModel[$primaryKey])) {
$value = [];
foreach ($keys as $key) {
$key = static::normalizeModelKey($key);
if (isset($buckets[$key])) {
$value = array_merge($value, $buckets[$key]);
}
}
} else {
$key = static::normalizeModelKey($primaryModel[$primaryKey]);
$value = isset($buckets[$key]) ? $buckets[$key] : ($multiple ? [] : null);
}

$primaryModel->populateRelation($relationName, is_array($value) ? (new Collection($value))->keyBy(function ($item) {return $item->id;}) : $value);
}
}

/**
* Сгруппировать найденные модели
* @param array $models
* @param string $linkKey
* @param bool $multiple
* @return array
*/
protected static function buildBuckets($models, $linkKey, $multiple)
{
$buckets = [];

foreach ($models as $model) {
$key = $model[$linkKey];
if (is_scalar($key)) {
$buckets[$key][] = $model;
} elseif (is_array($key)){
foreach ($key as $k) {
$k = static::normalizeModelKey($k);
$buckets[$k][] = $model;
}
} else {
$key = static::normalizeModelKey($key);
$buckets[$key][] = $model;
}
}

if (!$multiple) {
foreach ($buckets as $i => $bucket) {
$buckets[$i] = reset($bucket);
}
}

return $buckets;
}

/**
* @param mixed $value raw key value.
* @return string normalized key value.
*/
protected static function normalizeModelKey($value)
{
if (is_object($value) && method_exists($value, '__toString')) {
// ensure matching to special objects, which are convertable to string, for cross-DBMS relations, for example: `|MongoId`
$value = $value->__toString();
}

return $value;
}
}
82 changes: 5 additions & 77 deletions src/Queries/BaseRelationQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Arrilot\BitrixModels\Queries;


use Arrilot\BitrixModels\Helpers;
use Arrilot\BitrixModels\Models\BaseBitrixModel;
use Illuminate\Support\Collection;

Expand Down Expand Up @@ -107,6 +108,7 @@ protected function filterByModels($models)
}
}

$values = array_filter($values);
if (empty($values)) {
$this->stopQuery();
}
Expand Down Expand Up @@ -134,7 +136,7 @@ protected function filterByModels($models)
public function findWith($with, &$models)
{
// --- получаем модель, на основании которой будем брать запросы релейшенов
$primaryModel = reset($models);
$primaryModel = $models->first();
if (!$primaryModel instanceof BaseBitrixModel) {
$primaryModel = $this->model;
}
Expand Down Expand Up @@ -195,83 +197,9 @@ public function populateRelation($name, &$primaryModels)
$this->filterByModels($primaryModels);

$models = $this->getList();
$buckets = $this->buildBuckets($models, $this->localKey);

foreach ($primaryModels as $i => $primaryModel) {
if ($this->multiple && is_array($keys = $primaryModel[$this->foreignKey])) {
$value = [];
foreach ($keys as $key) {
$key = $this->normalizeModelKey($key);
if (isset($buckets[$key])) {
$value = array_merge($value, $buckets[$key]);
}
}
} else {
$key = $this->getModelKey($primaryModel, $this->foreignKey);
$value = isset($buckets[$key]) ? $buckets[$key] : ($this->multiple ? [] : null);
}

$primaryModel->populateRelation($name, is_array($value) ? (new Collection($value))->keyBy(function ($item) {return $item->id;}) : $value);
}

Helpers::assocModels($primaryModels, $models, $this->foreignKey, $this->localKey, $name, $this->multiple);

return $models;
}

/**
* Сгруппировать найденные модели
* @param array $models
* @param array|string $linkKeys
* @param bool $checkMultiple
* @return array
*/
private function buildBuckets($models, $linkKeys, $checkMultiple = true)
{
$buckets = [];

foreach ($models as $model) {
$key = $this->getModelKey($model, $linkKeys);
$buckets[$key][] = $model;
}

if ($checkMultiple && !$this->multiple) {
foreach ($buckets as $i => $bucket) {
$buckets[$i] = reset($bucket);
}
}

return $buckets;
}

/**
* Получить значение атрибутов в виде строки
* @param BaseBitrixModel $model
* @param array|string $attributes
* @return string
*/
private function getModelKey($model, $attributes)
{
$key = [];
foreach ((array)$attributes as $attribute) {
$key[] = $this->normalizeModelKey($model[$attribute]);
}
if (count($key) > 1) {
return serialize($key);
}
$key = reset($key);
return is_scalar($key) ? $key : serialize($key);
}

/**
* @param mixed $value raw key value.
* @return string normalized key value.
*/
private function normalizeModelKey($value)
{
if (is_object($value) && method_exists($value, '__toString')) {
// ensure matching to special objects, which are convertable to string, for cross-DBMS relations, for example: `|MongoId`
$value = $value->__toString();
}

return $value;
}
}

0 comments on commit eaeba72

Please sign in to comment.