3
respostas

[Dúvida] Excluir tudo relacionado a um Artista quando ele for excluído [Laravel]

Eu venho quebrando a cabeça há algum tempo com a seguinte situação. Eu tenho uma situação onde um admin quer remover um artista da base de dados do site, e com essa remoção ele deve excluir ANTES também:

  • Álbuns + capas dos álbuns do artista
  • Faixas destes álbuns
  • Singles destes álbuns
  • Filmes + capas dos filmes que esse artista participou
  • Desafetos do artista

Além disso, preciso mudar o campo artistaID nos vídeos desse artista excluído para um genérico cujo id é 182 e tornar os campos albumID e trackNumero em NULL, já que os álbuns relacionados à esses vídeos não existem mais.

Aí, depois de tudo isso é que eu finalmente excluo a foto de perfil do artista, pra enfim excluir o artista.

A estrutura das models é a seguinte: Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Eu consigo remover os álbuns (mas não as capas), as faixas, os singles e aí entro num erro 404. Tentei alguns códigos, mas nenhum chega de fato ao final da ação, que é remover o artista.

Eis o controller:

public function removerArtista(Request $request){
        $artista = Artistas::findOrFail($request->artistaID);
        
        /* Faz a busca por todos os álbuns do artista */
        $albuns = $artista->albuns;

        /* Remove as capas de álbuns antes de prosseguir (NÃO FUNCIONA) */
        foreach ($albuns as $album)
        {
            //$image_path = 'storage/albuns/' . $album->coverAlbum;
    
            Storage::delete(Storage::path('albuns/'.$album->coverAlbum));
            $album->faixas()->delete(); /* Remove todas as faixas para aqueles álbuns */
            $album->singles()->delete(); /* Remove todos os singles daqueles álbuns  */
            $album->delete(); /* Remove o álbum */
        }
        
        /* DÁ ERRO 404 A PARTIR DAQUI /\ */

        /* Faz a busca por todos os filmes do artista */
        $filmes = $artista->filmes;

        /* Remove as capas de filmes antes de prosseguir */
        foreach ($filmes as $filme)
        {
            $filme->delete(); /* Remove o filme */
        }

        $artista->desafetos()->delete(); /* Remove todos os desafetos do artista */
        $artista->grupos()->delete(); /* Remove todos os grupos do artista */

        $videos = $artista->videos;

        foreach($videos as $video){
            $video = Videos::findOrFail($video);
            $video->artistaID = 182;
            $video->albumID = NULL;
            $video->trackNumero = NULL;
            $video->save();
        }
        unlink('storage/artistas/'.$artista->fotoPerfil);
        return 'SUCESSO' //mensagem genérica para testes;
    }
3 respostas

Olá Elisame, tudo bem?

Pelo que entendi, você está tentando excluir um artista e todos os dados relacionados a ele, mas está encontrando um erro 404 durante o processo. Isso pode estar acontecendo por vários motivos, mas vamos tentar resolver isso passo a passo.

Primeiro, vamos verificar a exclusão das capas dos álbuns. Você mencionou que isso não está funcionando. O método Storage::delete() retorna um booleano indicando se a operação foi bem-sucedida ou não. Você pode verificar isso para ver se a exclusão está realmente ocorrendo:

$deleted = Storage::delete(Storage::path('albuns/'.$album->coverAlbum));
if ($deleted) {
    echo "Capa do álbum deletada com sucesso.";
} else {
    echo "Falha ao deletar a capa do álbum.";
}

Se a capa do álbum não está sendo excluída, pode ser que o caminho do arquivo esteja incorreto ou o arquivo não exista.

Em relação ao erro 404, ele geralmente ocorre quando uma URL não é encontrada. Isso pode estar relacionado à forma como você está tentando acessar os filmes do artista. Você poderia verificar se a relação entre o artista e os filmes está correta e se os filmes estão sendo retornados como esperado.

Além disso, é importante garantir que todas as operações de exclusão estejam dentro de uma transação do banco de dados. Isso garante que, se algo der errado em qualquer ponto, todas as operações serão revertidas, mantendo a integridade dos dados.

Espero que isso ajude! Se você tiver mais perguntas, fique à vontade para perguntar.

https://cursos.alura.com.br/forum/topico-duvida-excluir-tudo-relacionado-a-um-artista-quando-ele-for-excluido-laravel-356706

É exatamente isso. Quando um artista for removido do banco de dados, suas informações relacionadas vão ser removidas ou alteradas.

Sobre a transação, como estou apenas testando o funcionamento, eu ainda não pesquisei a fundo como envolver todas essas ações numa transação - como eu faria exatamente isso?

A primeira coisa que eu havia pensado é justamente o relacionamento, mas, para cada artista eu tenho páginas individuais onde eu gerencio: Perfil, História, Discografia, Filmes, Desafetos, Grupos e Vídeos, e todos eles retornam corretamente os dados pra cada artista.

Como o projeto ainda não tem todas as imagens linkadas - perfis, capas de filmes, capas de álbuns e etc. - isso poderia estar causando o 404? Porque no log do Laravel ele não fala nada sobre o erro 404... Como eu poderia verificar se imagem existe ou não antes de proceder para exclusão dela?

Não sei se o github do projeto ajudaria, mas caso ajude: https://github.com/ElisameAraujo/Admin-v3.1

Depois de mais uma verificação no código, consegui corrigir os erros e agora remover um artista funciona como eu esperava! Cheguei ao seguinte código:

public function removerArtista(Request $request){
        $artista = Artistas::findOrFail($request->artistaID);
        
        /* Faz a busca por todos os álbuns do artista */
        $albuns = $artista->albuns;

        /* Faz a iteração em cada álbum */
        if($artista->albuns()->count() > 0){
            foreach ($albuns as $album)
            {

                /* Busca pela capa do álbum e remove ela antes de prosseguir */
                if($album->coverAlbum === NULL || empty($album->coverAlbum) || $album->coverAlbum === ""){

                }else{
                    unlink('storage/albuns/'.$album->coverAlbum);
                }

                /**
                * Remove todas as faixas para aqueles álbum
                */
                if($album->faixas()->count() > 0){
                    $album->faixas()->delete();
                }else{
                }

                /**
                 * Remove todos os singles daqueles álbum
                 */
                if($album->singles()->count() > 0){
                    $album->singles()->delete();
                }else{
                
                }
                $album->delete(); /* Remove o álbum */
            }
        }else{
        
        }

        /* Faz a busca por todos os filmes do artista */
        $filmes = $artista->filmes;

        /* Faz a iteração por cada filme antes de prosseguir */
        if($artista->filmes()->count() > 0){
            foreach ($filmes as $filme)
            {
                /**
                 * Busca pela capa do filme e remove ela
                 */
                if($filme->coverFilme === NULL || empty($filme->coverFilme) || $filme->coverFilme === ""){

                }else{
                    unlink('storage/filmes/'.$filme->coverFilme);
                }
                $filme->delete(); /* Remove o filme */
            }
        }else{

        }
        if($artista->desafetos()->count() > 0){
            $artista->desafetos()->delete(); /* Remove todos os desafetos do artista */
        }else{
        
        }
        if($artista->grupos()->count() > 0){
            $artista->grupos()->delete(); /* Remove todos os grupos do artista */
        }else{
        
        }

        /**
         * -> Busca todos os videos daquele artista e atualiza o ID para um valor genenérico (artistaID = 182 (Outros))
         * -> Remove o id do álbum 
         * -> Remove o número da faixa
         */
        if($artista->videos()->count() > 0){ 
            DB::transaction(function() use ($artista) {
                $artista->videos()->update(['artistaID' => 182, 'albumID' => NULL, 'trackNumero' => NULL]);
                $artista->save();
            });
        }else{
        
        }

        /**
         * Remove a imagem de perfil do artista
         */
        if($artista->fotoPerfil === NULL || empty($artista->fotoPerfil) || $artista->fotoPerfil === ""){

        }else{
            unlink('storage/artistas/'.$artista->fotoPerfil);
        }

        /**
         * Finalmente, remove o artista e redireciona para a página correta baseada no tipo de artista
         * Caso o tipo de artista seja igual a 1 (Solo) redireciona para a rota de artista solo, caso contrário irá para rota de duos, trios e grupos
         */
        $artista->delete();

        if($request->tipo == 1){
            return to_route('artistas-solo')
            ->with('removido', 'Artista, álbuns, faixas, singles, filmes, desafetos e grupos removidos com sucesso.');
        }else{
            return to_route('artistas-multi')
            ->with('removido', 'Artista, álbuns, faixas, singles, filmes, desafetos e grupos removidos com sucesso.');
        }
    }

Há alguma coisa que eu precise melhorar no código?