robsonvleite / datalayer

The data layer is a persistent abstraction component of your database that PDO (O data layer é um componente para abstração de persistência no seu banco de dados que usa PDO com prepared statements)
https://www.upinside.com.br
MIT License
144 stars 53 forks source link

Salvar múltiplas linhas em tabela sem chave primária #42

Closed felipeabranches closed 3 years ago

felipeabranches commented 3 years ago

MySQL: 5.7.31 PHP: 7.3.21 Datalayer: 1.1.8

Estou com problemas em salvar múltiplas linhas em tabela sem chave primária. Possuo 3 tabelas: "user_account", "user_group" e "user_group_map". Em um formulário para criar ou editar a conta, posso escolher mais de um grupo para esse usuário. O usuário é criado ou editado na tabela "user_account", mas nada é salvo na tabela "user_group_map"

A tabela "user_group_map" possui apenas 2 campos INT: id_user e id_group.

CREATE TABLE `user_group_map` (
  `id_user` int(10) UNSIGNED NOT NULL DEFAULT '0',
  `id_group` int(10) UNSIGNED NOT NULL DEFAULT '0',
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

GroupMapModel.php

<?php

namespace Source\Models\Systematics;

use CoffeeCode\DataLayer\DataLayer;

/**
 *
 */
class GroupMapModel extends DataLayer
{
    public function __construct()
    {
        parent::__construct('user_group_map', [], 'id_user', false);
    }
}

AccountModel.php (resumido)

class AccountModel extends DataLayer
    public function __construct()
    {
        parent::__construct('user_account', ['username', 'email']);
    }

    public function createAccount($data)
    {
        // New Account
        $row = $this;

        // Data
        $row->lastname = ucfirst(strtolower($data['lastname']));
        $row->forename = ucfirst(strtolower($data['forename']));
        $row->username = strtolower($data['username']);
        $row->email = $data['email'];
        $row->passwd = $data['passwd'];

        // Create
        $account = $row->save();

        if (!$account)
        {
            if ($row->fail()->getCode() == 23000)
            {
                $alert_type = 'warning';
                $_SESSION['alert'] = 'Username already exists.';
            }
            else
            {
                $alert_type = 'danger';
                $_SESSION['alert'] = 'Failed to create Account: ' . $row->fail()->getMessage();
            }
        }
        else
        {
            // Get this Id
            $lastId = $this->params['id'];

            // Insert a pair of User and Group for each Group selected
            $map = new GroupMapModel();
            foreach ($data['id_group'] as $group)
            {
                $map->id_user = $lastId;
                $map->id_group = $group;
                $groups = $map->save();
            }

            if (!$groups)
            {
                // If some error ocour, insert 0 value to id_group
                $map->id_user = $lastId;
                $map->id_group = 0;
                $map->save();

                $alert_type = 'danger';
                $_SESSION['alert'] = 'Failed to add Groups to Account: ' . $map->fail()->getMessage();
            }
            else
            {
                $alert_type = 'success';
                $_SESSION['alert'] = 'Account created!';
            }
        }

        return $alert_type;
    }
}

Ao salvar, o usuário e criado na tabela "user_account", mas nada na tabela "user_group_map", e recebo o erro ( ! ) Fatal error: Uncaught Error: Call to a member function data() on null in C:\wamp64\www\test\vendor\coffeecode\datalayer\src\DataLayer.php on line 267

Teste 1

Altero a linha 267 de C:\wamp64\www\test\vendor\coffeecode\datalayer\src\DataLayer.php para $this->data = $this->find("{$this->primary} = :id", "id={$id}")->data(); Não exibe nenhum erro, salva a conta mas não os grupos

Teste 2

Sem alterar C:\wamp64\www\test\vendor\coffeecode\datalayer\src\DataLayer.php Crio uma chave primária e edito GroupMapModel.php

<?php

namespace Source\Models\Systematics;

use CoffeeCode\DataLayer\DataLayer;

/**
 *
 */
class GroupMapModel extends DataLayer
{
    public function __construct()
    {
        parent::__construct('user_group_map', [], 'id', false);
    }
}

Não exibe nenhum erro, salva a conta mas APENAS o último grupo selecionado. Acredito que isso se deva ao fato de prucurar pela chave primária e reescrever essa mesma linha na tabela o número de vezes igual ao número de grupos selecionados, restando salvo, portanto, apenas o último grupo selecionado.

Como posso resolver essa questão? Obrigado

felipeabranches commented 3 years ago

Realizei um novo teste, dessa vez com as alterações dos testes 1 e 2, concomitantemente, e funcionou! Porém, teria como alcançar esse resultado sem a chave primária para "user_group_map"?

robsonvleite commented 3 years ago

Crie a chave primária do registro.

id (primária) id_user, id_group

Resolvido e com boas práticas 👍