Cascades the delete operation to associated entities.

@param object   $entity
@param object[] $visited
505365
private function cascadeRemove($entity, array &$visited)
    {
        $entitiesToCascade = [];
        $class             = $this->em->getClassMetadata(get_class($entity));

        foreach ($class->getDeclaredPropertiesIterator() as $association) {
            if (! ($association instanceof AssociationMetadata && in_array('remove', $association->getCascade(), true))) {
                continue;
            }

            if ($entity instanceof GhostObjectInterface && ! $entity->isProxyInitialized()) {
                $entity->initializeProxy();
            }

            $relatedEntities = $association->getValue($entity);

            switch (true) {
                case $relatedEntities instanceof Collection:
                case is_array($relatedEntities):
                    // If its a PersistentCollection initialization is intended! No unwrap!
                    foreach ($relatedEntities as $relatedEntity) {
                        $entitiesToCascade[] = $relatedEntity;
                    }
                    break;

                case $relatedEntities !== null:
                    $entitiesToCascade[] = $relatedEntities;
                    break;

                default:
                    // Do nothing
            }
        }

        foreach ($entitiesToCascade as $relatedEntity) {
            $this->doRemove($relatedEntity, $visited);
        }
    }
202655
public function remove(EntityRemoved $event)
    {
        $entity = $event->getEntity();
        $collection = $event->getCollection();
        $this->deleteRelation($entity, $collection);
    }
949451
private function doDetach($xmlEntity, array &$visited)
    {
        $oid = spl_object_hash($xmlEntity);
        if (isset($visited[$oid])) {
            return; // Prevent infinite recursion
        }

        $visited[$oid] = $xmlEntity; // mark visited

        switch ($this->getXmlEntityState($xmlEntity, self::STATE_DETACHED)) {
            case self::STATE_MANAGED:
                $this->removeFromIdentityMap($xmlEntity);
                unset($this->entityIdentifiers[$oid], $this->entityUpdates[$oid],
                        $this->entityDeletions[$oid], $this->entityIdentifiers[$oid],
                        $this->entityStates[$oid], $this->originalEntityData[$oid]);
                break;
            case self::STATE_NEW:
            case self::STATE_DETACHED:
                return;
        }

        //$this->cascadeDetach($document, $visited);
    }
828301
@Override
	public void delete(Object entity) {
		if (entity == null) {
			throw new IllegalArgumentException("'entity' must not be [" + entity + "]");
		}
		
		assertTransactional();
		List<Log> logs = transaction.get().logs();
		
		if (logs.isEmpty()) {
			throw new IllegalStateException("Log ["
					+ Log.Operation.DELETE
					+ "] is not allowed: previous operation must be ["
					+ Log.Operation.GET + "]");
		}
		
		for (int i = logs.size() - 1; i >= 0; i--) {
			Log log = logs.get(i);
			
			if (keyValue(entity).equals(keyValue(log.entity()))) {
				if (log.operation() == Log.Operation.GET) {
					break;
				} else {
					throw new IllegalStateException("Log [" + log.operation() 
							+ "] -> [" + Log.Operation.DELETE
							+ "] is not allowed: previous operation must be ["
							+ Log.Operation.GET + "]");
				}
			}
		}
		
		Transaction tx = transaction.get().transaction();
		List<Key> keys = new ArrayList<Key>();
		
		for (Entity e : Translation.toEntities(entity)) {
			keys.add(e.getKey());
		}
		
		datastore.delete(tx, keys);
		Log log = new Log(logs.size() + 1, Log.Operation.DELETE, entity);
		log.state(State.UNCOMMITTED);
		logs.add(log);
	}
144108
public function remove(Entity $entity) {
    if (method_exists($entity,'remove')) {
      $entity->remove();
    }
    $this->_em->remove($entity);
    
    return $this;
  }
1346392
@Transactional
    public void delete(E entity) {
        if (entityManager.contains(entity)) {
            entityManager.remove(entity);
        } else {
            // could be a delete on a transient instance
            E entityRef = entityManager.getReference(type, entity.getId());

            if (entityRef != null) {
                entityManager.remove(entityRef);
            } else {
                log.warning("Attempt to delete an instance that is not present in the database: " + entity);
            }
        }
    }
747980
private function doRefresh($entity, array &$visited)
    {
        $oid = spl_object_hash($entity);

        if (isset($visited[$oid])) {
            return; // Prevent infinite recursion
        }

        $visited[$oid] = $entity; // mark visited

        if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
            throw OGMInvalidArgumentException::entityNotManaged($entity);
        }

        $this->getPersister(get_class($entity))->refresh($this->entityIds[$oid], $entity);

        $this->cascadeRefresh($entity, $visited);
    }
1297247
protected function _resetrelationships($entity)
    {
        $entities = clone $entity->getRepository()->getSpace()->getEntities();

        //reset all the entities that have a belongs to or one to one relationship
        //with the $entity. Because since $entity is not being saved
        //nor should any child that requires the parent $entity value 
        foreach ($entities as $child) {
            if ($child->eql($entity)) {
                continue;
            }

            $relationships = $child->getEntityDescription()->getRelationships();

            foreach ($relationships as $relationship) {
                //child has a one to one or belongs to relationship to the entity (parent) 
                if ($relationship->isOneToOne() || $relationship->isManyToOne()) {
                    $value = $child->get($relationship->getName());

                    if ($entity->eql($value)) {
                        $child->reset();
                    }
                }
            }
        }
    }
24512
public function handle(Entity $entity)
    {
        // We will initially check if the model is using soft deletes. If so,
        // the attribute values will remain untouched as they should sill
        // be available till the entity is truly deleted from database.
        if (in_array(SoftDeletes::class, class_uses_recursive(get_class($entity))) && ! $entity->isForceDeleting()) {
            return;
        }

        foreach ($entity->getEntityAttributes() as $attribute) {
            if ($entity->relationLoaded($relation = $attribute->getAttribute('slug'))
                && ($values = $entity->getRelationValue($relation)) && ! $values->isEmpty()) {
                // Calling the `destroy` method from the given $type model class name
                // will finally delete the records from database if any was found.
                // We'll just provide an array containing the ids to be deleted.
                forward_static_call_array([$attribute->getAttribute('type'), 'destroy'], [$values->pluck('id')->toArray()]);
            }
        }
    }
749466
public function deleteEntity(EntityInterface $entity)
    {
        $delete = $this->tableGateway->getSql()->delete();
        $delete->where->equalTo(
            $this->tableGateway->getPrimaryKey(), $entity->getIdentifier()
        );

        try {
            $this->tableGateway->deleteWith($delete);
        } catch (RuntimeException $e) {
            return false;
        }

        return true;
    }
305449
private function cascadePersist(object $document, array &$visited) : void
    {
        $class = $this->dm->getClassMetadata(get_class($document));

        $associationMappings = array_filter(
            $class->associationMappings,
            static function ($assoc) {
                return $assoc['isCascadePersist'];
            }
        );

        foreach ($associationMappings as $fieldName => $mapping) {
            $relatedDocuments = $class->reflFields[$fieldName]->getValue($document);

            if ($relatedDocuments instanceof Collection || is_array($relatedDocuments)) {
                if ($relatedDocuments instanceof PersistentCollectionInterface) {
                    if ($relatedDocuments->getOwner() !== $document) {
                        $relatedDocuments = $this->fixPersistentCollectionOwnership($relatedDocuments, $document, $class, $mapping['fieldName']);
                    }
                    // Unwrap so that foreach() does not initialize
                    $relatedDocuments = $relatedDocuments->unwrap();
                }

                $count = 0;
                foreach ($relatedDocuments as $relatedKey => $relatedDocument) {
                    if (! empty($mapping['embedded'])) {
                        [, $knownParent ] = $this->getParentAssociation($relatedDocument);
                        if ($knownParent && $knownParent !== $document) {
                            $relatedDocument               = clone $relatedDocument;
                            $relatedDocuments[$relatedKey] = $relatedDocument;
                        }
                        $pathKey = CollectionHelper::isList($mapping['strategy']) ? $count++ : $relatedKey;
                        $this->setParentAssociation($relatedDocument, $mapping, $document, $mapping['fieldName'] . '.' . $pathKey);
                    }
                    $this->doPersist($relatedDocument, $visited);
                }
            } elseif ($relatedDocuments !== null) {
                if (! empty($mapping['embedded'])) {
                    [, $knownParent ] = $this->getParentAssociation($relatedDocuments);
                    if ($knownParent && $knownParent !== $document) {
                        $relatedDocuments = clone $relatedDocuments;
                        $class->setFieldValue($document, $mapping['fieldName'], $relatedDocuments);
                    }
                    $this->setParentAssociation($relatedDocuments, $mapping, $document, $mapping['fieldName']);
                }
                $this->doPersist($relatedDocuments, $visited);
            }
        }
    }
530216
public function clear($entity)
    {
        /**
         * @var ObjectManager $objectManager
         */
        $objectManager = $this
            ->get('elcodi.provider.manager')
            ->getManagerByEntityNamespace(get_class($entity));

        $objectManager->clear($entity);

        return $this;
    }
1174279
private function doMerge(object $document, array &$visited, ?object $prevManagedCopy = null, ?array $assoc = null) : object
    {
        $oid = spl_object_hash($document);

        if (isset($visited[$oid])) {
            return $visited[$oid]; // Prevent infinite recursion
        }

        $visited[$oid] = $document; // mark visited

        $class = $this->dm->getClassMetadata(get_class($document));

        /* First we assume DETACHED, although it can still be NEW but we can
         * avoid an extra DB round trip this way. If it is not MANAGED but has
         * an identity, we need to fetch it from the DB anyway in order to
         * merge. MANAGED documents are ignored by the merge operation.
         */
        $managedCopy = $document;

        if ($this->getDocumentState($document, self::STATE_DETACHED) !== self::STATE_MANAGED) {
            if ($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()) {
                $document->initializeProxy();
            }

            $identifier = $class->getIdentifier();
            // We always have one element in the identifier array but it might be null
            $id          = $identifier[0] !== null ? $class->getIdentifierObject($document) : null;
            $managedCopy = null;

            // Try to fetch document from the database
            if (! $class->isEmbeddedDocument && $id !== null) {
                $managedCopy = $this->dm->find($class->name, $id);

                // Managed copy may be removed in which case we can't merge
                if ($managedCopy && $this->getDocumentState($managedCopy) === self::STATE_REMOVED) {
                    throw new InvalidArgumentException('Removed entity detected during merge. Cannot merge with a removed entity.');
                }

                if ($managedCopy instanceof GhostObjectInterface && ! $managedCopy->isProxyInitialized()) {
                    $managedCopy->initializeProxy();
                }
            }

            if ($managedCopy === null) {
                // Create a new managed instance
                $managedCopy = $class->newInstance();
                if ($id !== null) {
                    $class->setIdentifierValue($managedCopy, $id);
                }
                $this->persistNew($class, $managedCopy);
            }

            if ($class->isVersioned) {
                $managedCopyVersion = $class->reflFields[$class->versionField]->getValue($managedCopy);
                $documentVersion    = $class->reflFields[$class->versionField]->getValue($document);

                // Throw exception if versions don't match
                if ($managedCopyVersion !== $documentVersion) {
                    throw LockException::lockFailedVersionMissmatch($document, $documentVersion, $managedCopyVersion);
                }
            }

            // Merge state of $document into existing (managed) document
            foreach ($class->reflClass->getProperties() as $prop) {
                $name = $prop->name;
                $prop->setAccessible(true);
                if (! isset($class->associationMappings[$name])) {
                    if (! $class->isIdentifier($name)) {
                        $prop->setValue($managedCopy, $prop->getValue($document));
                    }
                } else {
                    $assoc2 = $class->associationMappings[$name];

                    if ($assoc2['type'] === 'one') {
                        $other = $prop->getValue($document);

                        if ($other === null) {
                            $prop->setValue($managedCopy, null);
                        } elseif ($other instanceof GhostObjectInterface && ! $other->isProxyInitialized()) {
                            // Do not merge fields marked lazy that have not been fetched
                            continue;
                        } elseif (! $assoc2['isCascadeMerge']) {
                            if ($this->getDocumentState($other) === self::STATE_DETACHED) {
                                $targetDocument = $assoc2['targetDocument'] ?? get_class($other);
                                /** @var ClassMetadata $targetClass */
                                $targetClass = $this->dm->getClassMetadata($targetDocument);
                                $relatedId   = $targetClass->getIdentifierObject($other);

                                if ($targetClass->subClasses) {
                                    $other = $this->dm->find($targetClass->name, $relatedId);
                                } else {
                                    $other = $this
                                        ->dm
                                        ->getProxyFactory()
                                        ->getProxy($targetClass, $relatedId);
                                    $this->registerManaged($other, $relatedId, []);
                                }
                            }

                            $prop->setValue($managedCopy, $other);
                        }
                    } else {
                        $mergeCol = $prop->getValue($document);

                        if ($mergeCol instanceof PersistentCollectionInterface && ! $mergeCol->isInitialized() && ! $assoc2['isCascadeMerge']) {
                            /* Do not merge fields marked lazy that have not
                             * been fetched. Keep the lazy persistent collection
                             * of the managed copy.
                             */
                            continue;
                        }

                        $managedCol = $prop->getValue($managedCopy);

                        if (! $managedCol) {
                            $managedCol = $this->dm->getConfiguration()->getPersistentCollectionFactory()->create($this->dm, $assoc2, null);
                            $managedCol->setOwner($managedCopy, $assoc2);
                            $prop->setValue($managedCopy, $managedCol);
                            $this->originalDocumentData[$oid][$name] = $managedCol;
                        }

                        /* Note: do not process association's target documents.
                         * They will be handled during the cascade. Initialize
                         * and, if necessary, clear $managedCol for now.
                         */
                        if ($assoc2['isCascadeMerge']) {
                            $managedCol->initialize();

                            // If $managedCol differs from the merged collection, clear and set dirty
                            if (! $managedCol->isEmpty() && $managedCol !== $mergeCol) {
                                $managedCol->unwrap()->clear();
                                $managedCol->setDirty(true);

                                if ($assoc2['isOwningSide'] && $class->isChangeTrackingNotify()) {
                                    $this->scheduleForSynchronization($managedCopy);
                                }
                            }
                        }
                    }
                }

                if (! $class->isChangeTrackingNotify()) {
                    continue;
                }

                // Just treat all properties as changed, there is no other choice.
                $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy));
            }

            if ($class->isChangeTrackingDeferredExplicit()) {
                $this->scheduleForSynchronization($document);
            }
        }

        if ($prevManagedCopy !== null) {
            $assocField = $assoc['fieldName'];
            $prevClass  = $this->dm->getClassMetadata(get_class($prevManagedCopy));

            if ($assoc['type'] === 'one') {
                $prevClass->reflFields[$assocField]->setValue($prevManagedCopy, $managedCopy);
            } else {
                $prevClass->reflFields[$assocField]->getValue($prevManagedCopy)->add($managedCopy);

                if ($assoc['type'] === 'many' && isset($assoc['mappedBy'])) {
                    $class->reflFields[$assoc['mappedBy']]->setValue($managedCopy, $prevManagedCopy);
                }
            }
        }

        // Mark the managed copy visited as well
        $visited[spl_object_hash($managedCopy)] = $managedCopy;

        $this->cascadeMerge($document, $managedCopy, $visited);

        return $managedCopy;
    }
1115769
public function remove($entity)
    {
        if ($this->evm->hasListeners(Events::preRemove)) {
            $this->evm->dispatchEvent(Events::preRemove, new Event\LifecycleEventArgs($entity, $this->sm));
        }

        $oid = spl_object_hash($entity);
        $this->scheduledForDelete[$oid] = $entity;

        if ($this->evm->hasListeners(Events::postRemove)) {
            $this->evm->dispatchEvent(Events::postRemove, new Event\LifecycleEventArgs($entity, $this->sm));
        }
    }
334915
private function cascadeRemove($document, array &$visited)
    {
        $class = $this->dm->getClassMetadata(get_class($document));
        foreach ($class->propertyMetadata as $mapping) {
            if (!$mapping->isCascadeRemove && !$mapping->orphanRemoval) {
                continue;
            }

            if ($document instanceof Proxy && !$document->__isInitialized__) {
                $document->__load();
            }

            $relatedDocuments = $class->getPropertyMetadata($mapping->name)->getValue($document);
            if ($relatedDocuments instanceof Collection || is_array($relatedDocuments)) {
                // If its a PersistentCollection initialization is intended! No unwrap!
                foreach ($relatedDocuments as $relatedDocument) {
                    $this->doRemove($relatedDocument, $visited);
                }
            } elseif ($relatedDocuments !== null) {
                $this->doRemove($relatedDocuments, $visited);
            }
        }
    }
1126971
public function delete($id, $cascade = false) {
        
        // remove has one
        if (isset($this->one[$id])) {
            // iterate through all data
            foreach ($this->one[$id] as $class => $foreignId) {
                $object = $class::getInstance();
                // remove entry in many
                if (null !== ($key = array_search($id, $object->many[$foreignId][$this->class]))) {
                    unset($object->many[$foreignId][$this->class][$key]);
                    self::$dirty[$class] = true;
                }
            }
            unset($this->one[$id]);
        }
        
        // remove has many
        if (isset($this->many[$id])) {
            // iterate through many
            foreach ($this->many[$id] as $class => $foreignIds) {
                $object = $class::getInstance();
                if ($cascade) {
                    // delete objects
                    foreach ($foreignIds as $foreignId) {
                        $object->delete($foreignId, $cascade);
                    }
                } else {
                    // 'only' unset
                    foreach ($foreignIds as $foreignId) {
                        unset($object->one[$foreignId][$this->class][$id]);
                    }
                }
                self::$dirty[$class] = true;
            }
            unset($this->many[$id]);
        }
        
        // unset element
        unset($this->data[$id]);
        self::$dirty[$this->class] = true;
    }
1173170
private function cascadePersist($document, array &$visited)
    {
        $class = $this->dm->getClassMetadata(get_class($document));

        foreach ($class->associationMappings as $fieldName => $mapping) {
            if ( ! $mapping['isCascadePersist']) {
                continue;
            }

            $relatedDocuments = $class->reflFields[$fieldName]->getValue($document);

            if ($relatedDocuments instanceof Collection || is_array($relatedDocuments)) {
                if ($relatedDocuments instanceof PersistentCollection) {
                    // Unwrap so that foreach() does not initialize
                    $relatedDocuments = $relatedDocuments->unwrap();
                }

                foreach ($relatedDocuments as $relatedDocument) {
                    $this->doPersist($relatedDocument, $visited);
                }
            } elseif ($relatedDocuments !== null) {
                $this->doPersist($relatedDocuments, $visited);
            }
        }
    }