Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Bom dia pessoal, estou precisando da ajuda de vocês para resolver um problema de relacionamento de classes que será usado no PDO.
Tenho uma classe Produto que tem um atributo que faz referência a classe Categoria. Até aqui tudo bem.
Porém quando eu faço a consulta no banco para trazer os produtos, ele me retorna o valor da categoria NULL, como posso resolver isso?
Não estar NULL, no banco coloquei categoria de id 1 para todos os produtos.
Utilizo "fetchAll(\PDO::FETCH_CLASS, 'Produto')" para me devolver em forma de objeto e não em array.
OBS: Não levem em consideração os nomes de atributos e métodos, serão refatorados kkkkkk
class Categoria {
private $id;
private $descricao;
function getId() {
return $this->id;
}
function getDescricao() {
return $this->descricao;
}
function setId($id) {
$this->id = $id;
}
function setDescricao($descricao) {
$this->descricao = $descricao;
}
}
class Produto {
private $id;
private $nome;
private $descricao;
private $categoria_id;
public function __construct() {
$this->categoria_id = new Categoria();
}
function getId() {
return $this->id;
}
function getNome() {
return $this->nome;
}
function getDescricao() {
return $this->descricao;
}
function setId($id) {
$this->id = $id;
}
function setNome($nome) {
$this->nome = $nome;
}
function setDescricao($descricao) {
$this->descricao = $descricao;
}
function getCategoria_id() {
return $this->categoria_id;
}
function setCategoria_id($categoria) {
$this->categoria_id = $categoria;
}
}
$stmt = $query->execute();
$stmt->fetchAll(\PDO::FETCH_CLASS, 'Produto');
0 =>
object(Produto)[18]
private 'id' => int 3
private 'nome' => string 'Produto B55333' (length=14)
private 'descricao' => string 'Teste B66666' (length=12)
private 'categoria_id' =>
object(Categoria)[19]
private 'id' => null
private 'descricao' => nullEntendi...
Acho que vou optar por fazer isso:
O que pode ser feito é, com o "id_categoria" de "Produto" fazer outra consulta para pegar o objeto "Categoria", o problema é que assim você pode perder um pouco de performance.
Já usei o doctrine, mas prefiro usar algo mais simples, estou usando o SlimPDO.
Obrigado.
Há a possibilidade em você mesmo criar seu sistema ORM e deixar ele com a simplicidade que deseja.
Eu coloquei um join e alias na minha consulta:
$query = $this->getDBInstance()
->select(array('produto.*', 'categoria.descricao as descCategoria'))
->from('Produto')
->join('categoria', 'categoria.id', '=', 'produto.categoria_id', 'INNER');
$stmt = $query->execute();
$register = $stmt->fetchAll(\PDO::FETCH_CLASS);
0 =>
object(stdClass)[18]
public 'id' => int 3
public 'nome' => string 'Produto B55333' (length=14)
public 'descricao' => string 'Teste B66666' (length=12)
public 'categoria_id' => int 2
public 'descCategoria' => string 'Categoria 2' (length=11)
Ele juntou tudo em uma stdClass, porque coloquei fetchAll(\PDO::FETCH_CLASS).. Eu queria que fosse um objeto da classe Produto:
0 =>
object(Produto)[18]
private 'id' => int 3
private 'nome' => string 'Produto B55333' (length=14)
private 'descricao' => string 'Teste B66666' (length=12)
private 'categoria_id' =>
object(Categoria)[19]
private 'id' => 2
private 'descricao' => 'Categoria 2'
Mas quando coloco fetchAll(\PDO::FETCH_CLASS, 'Produto') ele dar erro: SQLSTATE[HY000]: General error: could not call class constructor.
Tem como fazer isso?
>
Mas quando coloco fetchAll(\PDO::FETCH_CLASS, 'Produto') ele dar erro: SQLSTATE[HY000]: General error: could not call class constructor.
Tem como fazer isso?
Tem sim.
Esse erro pode ser um problema de require/include, você está utilizando autoload? como está importando os arquivos ".php"? como ficou a classe Produto?
Tem sim. Isso pode ser um problema de require/include, você está utilizando autoload? como está importando os arquivos ".php"? como ficou a classe Produto?
Não acho que seja isso, estou usando autoload, psr-4, utilizo namespaces e talz..
O carregamento dos arquivos/classes estão funcionando perfeitamente.
Na verdade fica assim:
fetchAll(\PDO::FETCH_CLASS, 'app\Models\Produto')
A diretiva PDO::FETCH_CLASS foi desenvolvida para uma consulta (que pode ter de 1 a N tabelas) representar um único objeto. Por isso, sua categoria nunca será criada dessa forma.
Nesse caso, o melhor que pode fazer, são duas consultas:
$stmt = $query->execute();
$produtoArr = $stmt->fetchAll(\PDO::FETCH_CLASS, 'Produto');
$statement = $pdo->prepare('select * from categoria where id = :id');
foreach($produtoArr as $produto) {
$stmt = $query->execute(array(':id' , $produto->getCategoria_id()));
$categoria = $stmt->fetch(\PDO::FETCH_CLASS, 'Categoria');
$produto->setCategoria($categoria);//O método não existe, vai ter que ter algo similar
}Rapaz, tinha pensado exatamente isso, testei e funcionou do jeito que eu quero:
0 =>
object(app\Models\Produto)[18]
private 'id' => int 3
private 'nome' => string 'Produto B55333' (length=14)
private 'descricao' => string 'Teste B66666' (length=12)
private 'categoria_id' =>
object(app\Models\Categoria)[35]
private 'id' => int 2
private 'descricao' => string 'Categoria 2' (length=11)Enfim, acho que vai ficar assim mesmo...
Obrigado pela ajuda de todos.
Não é feio, é apenas genérico.
É comum, falando-se de ORM, a maioria dos programadores pensarem que um objeto deve ser uma tabela e vice-versa, apesar de não ser verdade. Para PDO, apenas foi implementado o que é de consenso da maioria.
Entendi. vlw o/
Até onde eu sei, você não vai conseguir mapear os parâmetros da sua classe "Categoria" com os campos da tabela dessa forma, utilizando somente o PDO.
O que pode ser feito é, com o "id_categoria" de "Produto" fazer outra consulta para pegar o objeto "Categoria", o problema é que assim você pode perder um pouco de performance.
Outra maneira é você retornar os campos da tabela categoria nos parâmetros da classe "Produto" e quando o método "getCategoria" for chamado, você cria o objeto categoria, assim será feito apenas uma consulta, o código ficaria parecido com isso: (obs: não executei esse código)
class Produto
{
$stm = $pdo->prepare("
Apenas para complementar, caso você não conheça e queira fazer algo um pouco mais avançado, existem alguns frameworks ou ORM (Object Relational Mapper) que foram criados especificamente para trabalhar com isso; recomendo dar uma olhada no Doctrine.