private function addToOrRemoveFrom($action, $name, $arg)
{
if ($this->isDetached()) {
throw new InvalidMethodCallException('Cannot add or remove related entity to detached entity.');
}
if ($arg === null) {
throw new InvalidArgumentException('Invalid argument given in entity ' . get_called_class() . '.');
}
if (is_array($arg) or $arg instanceof Traversable and !$arg instanceof Entity) {
foreach ($arg as $value) {
$this->addToOrRemoveFrom($action, $name, $value);
}
} else {
$method = $action === self::ACTION_ADD ? 'addTo' : 'removeFrom';
$property = $this->getCurrentReflection()->getEntityProperty($name);
if ($property === null or !$property->hasRelationship() or !$property->getRelationship() instanceof Relationship\HasMany) {
throw new InvalidMethodCallException("Cannot call {$method} method with '{$name}' property in entity " . get_called_class() . '. Only properties with m:hasMany relationship can be managed this way.');
}
if ($property->getFilters()) {
throw new InvalidMethodCallException("Cannot call {$method} method with '{$name}' property in entity " . get_called_class() . '. Only properties without filters can be managed this way.');
// deliberate restriction
}
$relationship = $property->getRelationship();
if ($arg instanceof Entity) {
if ($arg->isDetached()) {
throw new InvalidArgumentException('Cannot add or remove detached entity ' . get_class($arg) . " to {$name} in entity " . get_called_class() . '.');
}
$type = $property->getType();
if (!$arg instanceof $type) {
$type = gettype($arg) !== 'object' ? gettype($arg) : 'instance of ' . get_class($arg);
throw new InvalidValueException("Unexpected value type given in property '{$property->getName()}' in entity " . get_called_class() . ", {$property->getType()} expected, {$type} given.");
}
$data = $arg->getRowData();
$arg = $data[$this->mapper->getPrimaryKey($relationship->getTargetTable())];
}
$table = $this->mapper->getTable($this->getCurrentReflection()->getName());
$values = [$relationship->getColumnReferencingSourceTable() => $this->row->{$this->mapper->getPrimaryKey($table)}, $relationship->getColumnReferencingTargetTable() => $arg];
$method .= 'Referencing';
$this->row->{$method}($values, $relationship->getRelationshipTable(), $relationship->getColumnReferencingSourceTable(), null, $relationship->getStrategy());
}
}