Saltar al contenido

Sincronizar una relación de uno a varios en Laravel

Encontramos el hallazgo a esta obstáculo, al menos eso deseamos. Si tienes dudas dínoslo, que para nosotros será un placer responderte

Solución:

Desafortunadamente no hay sync método para relaciones de uno a varios. Es bastante sencillo hacerlo tú mismo. Al menos si no tienes ningún extranjero key referenciando links. Porque entonces puede simplemente eliminar las filas e insertarlas todas de nuevo.

$links = array(
    new Link(),
    new Link()
);

$post->links()->delete();
$post->links()->saveMany($links);

Si realmente necesita actualizar uno existente (por cualquier motivo), debe hacer exactamente lo que describió en su pregunta.

El problema de eliminar y leer las entidades relacionadas es que romperá cualquier key restricciones que pueda tener en esas entidades secundarias.

Una mejor solución es modificar Laravel’s HasMany relación para incluir un sync método:

 [], 'deleted' => [], 'updated' => [],
        ];

        $relatedKeyName = $this->related->getKeyName();

        // First we need to attach any of the associated models that are not currently
        // in the child entity table. We'll spin through the given IDs, checking to see
        // if they exist in the array of current ones, and if not we will insert.
        $current = $this->newQuery()->pluck(
            $relatedKeyName
        )->all();
    
        // Separate the submitted data into "update" and "new"
        $updateRows = [];
        $newRows = [];
        foreach ($data as $row) 
            // We determine "updateable" rows as those whose $relatedKeyName (usually 'id') is set, not empty, and
            // match a related row in the database.
            if (isset($row[$relatedKeyName]) && !empty($row[$relatedKeyName]) && in_array($row[$relatedKeyName], $current)) 
                $id = $row[$relatedKeyName];
                $updateRows[$id] = $row;
             else 
                $newRows[] = $row;
            
        

        // Next, we'll determine the rows in the database that aren't in the "update" list.
        // These rows will be scheduled for deletion.  Again, we determine based on the relatedKeyName (typically 'id').
        $updateIds = array_keys($updateRows);
        $deleteIds = [];
        foreach ($current as $currentId) 
            if (!in_array($currentId, $updateIds)) 
                $deleteIds[] = $currentId;
            
        

        // Delete any non-matching rows
        if ($deleting && count($deleteIds) > 0) 
            $this->getRelated()->destroy($deleteIds);    
        

        $changes['deleted'] = $this->castKeys($deleteIds);

        // Update the updatable rows
        foreach ($updateRows as $id => $row) 
            $this->getRelated()->where($relatedKeyName, $id)
                 ->update($row);
        
        
        $changes['updated'] = $this->castKeys($updateIds);

        // Insert the new rows
        $newIds = [];
        foreach ($newRows as $row) 
            $newModel = $this->create($row);
            $newIds[] = $newModel->$relatedKeyName;
        

        $changes['created'] = $this->castKeys($newIds);

        return $changes;
    


    /**
     * Cast the given keys to integers if they are numeric and string otherwise.
     *
     * @param  array  $keys
     * @return array
     */
    protected function castKeys(array $keys)
    
        return (array) array_map(function ($v) 
            return $this->castKey($v);
        , $keys);
    
    
    /**
     * Cast the given key to an integer if it is numeric.
     *
     * @param  mixed  $key
     * @return mixed
     */
    protected function castKey($key)
    
        return is_numeric($key) ? (int) $key : (string) $key;
    

Puede anular el de Eloquent Model clase para usar HasManySyncable en lugar del estándar HasMany relación:

newRelatedInstance($related);

        $foreignKey = $foreignKey ?: $this->getForeignKey();

        $localKey = $localKey ?: $this->getKeyName();

        return new HasManySyncable(
            $instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey
        );
    

Suponiendo que tu Post el modelo se extiende MyBaseModel y tiene un links()hasMany relación, puedes hacer algo como:

$post->links()->sync([
    [
        'id' => 21,
        'name' => "LinkedIn profile"
    ],
    [
        'id' => null,
        'label' => "Personal website"
    ]
]);

Cualquier registro en este multidimensional array que tienen un id que coincide con la tabla de la entidad secundaria (links) será actualizado. Registros en la tabla que no están presentes en este array será eliminado. Registros en el array que no están presentes en la tabla (tienen un id, o un id de null) se considerarán registros “nuevos” y se insertarán en la base de datos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *