<commit_before><?php
namespace Tenet\Filter;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Util\Debug;
use Tenet\FilterInterface;
use Tenet\Accessor;

class AssociationToManyFilter extends AbstractAssociationFilter implements FilterInterface
{
	/**
	 *
	 */
	public function convertToSetterValue(Accessor $accessor, $object, $field, $value)
	{
		$manager            = $accessor->getObjectManager();
		$objectMetadata     = $manager->getClassMetadata(get_class($object));
		$collection         = $accessor->get($object, $field);
		$incomingCollection = new ArrayCollection();

		// very helpful:
		// http://doctrine-orm.readthedocs.org/en/latest/reference/unitofwork-associations.html

		if ($value) {
			$values = !is_array($value)
				? array($value)
				: $value;

			foreach($values as $key => $value) {
				$incomingCollection->add($this->makeObject($accessor, $object, $field, $value));
			}
		}

		$isInverse   = $objectMetadata->isAssociationInverseSide($field);
		$mappedField = $objectMetadata->getAssociationMappedByTargetField($field);

		foreach($collection as $i => $relatedObject) {
			if (!$incomingCollection->contains($relatedObject)) {
				$collection->remove($i);

				if ($isInverse) {
					$accessor->set($relatedObject, $mappedField, NULL);
				}
			}
		}

		return $incomingCollection;
	}

<commit_msg>Bi-directional self-referencing many-to-many fixes (hopefully with no regressions)<commit_after><?php
namespace Tenet\Filter;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Util\Debug;
use Tenet\FilterInterface;
use Tenet\Accessor;

class AssociationToManyFilter extends AbstractAssociationFilter implements FilterInterface
{
	/**
	 *
	 */
	public function convertToSetterValue(Accessor $accessor, $object, $field, $value)
	{
		$manager            = $accessor->getObjectManager();
		$objectMetadata     = $manager->getClassMetadata(get_class($object));
		$collection         = $accessor->get($object, $field);
		$incomingCollection = new ArrayCollection();

		// very helpful:
		// http://doctrine-orm.readthedocs.org/en/latest/reference/unitofwork-associations.html

		$isInverse   = $objectMetadata->isAssociationInverseSide($field);
		$mappedField = $objectMetadata->getAssociationMappedByTargetField($field);
		$mappedClass = $objectMetadata->getAssociationTargetClass($field);

		if ($value) {
			$values = !is_array($value)
				? array($value)
				: $value;

			foreach ($values as $key => $value) {
				$relatedObject = $this->makeObject($accessor, $object, $field, $value);

				if ($mappedField) {
					$inverse = $accessor->get($relatedObject, $mappedField);

					if ($inverse instanceof Collection) {
						//
						// Handle bi-directional
						//
						if (!$inverse->contains($object)) {
							$inverse->add($object);
						}

						//
						// Handle self referencing bi-directional
						//
						if ($mappedClass == get_class($object)) {
							$peer = $accessor->get($object, $mappedField);

							if (!$peer->contains($relatedObject)) {
								$peer->add($relatedObject);
							}
						}
					}
				}

				$incomingCollection->add($relatedObject);
			}
		}

		foreach ($collection as $i => $relatedObject) {
			if (!$incomingCollection->contains($relatedObject)) {
				if ($mappedField) {
					$inverse = $accessor->get($relatedObject, $mappedField);

					if ($inverse instanceof Collection) {
						//
						// Handle bi-directional
						//
						if ($inverse->contains($object)) {
							$inverse->removeElement($object);
						}

						//
						// Handle self referencing bi-directional
						//
						if ($mappedClass == get_class($object)) {
							$peer = $accessor->get($object, $mappedField);

							if ($peer->contains($relatedObject)) {
								$peer->removeElement($relatedObject);
							}
						}
					} else {
						$accessor->set($relatedObject, $mappedField, NULL);
					}
				}
			}
		}

		return $incomingCollection;
	}


{'fraction_non_alphanumeric': 0.14672293942403178, 'fraction_numerical': 0.0, 'mean_word_length': 3.481646273637375, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2123909', 'n_tokens_mistral': 1521, 'n_tokens_neox': 1193, 'n_words': 207}