Executando verificação de segurança...
2

Dúvida sobre CRUD PHP/MySQL

Estou desenvolvendo um CRUD com PHP e cheguei na parte de fazer as ligações das tabelas de estado, cidade, bairro e rua. Para pegar esses dados eu implementei uma API de CEP, que quando o user digita seu CEP as informações carregam automaticamente. Estou com um pequeno problema, os estados eu ja pre inseri dentro do banco, por nao ser tratar de algo tão grande, mas o que está me incomodando, é o fato de os dados cidades, bairros, ruas serem duplicados quando houver um novo cadastro, tem alguma maneira de corrigir isto?

Pritn da tabela cidades:
https://prnt.sc/RH_-w40ujFWx

Preciso que não ocorra um mesmo cadastro se o mesmo ja existir, é possivel?

Carregando publicação patrocinada...
1

No Laravel há um método que atende a tua dúvida e tu pode transportar.

Há uma função firstOrCreate que recebe dois parâmetros: attributes e values, ambos arrays. O que ela tenta fazer é encontrar no banco algo que satisfaça as condições do que você passar no primeiro parâmetro, caso exista, retornará o próprio objeto, caso contrário, criará um novo registro.

Ela é mais ou menos assim:

public function firstOrCreate(array $attributes = [], array $values = [])
{
    if (!is_null($instance = $this->where($attributes)->first())) {
        return $instance;
    }

    return tap($this->newModelInstance(array_merge($attributes, $values)), function ($instance) {
        $instance->save();
    });
}

Como funciona:

Nesse trecho da função, ele está fazendo uma consulta no banco com tudo o que foi passado como primeiro parâmetro da função firstOrCreate.

if (!is_null($instance = $this->where($attributes)->first())) {
    return $instance;
}

Por exemplo:

User::firstOrCreate(['email' => '[email protected]'], []);

A função irá realizar uma consulta no banco, verificando o seguinte: se, na tabela users, existe um usuário com email tendo o valor [email protected], então me retorne esse usuário. Caso contrário, siga o seu curso.
Para o seu caso: ['nome_cidade' => 'value_that_you_want', 'fk_estado' => 'value_that_you_want'].

No segundo trecho da função, ele vai apenas criar uma nova instância do modelo, tendo como atributos os dois arrays mergeados que foram passados e salvará no banco. Por exemplo:

User::firstOrCreate(['email' => '[email protected]'], ['name' => 'Dummy User']);

Caso o email não exista, o resultado será um novo registro no banco com esse email e esse nome de usuário.

Talvez tenha ficado um pouco mais complexo do que deveria por se tratar do framework, mas a ideia central é: realize uma consulta no banco na hora de criar o registro. Se existir um registro com as condições que satisfaçam o que você deseja, retorne o que for adequado para ti. Se não existir, insira o novo registro.

1

@meira você consegue exemplificar quais são as ligações entre essas tabelas?
Se eu consegui entender bem, o que está acontecendo é que para cada novo cadastro que contém essas informações está duplicando as informações dentro do banco de dados correto?

Essa tabela do seu print seria uma tabela para armazenar as cidades?

Aparentemente você possui uma tabela para cada um desses modelos que você citou. Seria isso mesmo? Uma tabela para cidade, uma para estado e outra para endereço. Correto?

Se for isso mesmo, você poderia ter uma tabela extra que armazenaria todas as referências de chave estrangeira das outras tabelas que citei acima:

endereco_usuario
id | endereco_fk |

onde essa tabela faz referencia ao endereço em formato de chave estrangeira, que por sua vez faz referência à cidade

endereco
id | cidade_fk

onde essa tabela faz referência à cidade em formato de chave estrangeira e por fim, a cidade faz referênca ao estado

cidade
id | estado_fk

Perceba que aqui você terá uma tabela de estado contendo todos os estados do Brasil por exemplo, uma tabela de cidade que faz referência aos estados (onde você terá várias cidades para um mesmo estado por exemplo), uma tabela de endereços que faz referência a uma cidade (também podendo conter várias cidades para a mesma cidade) e a última, caso seja realmente isso, poderia ser uma tabela de endereco_usuario onde vc faz referência somente a primary key de um endereço.

Acho que ficaria algo assim

1 estado ----------> N cidades
1 cidade ----------> N enderecos

No final, se vc souber o ID de um endereço, você saberá a FK de uma cidade e na cidade vc sabe a FK do estado.

Se precisar, existe DB Diagram, que te ajuda no mapeamento de relações entre as tabelas

1

O banco ta assim, aqui da pra ter uma ideia melhor: https://prnt.sc/PP9iuleWl-XD

Ali na tabela endereço estou declarando a rua, mas poderia criar uma tabela para rua e deixar a de endereco para armazenar as fks.

Uma outra duvida, seria possivel não ter de cadastrar todas as cidades do Brasil em uma tabela? Eu queria fazer algo que conforme seja cadastrado pelo user, a cidade ou rua, o proximo cadastro ja buscasse desse antigo, sem duplicar.

1

Boaa entendi. Acho que vc fez mais ou menos como eu falei então.
Tem sim. O que você pode fazer é o seguinte: quando o usuário procurar por um endereço, vc pode ir até o seu banco e buscar por ele. Caso o seu banco não tenha o endereço procurado, você pode consumir alguma API de endereços (acho que a Brasil API deve conter o que vc precisa ), pegar as informações que essa API te retornar e por fim vc salva no seu banco de dados.
Conseguiu entender o que eu quis dizer?

1

Eu estou usando uma api que ao botar o CEP, ja busca todas as informações de cidade, estado, rua etc. Acho que vou tentar utilizar o comando select para pesquisar no banco se ja tem o cadastro, e se houver eu só atribuo a fk. Obrigado pleas dicas ai, tmj!

1

O exemplo abaixo simula um contador de visualização que não cadastra uma nova data se ela já existir no banco de dados, da pra pegar a mesma lógica para o seu problema.


include('Database/database.php');
$date_now = date('Y-m-d');
$query = "SELECT * FROM hit_counter_product WHERE `data` = '$date_now'";
$query = $pdo->query($query);
if ($query->rowCount() > 0) {
    $query = "UPDATE hit_counter_product SET `counter` = `counter` + 1 WHERE `data` = '$date_now'";
    $query = $pdo->query($query);
} else {
    $query = "INSERT INTO hit_counter_product (`data`, `counter`) VALUES ('$date_now', 1)";
    $query = $pdo->query($query);
}
    

Qualquer dúvida, só perguntar.