Поиск Symfony4 в PersistentCollection

Я борюсь со своим Symfony PersistentCollection - в наборе результатов запроса findByOne(), выполненного в репозитории. Мне нужно найти один или несколько элементов по определенному значению в PersistentCollection, то есть в другом объекте, который имеет отношение к другому.

У меня есть сущность RuleSet, связанная с сущностью SrcFile. В RuleSetRepository я вызываю метод findOneBy(['id' => 1), чтобы найти RuleSet ID=1. Это возвращает объект RuleSet, который имеет srcFiles: PersistentCollection.

Теперь мне нужно получить конкретный объект из этой коллекции. Я знаю, что есть метод getIterator() Я могу перебрать весь результат в коллекции и поставить условие, чтобы найти, где file.kind == 'master', но...

Есть ли лучший способ доступа/нахождения/поиска в PersistentCollection с использованием встроенного метода?

//...
// dump of acctual result of 
dump($grsr->findOneBy(['id' => 1)]);

// dumped data (shortened version):
ProfileUController.php on line 118:
RuleSet {#1509 ▼
  -id: 1
  -srcFiles: PersistentCollection {#1507 ▼
    -snapshot: array:5 [ …5]
    -owner: RuleSet {#1509}
    -association: array:15 [ …15]
    -em: EntityManager {#975 …11}
    -backRefFieldName: "ruleset"
    -typeClass: ClassMetadata {#1230 …}
    -isDirty: false
    #collection: ArrayCollection {#1481 ▼
      -elements: array:5 [▼
        0 => SrcFile {#1573 ▶}
        1 => SrcFile {#1734 ▶}
        //...
      ]
    }
    #initialized: true
  }
}

Я думаю, что самый простой способ - это собственный метод репозитория для этого.

Fabian Schmick 14.06.2019 16:38
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
0
1
925
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

То, что вы ищете, это Доктрина Criteria, который позволяет вам фильтровать Collection. Он достаточно умен, чтобы фильтровать на уровне базы данных, если объекты коллекции еще не находятся в памяти.

Вот краткий пример:

$ruleSet = $grsr->findOneBy(['id' => 1]);
$criteria = Criteria::create();
// Criteria to find SrcFiles where kind = 'master'
$criteria->where(Criteria::expr()->eq('kind', 'master');
// return only the srcFiles matching criteria
$ruleSet->srcFiles->matching($criteria);

Я предпочитаю создавать вспомогательные методы для своей сущности, так как считаю, что это немного чище. Это зависит от вас, но я бы сделал что-то подобное с сущностью RuleSet:

public function getMasterFiles()
{
    $criteria = Criteria::create();
    $criteria->where(Criteria::expr()->eq('kind', 'master'));
    // assuming you have a getter named getSrcFiles for the srcFiles association
    return $this->getSrcFiles()->matching($criteria);
}

Затем вы можете сделать что-то вроде этого (и вам не нужно дублировать код каждый раз, когда нам нужны мастер-файлы):

$ruleSet = $grsr->findOneBy(['id' => 1]);
$ruleSet->getMasterFiles();

Обновлять

Если вам нужно отфильтровать вложенные коллекции, вы должны использовать метод filter:

public function getMasterFiles()
{
    return $this->getSrcFiles()->filter(function(SrcFile $srcFile) {
        // if callback returns true, then object is included in result
        return ($srcFile->getKind() === 'master' && $srcFile->getSrcSheet()->getName() === 'MainData');
    });
}

Метод filter более гибкий, но он всегда применяется к объектам после их извлечения из базы данных. Обычно это не имеет большого значения, но может повлиять на производительность. Другой вариант — пользовательский метод репозитория, но я предпочитаю использовать вспомогательные методы для сущностей. Мне он кажется более ORMish.

Идеально! Это то, что я ищу. Еще один вопрос - я не упомянул об этом в своем исходном сообщении, чтобы сделать его максимально простым, но srcFiles, соответствующие критериям, имеют свою собственную коллекцию с именем srcSheets. Как связать запрос, чтобы найти файл expr()->eq('kind', 'master') с srcSheet ...expr()->eq('name', 'MainData')?

ino 14.06.2019 17:56

Это становится более сложным. Criteria поддерживает только свойства непосредственно в ассоциации, поэтому вы не можете фильтровать вложенные ассоциации. Для этого нужно использовать функцию filter, которая отлично работает, но не будет фильтровать на уровне SQL, поэтому загружает все объекты в память и фильтрует в PHP. Я обновлю свой ответ примером.

patrick3853 14.06.2019 18:09

Отлично, это то, на чем я могу основываться. Большое спасибо.

ino 14.06.2019 18:34

Нет проблем, рад, что смог помочь!

patrick3853 14.06.2019 18:37

отсутствует закрытие ) в $criteria->where(Criteria::expr()->eq('kind', 'master');, не могли бы вы исправить. Я не могу сохранить правки, содержащие изменение только одной буквы...

caramba 25.04.2020 11:39

Другие вопросы по теме