Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Dúvida no Ex. 5 da Aula 12 - Método abstrato

Oi pessoal sou iniciante em desenvolvimento e estou com algumas dúvidas. não consigo avançar no curso.

Duvida 1-) Na hora de adicionar o produto, está dando erro "Warning: Missing argument 1 for Produto::__construct(), called in C:\wamp\www\loja\class\ProdutoFactory.php on line 9 and defined in C:\wamp\www\loja\class\Produto.php on line 69"

Estou com dúvida de como adicionar os construtores a classe Produto, já que ProdutoFactory não passa os argumentos quando instacia LivroFisico ou Ebook .Como posso fazer ?

//classe adiciona-produto

$tipoProduto = $_POST["tipoProduto"]; $factory = new ProdutoFactory();$produto = $factory->criaPor($tipoProduto);

$produto->atualizaBaseadoEm($_POST);

$produtoDao = new ProdutoDAO($conexao);

//resto do codigo

Notem que os argumentos só são passados em $produto->atualizaBaseadoEm($_POST); depois que a classe foi instanciada e ai da erro.

Uma duvida que ficou para trás e não consegui resolver.

Dúvida 2-) Como funciona um objeto dentro de objeto? Na hora de exibir a listagem de produto, existe a variável categoria, como em php o tipo da variável e definido dinamicamente, e assim pode receber um objeto. Mas na hora que faz o select no banco de dados o categoria_id é um numero. Como posso exibir o nome? É necessário instanciar o classe categoria fazer o select em categoria e comparar os IDs?

<?php require_once("conecta.php"); require_once("cabecalho.php"); require_once("class/produtoDAO.php"); require_once("conecta.php"); ?>

<?php $produtoDao = new ProdutoDAO($conexao); $produtos = $produtoDao->listaProdutos();

var_dump($produtos);

foreach($produtos as $produto) : ?>

<?= $produto->nome ?> <?= $produto->getPreco() ?> <?= $produto->mostraImposto() ?> <?= substr($produto->descricao, 0, 40) ?> <?= $produto->categoria; ?>

<?php if($produto->isLivro()){ echo "ISBN: ".$produto->getIsbn(); } ?>

// resto do codigo abaixo

Obrigado!

6 respostas

Olá amigo, você pode postar os arquivos das classes ? lembre-se de usar a formatação do forum para códigos, pois facilita a interpretação.

Opa Claro, não sabia usar a formatação do fórum.

<?php

class Categoria{
    private $id;
    private $nome;

    public function getId(){
        return $this->id;
    }

    public function setId($id){
        $this->id = $id;
    }

    public function getNome(){
        return $this->nome;
    }

    public function setNome($nome){
        $this->nome = $nome;
    }

}
<?php

class Ebook extends Livro{

    private $waterMark;

    public function getWaterMark(){
        return $this->waterMark;
    } 

    public function setWaterMark($waterMark){
        $this->waterMark = $waterMark;
    }
}
<?php

class Livro extends Produto{
    private $isbn;  

    function calculaImposto(){
        return $this->getPreco() - $this->getPreco() * 0.065;
    }

    public function mostraImposto(){
        return $this->getPreco() * 0.1; 
    }

    public function getIsbn(){
        return $this->isbn;
    }

    public function setIsbn($isbn){
        $this->isbn = $isbn;
    }    

}
<?php

class LivroFisico extends Livro{

    private $taxaImpressao;

    public function getTaxaImpressao(){
        return this->taxaImpressao;            
    }

    public function setTaxaImpressao($taxaImpressao){
        $this->taxaImpressao = $taxaImpressao;
    }


    abstract function atualizaBaseadoEm($params)
    {

    if (method_exists($this, "setIsbn")) {
            $this->setIsbn($params["isbn"]);
        }
        if (method_exists($this, "setWaterMark")) {
            $this->setWaterMark($params["waterMark"]);
        }
        if (method_exists($this, "setTaxaImpressao")) {
            $this->setTaxaImpressao($params["taxaImpressao"]);
        }

        $this->nome = $params["nome"];      
        $this->setPreco($params["preco"]);
        $this->descricao = $params["descricao"];
        $this->categoria = $params["categoria_id"];
        $this->usado = $params['usado'];
    } 

}
<?php

abstract class Produto{
    private $id;    
    public $nome;
    private $preco;
    public $descricao;
    public $categoria;
    public $usado;    
    private $tipoProduto;

    //methods


    //O método temIsbn precisa verificar se o produto em questão é uma instância de Livro. Podemos fazer isso com o instanceof
    function temIsbn() {
        return $this instanceof Livro;
    }    

     function isLivro(){
         return strcasecmp($this->tipoProduto, "livro") == 0;
    }

    public function valorComDesconto($valor = 0.9){
        if($valor > 0 && $valor < 1){
          $this->preco = $this->preco * $valor;
        }
        return $this->preco;
    }

    public function mostraImposto(){
        return $this->getPreco() * 0.2; 
    }

    abstract function atualizaBaseadoEm($params)  {        
    }    

    //magic methods    
    function __construct($nome, $preco, $descricao, $categoria, $usado, $tipoProduto){
        $this->nome = $nome;
        $this->setPreco($preco);        
        $this->descricao = $descricao;
        $this->categoria = $categoria;
        $this->usado = $usado;
        $this->setTipoProduto($tipoProduto); 
    }

    function __toString(){
        return "Nome: ".$this->nome
            .", Preco: ".$this->getPreco();
    }

    function __destruct(){
        echo "</br> Objeto: " . $this->nome." destruido.";
    }

    //getters and setters

    public function getId(){
        return $this->id;
    }

    public function setId($id){
        $this->id = $id;
    }

    public function getPreco(){
        return $this->preco;
    }

    public function setPreco($preco){
        if($preco > 0){
            $this->preco = $preco;
        }
    }

    function setTipoProduto($tipoProduto) {   
        $this->tipoProduto = $tipoProduto;
    }

    function getTipoProduto(){
        return $this->tipoProduto;
    }
}
<?php

class ProdutoDAO{

    private $conexao;

    //obrigatorio passar uma conexao do banco
    function __construct($conexao){
        $this->conexao = $conexao; 
    }

    function listaProdutos() {
        $produtos = array();
        $resultado = mysqli_query($this->conexao, "select * from produtos");
        while($array = mysqli_fetch_assoc($resultado)) { 

            //Precisamos instânciar um Livro, caso haja um isbn, ou Produto no caso contrário.            
            if (trim($array['isbn'])!=="") {
                $produto = new Livro(
                    $array['nome'],
                    $array['preco'],
                    $array['descricao'],
                    $array['categoria'],
                    $array['usado'],
                    $array['tipoProduto']
                );

                $produto->setIsbn($array['isbn']);

            } else {
                $produto = new Produto(
                    $array['nome'],
                    $array['preco'],
                    $array['descricao'],
                    $array['categoria'],
                    $array['usado'],
                    $array['tipoProduto']                    
                );
            }

            //resto dos atributos setados fora dos construtores
            $produto->setId($array['id']);            
            $produto->descricao = $array['descricao'];
            $produto->categoria = $array['categoria_id'];
            $produto->usado = $array['usado'];      

            array_push($produtos, $produto);
        }
        return $produtos;
    }

    function insereProduto(Produto $produto) {

        if ($produto->temIsbn()) {
            $isbn = $produto->getIsbn();
        } else {
            $isbn = "";
        }

      $query = 
        "insert into produtos (nome, preco, descricao, 
        categoria_id, usado, isbn, tipoProduto, waterMark, taxaImpressao) values 
        ('{$produto->nome}', '{$produto->getPreco()}', 
        '{$produto->descricao}', '{$produto->categoria}', 
        '{$produto->usado}', '{$isbn}', '{$produto->getTipoProduto()}' '{$waterMark}', 
        '{$taxaImpressao}')";
        var_dump($query);        
        return mysqli_query($this->conexao, $query);
    }

    function alteraProduto($produto) {
        $query = "update produtos set nome = '{$produto->nome}', preco = {$produto->getPreco()}, descricao = '{$produto->descricao}', categoria_id= {$produto->categoria_id}, usado = {$produto->usado} where id = '{$produto->getId()}'";
        return mysqli_query($this->conexao, $query);
    }

    function buscaProduto($id) {
        $query = "select * from produtos where id = {$id}";
        $resultado = mysqli_query($this->conexao, $query);
        return mysqli_fetch_assoc($resultado);
    }

    function removeProduto($id) {
        $query = "delete from produtos where id = {$id}";
        return mysqli_query($this->conexao, $query);
    } 
}
<?php

class ProdutoFactory{

    private $classes = array("Produto", "Ebook", "LivroFisico");
    function criaPor($tipoProduto)
    {
        if (in_array($tipoProduto, $this->classes)) {
            return new $tipoProduto;
        }
        return new Produto();
    }

}
solução!

Olá boa noite, desculpe a demora mas é que está meio corrido aqui, estou em final de semestre e ta uma correria muito grande, mas vamos ao que interessa.

o problema é bem simples, na classe onde você ProdutoFactory onde você instancia um novo produto você deve passar os valores na criação desse objeto exemplo.

está assim.

class ProdutoFactory{

    private $classes = array("Produto", "Ebook", "LivroFisico");
    function criaPor($tipoProduto)
    {
        if (in_array($tipoProduto, $this->classes)) {
            return new $tipoProduto;
        }
        return new Produto();
    }

}

e deve ficar assim


class ProdutoFactory{

    private $classes = array("Produto", "Ebook", "LivroFisico");
    function criaPor($tipoProduto)
    {
        if (in_array($tipoProduto, $this->classes)) {
            return new $tipoProduto;
        }
        return new Produto($nome, $preco, $descricao, $categoria, $usado, $tipoProduto);
    }

}

logicamente que tem que existir essas variáveis, ai você pega via poste. eu acho que é só isso de acordo com o erro que ta dando lá em cima. Espero ter ajudado.

Obrigado. Com isso, e algumas outra alterações, consegui fazer funcionar como esperado.

Só ficou faltando mesmo a parte do categoria, tenho que listar a categoria e setar o nome correspondente aquele id.

Depois vou fazer o alterar-formulario para funcionar com herança dos livrosFisico e Ebook.

<?php

class Categoria{
    private $id;
    private $nome;

    public function getId(){
        return $this->id;
    }

    public function setId($id){
        $this->id = $id;
    }

    public function getNome(){
        return $this->nome;
    }

    public function setNome($nome){
        $this->nome = $nome;
    }

}
<?php

class Ebook extends Livro{

    private $waterMark;

    public function getWaterMark(){
        return $this->waterMark;
    } 

    public function setWaterMark($waterMark){
        $this->waterMark = $waterMark;
    }


    function atualizaBaseadoEm($params)
    {                

        $this->setWaterMark($params["waterMark"]);
        $this->setIsbn($params["isbn"]);

        $this->nome = $params["nome"];      
        $this->setPreco($params["preco"]);
        $this->descricao = $params["descricao"];
        $this->categoria = $params["categoria_id"];
        $this->usado = $params['usado'];
    } 

}
<?php

abstract class Livro extends Produto{
    private $isbn;

    function calculaImposto(){
        return $this->getPreco() - $this->getPreco() * 0.065;
    }

    public function mostraImposto(){
        return $this->getPreco() * 0.1; 
    }

    public function getIsbn(){
        return $this->isbn;
    }

    public function setIsbn($isbn){
        $this->isbn = $isbn;
    }    

}
<?php

class LivroFisico extends Livro{

    private $taxaImpressao;

    public function getTaxaImpressao(){
        return $this->taxaImpressao;            
    }

    public function setTaxaImpressao($taxaImpressao){
        $this->taxaImpressao = $taxaImpressao;
    }


    function atualizaBaseadoEm($params){                

        $this->setTaxaImpressao($params["taxaImpressao"]);
        $this->setIsbn($params["isbn"]);

        $this->nome = $params["nome"];      
        $this->setPreco($params["preco"]);
        $this->descricao = $params["descricao"];
        $this->categoria = $params["categoria_id"];
        $this->usado = $params['usado'];
    } 

}
<?php

abstract class Produto{
    private $id;    
    public $nome;
    private $preco;
    public $descricao;
    public $categoria;
    public $usado;    
    private $tipoProduto;

    //methods


    //O método temIsbn precisa verificar se o produto em questão é uma instância de Livro. Podemos fazer isso com o instanceof
    function temIsbn() {
        return $this instanceof Livro;
    }    

     function isLivro(){
         return strcasecmp($this->tipoProduto, "Livro") == 0;
    }

    public function valorComDesconto($valor = 0.9){
        if($valor > 0 && $valor < 1){
          $this->preco = $this->preco * $valor;
        }
        return $this->preco;
    }       

    public function mostraImposto(){
        return $this->getPreco() * 0.2; 
    }

    abstract function atualizaBaseadoEm($params);

    //magic methods    
   function __construct($nome, $preco, $descricao, $categoria, $usado, $tipoProduto){
        $this->nome = $nome;
        $this->setPreco($preco);        
        $this->descricao = $descricao;
        $this->categoria = $categoria;
        $this->usado = $usado;
        $this->setTipoProduto($tipoProduto); 
    }

    function __toString(){
        return "Nome: ".$this->nome
            .", Preco: ".$this->getPreco();
    }

    function __destruct(){
        echo "</br> Objeto: " . $this->nome." destruido.";
    }

    //getters and setters

    public function getId(){
        return $this->id;
    }

    public function setId($id){
        $this->id = $id;
    }

    public function getPreco(){
        return $this->preco;
    }

    public function setPreco($preco){
        if($preco > 0){
            $this->preco = $preco;
        }
    }

    function setTipoProduto($tipoProduto) {   
        $this->tipoProduto = $tipoProduto;
    }

    function getTipoProduto(){
        return $this->tipoProduto;
    }
}
<?php

class ProdutoDAO{

    private $conexao;

    //obrigatorio passar uma conexao do banco
    function __construct($conexao){
        $this->conexao = $conexao; 
    }

    function listaProdutos() {
        $produtos = array();
        $resultado = mysqli_query($this->conexao, "select * from produtos");

        while($produto_atual = mysqli_fetch_assoc($resultado)) {

            $categoria = new Categoria;            
            $categoria->setNome($produto_atual['categoria_nome']);           

            $produto = new $produto_atual['tipoProduto'](
                $produto_atual['nome'],
                $produto_atual['preco'],
                $produto_atual['descricao'],
                $produto_atual['categoria'],
                $produto_atual['usado'],
                $produto_atual['tipoProduto']
            );         

            //demais atributos setados fora dos construtores
            $produto->setId($produto_atual['id']);

            if(method_exists($produto, "setIsbn")) {
                $produto->setIsbn($produto_atual['isbn']);
            }      

            if(method_exists($produto, "setWaterMark")) {
                $produto->setWaterMark($produto_atual['waterMark']);
            }       

            if(method_exists($produto, "setTaxaImpressao")) {
                $produto->setTaxaImpressao($produto_atual['taxaImpressao']);
            }          

            array_push($produtos, $produto);
        }
        return $produtos;
    }

    function insereProduto(Produto $produto) {

        var_dump($produto);

        if(array_key_exists('usado', $_POST)) {
           $produto->usado = true;
        } else {
           $produto->usado = false;
        }

        $isbn = "";
        if(method_exists($produto, "getIsbn")) {
            $isbn = $produto->getIsbn();
        }

        $waterMark = "";
        if(method_exists($produto, "getWaterMark")) {
            $waterMark = $produto->getWaterMark();
        }

        $taxaImpressao = "";
        if(method_exists($produto, "getTaxaImpressao")) {
            $taxaImpressao = $produto->getTaxaImpressao();
        }

      $query = 
        "insert into produtos (nome, preco, descricao, categoria_id, usado, isbn, tipoProduto, waterMark, taxaImpressao)
        values('{$produto->nome}', '{$produto->getPreco()}', '{$produto->descricao}', '{$produto->categoria}',
        '{$produto->usado}', '{$isbn}', '{$produto->getTipoProduto()}', '{$waterMark}', '{$taxaImpressao}')";
        var_dump($query);        
        return mysqli_query($this->conexao, $query);
    }

    function alteraProduto($produto) {
        $query = "update produtos set nome = '{$produto->nome}', preco = {$produto->getPreco()}, descricao = '{$produto->descricao}', categoria_id= {$produto->categoria_id}, usado = {$produto->usado} where id = '{$produto->getId()}'";
        return mysqli_query($this->conexao, $query);
    }

    function buscaProduto($id) {
        $query = "select * from produtos where id = {$id}";
        $resultado = mysqli_query($this->conexao, $query);
        return mysqli_fetch_assoc($resultado);
    }

    function removeProduto($id) {
        $query = "delete from produtos where id = {$id}";
        return mysqli_query($this->conexao, $query);
    } 
}
<?php

class ProdutoFactory{

    private $classes = array("Ebook", "LivroFisico");
    function criaPor($tipoProduto)
    {
        if (in_array($tipoProduto, $this->classes)) {
            return new $tipoProduto($nome, $preco, $descricao, $categoria, $usado, $tipoProduto);
        }
        return new LivroFisico($nome, $preco, $descricao, $categoria, $usado, $tipoProduto);

    }

}
<?php
require_once("conecta.php");
require_once("cabecalho.php"); 
require_once("class/produtoDAO.php");
require_once("conecta.php");
 ?>

<table class="table table-striped table-bordered">

    <?php    
        $produtoDao = new ProdutoDAO($conexao);        
        $produtos = $produtoDao->listaProdutos(); 

    var_dump($produtos);

    foreach($produtos as $produto) :    
    ?>

    <tr>
        <td><?= $produto->nome ?></td>
        <td><?= $produto->getPreco() ?></td>
        <td><?= $produto->mostraImposto() ?></td>
        <td><?= substr($produto->descricao, 0, 40) ?></td>
        <td><?= $produto->categoria; ?></td>        
        <td>
            <?=           
                $produto->getIsbn();
            ?>  
        </td>
        <td>
            <?= $produto->getTipoProduto() ?>  
        </td>        
        <td>
            <?php
                if(property_exists($produto, 'waterMark')){
                    echo $produto->getWaterMark();
                }

            ?>
        </td>  
        <td>
            <?php
                if(property_exists($produto, 'taxaImpressao')){
                    echo $produto->getTaxaImpressao();
                }
            ?>        
        </td>  

        <td><a class="btn btn-primary" href="produto-altera-formulario.php?id=<?=$produto->getId()?>">alterar</a></td>        
        <td>
            <form action="remove-produto.php" method="post">
                <input type="hidden" name="id" value="<?=$produto->getId()?>">
                <button class="btn btn-danger">remover</button>
            </form>
        </td>        
    </tr>

    <?php
        endforeach
    ?>

</table>

<?php include("rodape.php"); ?>
<tr>
    <td>Nome</td>
    <td> <input class="form-control" type="text" name="nome" value="<?=$produto['nome']?>"></td>
</tr>
<tr>
    <td>Preço</td>
    <td><input  class="form-control" type="number" name="preco" 
        value="<?=$produto['preco']?>"></td>
</tr>
<tr>
    <td>Descrição</td>
    <td><textarea class="form-control" name="descricao"><?=$produto['descricao']?></textarea></td>
</tr>
<tr>
    <td></td>
    <td><input type="checkbox" name="usado" <?=$usado?> value="true"> Usado
</tr>
<tr>
    <td>Categoria</td>
    <td>
        <select name="categoria_id" class="form-control">
        <?php foreach($categorias as $categoria) : 
            $essaEhACategoria = $produto['categoria_id'] == $categoria['id'];
            $selecao = $essaEhACategoria ? "selected='selected'" : "";
            ?>
            <option value="<?=$categoria['id']?>" <?=$selecao?>>
                    <?=$categoria['nome']?>
            </option>
        <?php endforeach ?>
        </select>
    </td>
</tr>
<tr>
  <td>Tipo de produto</td>
    <td>
        <select name="tipoProduto" class="form-control">            
            <optgroup label="Livro">
                <option value="LivroFisico">Livro Físico</option>
                <option value="Ebook">Ebook</option>
            </optgroup>
        </select>        
    </td>
<tr>
<tr>
    <td>ISBN</td>
    <td><input name="isbn"/ class="form-control"></td>
</tr>
<tr>
    <td>Water Mark(Quando for ebook)</td>
    <td> <input name="waterMark" class="form-control"> </td>
</tr>
<tr>
    <td>Taxa Impressão(Quando for livro fisico)</td>
    <td> <input name="taxaImpressao" class="form-control"> </td>
</tr>
<?php require_once("cabecalho.php"); 
require_once("banco-categoria.php");
require_once("logica-usuario.php");

verificaUsuario();

$produto = array("nome" => "", "descricao" => "", "preco" => "", "categoria_id" => "1");
$usado = "";
$categorias = listaCategorias($conexao);
?>            
    <h1>Formulário de produto</h1>
    <form action="adiciona-produto.php" method="post">
        <table class="table">

            <?php include("produto-formulario-base.php"); ?>

            <tr>
                <td>
                    <button class="btn btn-primary" type="submit">Cadastrar</button>
                </td>
            </tr>
        </table>
    </form>
<?php include("rodape.php"); ?>

``` <?php require_once("conecta.php"); require_once("cabecalho.php");require_once("class/produtoDAO.php"); require_once("logica-usuario.php");

verificaUsuario();

$categoria = new Categoria; $categoria->setNome($produto_atual['categoria_nome']);

$tipoProduto = $_POST["tipoProduto"]; $factory = new ProdutoFactory();$produto = $factory->criaPor($tipoProduto);

echo $tipoProduto; var_dump($_POST); $produto->atualizaBaseadoEm($_POST); var_dump($produto);

$produtoDao = new ProdutoDAO($conexao);

if($produtoDao->insereProduto($produto)) { ?>

O produto <?= $produto->nome ?>, <?= $produto->getPreco() ?> foi adicionado.

<?php } else { $msg = mysqli_error($conexao); ?>

O produto <?= $produto->nome ?> não foi adicionado: <?= $msg?>

<?php } ?>

<?php include("rodape.php"); ?>

Achei que meu o código ficou com excesso de ifs, Isso não é legal. Apesar dele funcionar mesmo quando outra classes herança de produto for adicionada. O ideal é usar arrays, tenho que pensar em algo retornar o $resultado em um array, e cada classe setar seus atributos correspontes daquele array, sem ficar usando 3x o ifs.

<?php require_once("conecta.php"); require_once("cabecalho.php");require_once("class/produtoDAO.php"); require_once("logica-usuario.php");

verificaUsuario();

$categoria = new Categoria; $categoria->setNome($produto_atual['categoria_nome']);

$tipoProduto = $_POST["tipoProduto"]; $factory = new ProdutoFactory();$produto = $factory->criaPor($tipoProduto);

echo $tipoProduto; var_dump($_POST); $produto->atualizaBaseadoEm($_POST); var_dump($produto);

$produtoDao = new ProdutoDAO($conexao);

if($produtoDao->insereProduto($produto)) { ?>

O produto <?= $produto->nome ?>, <?= $produto->getPreco() ?> foi adicionado.

<?php } else { $msg = mysqli_error($conexao); ?>
O produto <?= $produto->nome ?> não foi adicionado: <?= $msg?>

<?php } ?>
<?php include("rodape.php"); ?>

Olá, Antonio.

Para recuperar o nome da categoria, você precisa modificar a query no método listaProdutos.

Alterar para: "select p.*, c.nome as nome_categoria from Produtos p join Categorias c on p.categoria_id = c.id order by p.id asc"

Nessa query está sendo recuperado todos os campos da tabela Produtos e apenas o campo nome da tabela Categorias.