Jump to content
Gabriel Heming

[Tutorial] Integridade de coleções com uso de Iterator

Recommended Posts

Muitas vezes durante o desenvolvimento em orientações a objetos, tive problemas usando coleções de objetos, principalmente quanto a integridade.

Veja o exemplo de uma Pessoa que possui uma lista de Contatos.

Aqui vemos a implementação simples de uma classe Pessoa com uma lista de contatos (demais métodos foram omitidos para simplificação):

class Pessoa {

    private $contatoList = array();

    public function setContatoList(array $contatoList) {
        $this->contatoList = $contatoList;
    }

    public function getContatoList() {
        return $this->contatoList;
    }
}

E, agora, nossa entidade de contato:

class Contato {
    
    const EMAIL = 1;
    const TELEFONE = 2;
    
    private $contato;
    private $tipo;
    
    public function __construct($contato , $tipo) {
        $this->contato = $contato;
        $this->tipo = $tipo;
    }
}

Com nossas entidades implementadas, vamos usufruir de suas funcionalidades:

$contatoList = array();
$contatoList[] = new Contato('(54) 9999-9999' , Contato::TELEFONE);
$contatoList[] = new Contato('email@provedor.com.br' , Contato::EMAIL);

$pessoa = new Pessoa();
$pessoa->setContatoList($contatoList);

var_dump($pessoa->getContatoList());

Saída:

Citar

array (size=2)
0 =>
object(Contato)[1]
private 'contato' => string '(54) 9999-9999' (length=14)
private 'tipo' => int 2
1 =>
object(Contato)[2]
private 'contato' => string 'email@provedor.com.br' (length=21)
private 'tipo' => int 1


Dessa forma implementamos rapidamente uma classe simples Pessoa com sua lista de Contatos. Entretanto, não é possível adicionar apenas um contato para a lista já existente e nem podemos garantir a integridade dos dados (algo muito importante na orientação a objetos). Veja Só:

$contatoList = array();
$contatoList[] = new Contato('(54) 9999-9999' , Contato::TELEFONE);
$contatoList[] = new Contato('email@provedor.com.br' , Contato::EMAIL);
$contatoList[] = 'meu email é email@provedor.com.br';

$pessoa = new Pessoa();
$pessoa->setContatoList($contatoList);

var_dump($pessoa->getContatoList());

Saída:

Citar

array (size=3)
0 =>
object(Contato)[1]
private 'contato' => string '(54) 9999-9999' (length=14)
private 'tipo' => int 2
1 =>
object(Contato)[2]
private 'contato' => string 'email@provedor.com.br' (length=21)
private 'tipo' => int 1
2 => string 'meu email é email@provedor.com.br' (length=29)

Como podemos ver na saída acima, tivemos um falha na integridade da lista. Foi permitida a inserção de item que não é um contato, apesar de "parecer ser um".

Como podemos garantir que sempre será inserido um Contato na lista de usuários e poder adicionar um usuário existente a lista de contatos?

Vamos mudar um pouco a implementação da classe Pessoa:

class Pessoa {
 
    private $contatoList = array();
 
    public function setContatoList(array $contatoList) {
        /** verificar se existe algum elemento que não é do tipo contato **/
        $callback = function($row) {
            return !$row instanceof Contato;
        };
 
        if(array_filter($contatoList , $callback)) {
            throw new \RuntimeException('Somente valores do tipo Contato são permitidos');
        }        
 
        $this->contatoList = $contatoList;
    }
 
    public function getContatoList() {
        return $this->contatoList;
    }
}

E vamos ao novo teste:

$contatoList = array();
$contatoList[] = new Contato('(54) 9999-9999' , Contato::TELEFONE);
$contatoList[] = new Contato('email@provedor.com.br' , Contato::EMAIL);
$contatoList[] = 'meu email é @provedor.com.br';
 
$pessoa = new Pessoa();
try {
    $pessoa->setContatoList($contatoList);
} catch (\RuntimeException $exception) {
    echo $exception->getMessage();
}

Saída:

Citar

Somente valores do tipo Contato são permitidos

A lógica é simples, sempre que algum item da lista não for um Contato, o array retornado por array_filter será maior que zero. Nesse caso, será lançada uma exceção informando que a lista não está correta.

Ok, garantimos, por enquanto e sem minha total satisfação, a integridade de adicionar apenas listas que contenham apenas contatos. Deixarei a implementação da lista parada por enquanto e vamos implementar a funcionalidade para adicionar um contato a lista já existente.

class Pessoa {
 
    private $contatoList = array();
 
    public function setContatoList(array $contatoList) {
        /** verificar se existe algum elemento que não é do tipo contato **/
        $callback = function($row) {
            return !$row instanceof Contato;
        };
 
        if(array_filter($contatoList , $callback)) {
            throw new \RuntimeException('Somente valores do tipo Contato são permitidos');
        }        
 
        $this->contatoList = $contatoList;
    }
    
    public function addContato(Contato $contato) {
        $this->contatoList[] = $contato;
    }
 
    public function getContatoList() {
        return $this->contatoList;
    }
}

Implementamos o método, na classe pessoa, para permitir que possamos adicionar apenas um contato a lista já existente, vamos ao teste:

$contatoList = array();
$contatoList[] = new Contato('(54) 9999-9999' , Contato::TELEFONE);
 
$pessoa = new Pessoa();
try {
    $pessoa->setContatoList($contatoList);
} catch (\RuntimeException $exception) {
    echo $exception->getMessage();
}
 
$pessoa->addContato(new Contato('email@provedor.com.br' , Contato::EMAIL));
 
var_dump($pessoa->getContatoList());

Saída:

Citar

array (size=2)
0 =>
object(Contato)[1]
private 'contato' => string '(54) 9999-9999' (length=14)
private 'tipo' => int 2
1 =>
object(Contato)[3]
private 'contato' => string 'email@provedor.com.br' (length=21)
private 'tipo' => int 1

 

Ok, ok e ok. Está funcionando da forma esperada. Mas esse código não está, como diria Kent Beck, "fedendo"?

Vamos a alguns pontos:
- Por que a classe Pessoa está validando a lista?
- Por que a classe Pessoa está implementando um método de lista?
- Por que meu café... digo... por que a classe Pessoa está assumindo essas responsabilidades?

A resposta é simples, o PHP não implementa nativamente essa integridade.

A partir de então, e com muita pesquisa, percebe-se que é necessário implementar esta integridade. Neste momento partimos para o design pattern Iterator. Para que quiser saber mais sobre o Iterator como um Design Pattern, sugiro a leitura deste tópico.

Vamos a implementação da classe generalizada para coleções. Classe a qual será nossa base para qualquer implementação de coleções de objetos.

Obs: Essas implementações fazem parte do meu TCC da Pós e implementadas sobre o namespace Harbinger, nome o qual utilizo para o desenvolvimento das minhas API/Plugins e framework de estudos.

 

namespace Harbinger\Iterator;
 
/**
 * @author Gabriel Heming <gabriel.heming@hotmail.com>
 * @package Harbinger\Iterator
 **/
abstract class Collection implements \Iterator {
  
    /**
     * @var Object[]
     **/
    protected $object = array();

    /**
     * @var int
     **/
    private $pointer = 0;

    /**
     * @var int
     **/
    protected $total = 0;

    /**
     * add an Object into collection
     * @param Object $object
     * @return $this
     * @throws \UnexpectedValueException If Object isn't part of a object kind
     **/
    public function add($object) {
        $class = $this->getTargetClass();

        if(!$object instanceof $class) {
            throw new \UnexpectedValueException("This is a {$class} collection");
        }

        $this->object[$this->total] = $object;
        $this->total++;

        return $this;
    }

    /**
     * retrieve the object from current position
     * @return Object
     * @throws \OutOfBound---ception If the collection not has any object
     **/
    public function current() {
        if(isset($this->object[$this->key()])) {
            return $this->object[$this->key()];
        }

        throw new \OutOfBound---ception("Index {$this->key()} not exists as a object index");
    }

    /**
     * retrieve the current key
     * @return int
     **/
    public function key() {
        return $this->pointer;
    }

    /**
     * move the pointer to next index position
     **/
    public function next() {
        $this->pointer++;
    }

    /**
     * move the pointer to beginning
     **/
    public function rewind() {
        $this->pointer = 0;
    }

    /**
     * check if the actual position is valid
     * @return boolean
     **/
    public function valid() {
        return (isset($this->object[$this->key()]));
    }

    /**
     * return the object kind for collection
     * @return string
     **/
    abstract public function getTargetClass();
}

Dessa forma, desenvolvemos nossa base abstrata para a criação de uma coleção. Nossa abstração exige apenas uma implementação, o método getTargetClass. Este método é reponsável por informar qual objeto a coleção será responsável por manipular, não permitindo a inserção de nenhum outro tipo de objeto.

A partir desse ponto, podemos prosseguir de duas formas: uma classe genérica para trabalhar com objetos especificados em tempo de execução ou uma classe especializada em um determinado tipo de objeto.

Pois bem, vamos realizar das duas formas, iniciando com a nossa classe genérica:

namespace Harbinger\Iterator\Collection;
 
/**
 * @author Gabriel Heming <gabriel.heming@hotmail.com>
 * @package Harbinger\Iterator
 * @subpackage Collection
 **/
class Object implements \Harbinger\Iterator\Collection {
 
    /**
     * @var string
     **/
    private $targetClass;
 
    public function __construct($targetClass) {
        $this->targetClass = $targetClass;
    }
 
    /**
     * {@inheritdoc}
     **/
    public function getTargetClass() {
        return $this->targetClass;
    }
}

Vamos a modificação da classe pessoa:

class Pessoa {
 
    private $contatoCollection;
    
    public function __construct() {
        $this->contatoCollection = new \Harbinger\Iterator\Collection(\Contato::class);
    }
 
    public function setContatoCollection(\Harbinger\Iterator\Collection $contatoCollection) {
        if($this->contatoCollection->getTargetClass() != $contatoCollection->getTargetClass()) {
            throw new \UnexpectedValueException(
                sprintf(
                    "Expected a %s collection. %s given."
                    $this->contatoCollection->getTargetClass(),
                    $contatoCollection->getTargetClass()
                )
            );                    
        }
        
        $this->contatoCollection = $contatoCollection;
    }
 
    public function getContatoCollection() {
        return $this->contatoCollection;
    }
}

E o nosso uso:

$contatoCollection = new \Harbinger\Iterator\Collection\Object('Contato');
$contatoCollection->add(new Contato('(54) 9999-9999' , Contato::TELEFONE));
 
$pessoa = new Pessoa();
try {
    $pessoa->setContatoCollection($contatoCollection);
} catch (\RuntimeException $exception) {
    echo $exception->getMessage();
}
 
$pessoa->getContatoCollection()->add(new Contato('email@provedor.com.br' , Contato::EMAIL));
 
foreach($pessoa->getContatoCollection() AS $contato) {
    var_dump($contato);    
}

Saída:

Citar

object(Contato)[2]
private 'contato' => string '(54) 9999-9999' (length=14)
private 'tipo' => int 2

object(Contato)[4]
private 'contato' => string 'email@provedor.com.br' (length=21)
private 'tipo' => int 1


A implementação genérica está pronta e funcionando como o desejado. E caso eu tente utilizar uma classe que suporte outro tipo de objetos, teremos uma exception:

$collection = new \Harbinger\Iterator\Collection\Object('Pessoa');
 
$pessoa = new Pessoa();
try {
    $pessoa->setContatoCollection($collection);
} catch (\RuntimeException $exception) {
    echo $exception->getMessage();
}

Saída:

Citar

Expected a Contato collection. Pessoa given.


A nossa única baixa, neste tipo de implementação, é a necessidade de verificar o tipo de coleção adicionada a pessoa. Mas vamos a nossa implementação específica que resolve esse problema
Neste caso, ao invés de utilizar uma coleção genérica, utilizarei uma coleção especializada para objetos do Contato.

namespace Collection;
 
class Contato extends \Harbinger\Iterator\Collection {
 
/**
 * {@inheritdoc}
 **/
public function getTargetClass() {
    return \Contato::class;
}

Realizemos as modificações (ou exclusões) necessárias na classe Pessoa, class a qual ficará mais "enxuta".

class Pessoa {
 
    private $contatoCollection;
    
    public function __construct() {
        $this->contatoCollection = new \Collection\Contato();
    }
 
    public function setContatoCollection(\Collection\Contato $contatoCollection) {        
        $this->contatoCollection = $contatoCollection;
    }
 
    public function getContatoCollection() {
        return $this->contatoCollection;
    }
}

E nossa utilização:

$contatoCollection = new \Collection\Contato();
$contatoCollection->add(new Contato('(54) 9999-9999' , Contato::TELEFONE));
 
$pessoa = new Pessoa();
try {
    $pessoa->setContatoCollection($contatoCollection);
} catch (\RuntimeException $exception) {
    echo $exception->getMessage();
}
 
$pessoa->getContatoCollection()->add(new Contato('email@provedor.com.br' , Contato::EMAIL));
 
foreach($pessoa->getContatoCollection() AS $contato) {
    var_dump($contato);    
}

Saída:

Citar

object(Contato)[2]
private 'contato' => string '(54) 9999-9999' (length=14)
private 'tipo' => int 2

object(Contato)[4]
private 'contato' => string 'email@provedor.com.br' (length=21)
private 'tipo' => int 1


Como está se tornando frequente, obtivemos exito quanto o sucesso da implementação.
Uma classe específica nos da a vantagem de uma modelagem mais específica, utilizando o type hint da coleção necessária. Entretanto, nos gera granularidade, pois cada coleção especializada necessita de uma implementação e isso nos é traduzido através de uma nova classe.

Voltando ao Iterator, estou sentindo falta de algumas implementações, por exemplo, Iterator não permite contar quantos objetos existem em sua coleção, veja:

$collection = new \Collection\Contato();
$collection->add(new Contato('(54) 9999-9999' , Contato::TELEFONE));
$collection->add(new Contato('email@provedor.com.br' , Contato::EMAIL));
echo 'Quantidade de contatos: '.count($collection);

Saída:

Citar

Quantidade de contatos: 1


Mas como 1? Se eu tenho dois elementos? Como podemos resolver esse problema?

Para este fim, podemos utilizar a interface Countable. Para essa interface devemos implementar apenas um método denominado count. Vamos a implementação:

namespace Harbinger\Iterator;
 
abstract class Collection implements \Iterator , \Countable {
    
    /** demais métodos e propriedades omitidos **/
 
    /**
     * retrieve the number of rows
     * @return int
     **/
    public function count() {
        return (int)$this->total;
    }
}

E, agora, vamos novamente ao uso:

$collection = new \Collection\Contato();
$collection->add(new Contato('(54) 9999-9999' , Contato::TELEFONE));
$collection->add(new Contato('email@provedor.com.br' , Contato::EMAIL));
echo 'Quantidade de contatos: '.count($collection);

Saída:

Citar

Quantidade de contatos: 2

 

Neste momento, podemos contar quantos objetos nossa coleção possui.

Uma outra implementação interessante, é a interface SeekableIterator. Essa interface define que podemos ir para qualquer registro em específico e não apenas iterar sobre nossa coleção. A interface SeekableIterator extende a interface Iterator, logo devemos substituir a interface Iterator e utilizar em seu lugar a interface SeekableIterator. Vamos a nossa implementação:

 

namespace Harbinger\Iterator;
 
abstract class Collection implements \SeekableIterator , \Countable {

    /** demais métodos e propriedades omitidos **/

    /**
     * Seeks to a given position in the iterator.
     * @param int $position
     * @throws \OutOfBound---ception If an invalid position has been given
     **/
    public function seek($position) {
        if (!isset($this->object[$this->key()])) {
            throw new \OutOfBound---ception("invalid seek position ($position)");
        }
 
        $this->pointer = $position;
    }
}

Vamos a nosso teste recorrente:

try {
    $collection = new \Collection\Contato();
    $collection->add(new Contato('(54) 9999-9999' , Contato::TELEFONE));
    $collection->add(new Contato('email@provedor.com.br' , Contato::EMAIL));
    var_dump($collection->current());
    
    $collection->seek(1);
    var_dump($collection->current());
    
    $collection->seek(2);
    var_dump($collection->current());    
} catch (\RuntimeException $exception) {
    echo $exception->getMessage();
}


Saída:

Citar

object(Contato)[2]
private 'contato' => string '(54) 9999-9999' (length=14)
private 'tipo' => int 2

object(Contato)[3]
private 'contato' => string 'email@provedor.com.br' (length=21)
private 'tipo' => int 1

Index 2 not exists as a object index


Com um pouco de implementação, conseguimos um grande avanço na integridade quanto a orientação à objetos. Outra interface interessante para se utilizar com Iterator é ArrayAccess que permite que objetos sejam acessados como arrays. Essa implementação, deixarei para os interessados :yes:

No próximo artigo, quero demonstrar o uso de Iterator com dados retornados do banco de dados e a sua criação em tempo de execução.

Dúvidas, sugestões e críticas são muito bem vindas!


------

Código disponibilizado como pacote do composer:
https://bitbucket.org/harbingerproject/iterator

Para realizar a instalção do pacote, basta adicionar o repositório ao composer e adicionar como requerimento:

composer.json

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://username@bitbucket.org/harbingerproject/iterator.git"
        }
    ],
    "require": {
        "harbinger/iterator": "^1.0.2",
    }
}

E rodar o comando composer install (pode ser executado em qualquer sistema operacional).

  • +1 4

Share this post


Link to post
Share on other sites

Valeu Beraldo!

 

Dá para brincar bastante com essa implementação.

Share this post


Link to post
Share on other sites

Show..

Eu so aproveitaria o próprio valid() no current() e no seek()

Implementar uma Validação com FilterIterator, você acha que seria interessante?

 
    public function seek($position) {
        if ($this->valid() === false) {
            throw new \OutOfBound---ception("invalid seek position ($position)");
        }
 
       $this->pointer = $position;
    }

Share this post


Link to post
Share on other sites

Show..

Eu so aproveitaria o próprio valid() no current() e no seek()

Obrigado pela sugestão. No current é possível sim, acabei não utilizando pois isso fará parte da segundo tutorial, mas isso é segredo por enquanto :pinch:

 

Já no seek não é possível, pois o valid apenas valida posição atual, uma vez que a posição a ser definida no seek pode não existir eu não posso definir a posição sem antes ser validada.

 

Se eu definir, validar e, então, essa posição não existir, eu teria que voltar para a posição antiga. Dessa forma teria que manter a posição antiga em memória.

 

Implementar uma Validação com FilterIterator, você acha que seria interessante?

 

Sim, muito. Eu tenho uma implementação do FilterIterator que segue a mesma linha do array_filter. Como é algo simples, eu posso demonstrar aqui abaixo:

namespace Harbinger\Iterator\Filter;

/**
 * @author Gabriel Heming <gabriel.heming@hotmail.com>
 * @package Harbinger\Iterator
 * @subpackage Filter
 **/
class Custom extends \FilterIterator {

    /**
     * @var \Closure
     **/
    private $closure;

    /**
     * @param \Iterator $iterator
     * @param \Closure $closure
     **/
    public function __construct(\Iterator $iterator , \Closure $closure) {
        parent::__construct($iterator);

        $this->closure = $closure;
    }

    /**
     * Check whether the current element of the iterator is acceptable
     * @return boolean
     **/
    public function accept() {
        $closure = $this->closure;

        return $closure($this->getInnerIterator()->current());
    }

}

Dessa forma, eu posso criar uma validação em tempo de execução, exatamente como é criado para array_filter.

 

Caso eu queira contatos apenas do tipo email, eu posso criar dessa forma:

$contatoCollection = $pessoa->getContatoCollection();

$callback = function($contato) {
   return $contato->isTipo(\Contato::EMAIL);
};

$filteredIterator = new \Harbinger\Iterator\Filter\Custom($contatoCollection , $callback);

foreach($filteredIterator AS $contato) {
   var_dump($contato);
}
Edited by Gabriel Heming
adicionar comentários
  • +1 1

Share this post


Link to post
Share on other sites

 

 

Já no seek não é possível, pois o valid apenas valida posição atual, uma vez que a posição a ser definida no seek pode não existir eu não posso definir a posição sem antes ser validada.

 

Realmente. mas também afetaria o key().

 

Bom não testei aqui, posso estar enganado, mas, se vc por acaso usar o seek, (claro de forma displicente) um descuido.

$collection->seek(1);
$collection->seek(2); // mesmo existindo a index, a exception seria lançada.
 
var_dump($collection->current());

   public function seek($position) {
        if (!isset($this->object[$position])) {
            throw new \OutOfBound---ception("invalid seek position ($position)");
        }

Share this post


Link to post
Share on other sites

Valeu Williams Duarte! o/

Luis Paullo, a ideia é que sempre que não exista o index, seja lançada uma exceção e o ponteiro não seja movimentado. Mas isso não ocorrerá da forma que está sugerindo (lançar uma exceção mesmo que exista um index), pelo menos da forma que eu entendi.

Uma vez que o index existe, é alterado o ponteiro ($pointer). Tanto os métodos valid() como key() utilizam o ponteiro como referência.

Para eu utilizar o valid() no método seek, teria que ser feito dessa forma:

namespace Harbinger\Iterator;
 
abstract class Collection implements \SeekableIterator , \Countable {

    /** demais métodos e propriedades omitidos **/

    /**
     * Seeks to a given position in the iterator.
     * @param int $position
     * @throws \OutOfBound---ception If an invalid position has been given
     **/
    public function seek($position) {
        $oldPosition = $this->pointer;
        
        $this->pointer = $position;        
        
        if (!$this->valid()) {
            $this->pointer = $oldPosition;
            
            throw new \OutOfBound---ception("invalid seek position ($position)");
        }        
    }
}

E é a alteração "reversa" que eu quero evitar, uma vez que é de responsabilidade do método seek() movimentar o o ponteiro quando ele for válido.

 

Mas visando a reutilização e duplicação de código, eu poderia implementar da seguinte forma:

namespace Harbinger\Iterator;
 
abstract class Collection implements \SeekableIterator , \Countable {

    /** demais métodos e propriedades omitidos **/
    
    /**
     * check if the actual position is valid
     * @return boolean
     **/
    public function valid() {
        return $this->isValid($this->key());
    }

    /**
     * Seeks to a given position in the iterator.
     * @param int $position
     * @throws \OutOfBound---ception If an invalid position has been given
     **/
    public function seek($position) {
        if (!$this->isValid($position)) {
            throw new \OutOfBound---ception("invalid seek position ($position)");
        }

        $this->pointer = $position;
    }
    
    /**
     * check if the given position is valid
     * @param int $position
     * @return boolean
     **/
    protected function isValid($position) {
        return (isset($this->object[$position]));
    }
}

Encapsulo a forma de validação em um novo método, denominado isValid(), e, a partir de então, os métodos valid() e seek() passam a utilizar esse método de validação.

Edited by Gabriel Heming
Corrigir código

Share this post


Link to post
Share on other sites

kkkk. As ideias com relação ao seek é clara, como disse não testei nd so fiz uma observação irrelevante sobre seu código, ai nossas ideias não bateram. kkkk.

Mas entendi perfeitamente o seu conceito.

 

No fim era realmente pra buscar (apesar de bem pequena)

 

 

reutilização !!

 

você chego bem no ponto.

Share this post


Link to post
Share on other sites

Enquanto estive fora, fiquei preparando os próximos tutoriais. Também disponibilizei a biblioteca acima como biblioteca do composer.

 

Para quem quiser acompanhar o desenvolvimento do projeto, pode acompanhar pelo repositório: Harbinger Project

 

Código disponibilizado como pacote do composer:
Para realizar a instalção do pacote, basta adicionar o repositório ao composer e adicionar como requerimento:
composer.json
{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://username@bitbucket.org/harbingerproject/iterator.git"
        }
    ],
    "require": {
        "harbinger/iterator": "^1.0.2",
    }
}
E rodar o comando composer install (pode ser executado em qualquer sistema operacional).
-----
Nos próximos tutoriais ensinarei como dar continuidade com essa biblioteca em um sistema real (não só a teoria sempre muito bonitinha) e como criar seus próprios pacotes, sejam eles públicos ou privados (para uso interno da sua empresa).
  • +1 1

Share this post


Link to post
Share on other sites

Acompanhando e testando, é sempre bem vindo novos tutorias.

Pena que o Fórum não tem mais uma área reservada para os tutorias e em destaque, um erro dos Admins terem retirado os sub-fórum, ao meu ver um tiro no pé, pois era um jardim de pouso para futuros clientes do próprio Imasters.

Mas como programadores não são marqueteiros... B)

Obrigado!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • By britoriquee
      Olá pessoal!

      Tenho dois bancos: dt_dblogin e dt_dbdados, o primeiro salva os dados de login do usuário, como login, senha, id, etc... Já o segundo salva dados da empresa do usuário, como nome, endereço, cnpj, dentre varios outros. 
       
      A minha dúvida é: Como faço para verificar qual usuário está logado para liberar o conteúdo certo da empresa dele que está no outro banco? 
       
      Agradeço a atenção.
    • By leonardoc.g
      Quando eu tento fazer conexão no banco de dados pelo Dreamweaver me aparece essa mensagem:
       
      your php server doesn't have the MySQL module loaded or you cant't use the mysql_(p)connect functions
       
       
    • By Julie_santiago
      Olá!
      Pessoal, preciso muito de um help urgente. Estou tentando fazer uma simples query ao banco de dados, usando o Axios. Mas, não importa a forma de fazer a requisição, o Axios não funciona. O HTML está abaixo, onde chamo a função enviaDados() através do onsubmit.
      <div class="input-group md-form"> <form method="get" onsubmit="enviaDados()" name="buscar"> <input type="text" id="Form-search2" class="form-control" name="nomeReagente"> <label for="Form-search2">Search</label> <input type="submit" name="pesquisar" value="buscar"> </form> <span class="input-group-text dark lighten-2" id="basic-text1"> <i class="fas fa-search text-dark" aria-hidden="true"></i> </span> </div> Meu arquivo main.js que contém a função enviaDados().
      function enviaDados(){ let nome = buscar.nomeReagente.value recebeDados(nome); } Dentro dessa função, estou chamando outra: recebeDados() que executa a requisição Axios. Passo como parâmetro o valor lá do meu input. OBS.: Meu código está assim, aparentemente confuso, porque o objetivo é ter funções que enviam os dados dos meus formulários e outras funções (genéricas) para receber e tratar esses dados. Abaixo a função recebeDados():
      function recebeDados(nome_reagente){ axios.get('http://localhost/Quimica/php/recebe_json.php', { params: { nome } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log('Não foi possível realizar a requsição: '+error); }) .finally(function () { }); } Não importa o que eu faça, sempre cai no CATCH  - request aborted. Preciso muito resolver esse problema, mas não faço ideia do que pode ser. Relevem qualquer "noobice" porque estou aprendendo o básico ainda.
       
    • By JeanTDZ
      Olá pessoal!
       
      Estou com uma tremenda dificuldade.
      Tenho um formulário na qual está funcionando e cadastrando, porém preciso que o meu botão adicionar autorizado funcione e mostre o que foi digitado para o e-mail. As informações na vdd é enviada para o e-mail e o que será enviado é oque será digitado.
       
      Simplificando ->
      Tenho um botão que adiciona 2 inputs (NOME E SALDO) e conforme for clicando nesse botão, vai adicionando mais campos.
      Dúvida: Como posso fazer com que grave o que foi digitado nesses campos?
       
      Segue o que eu tentei fazer até agora:

      HTML
      <!DOCTYPE html> <html>     <head>         <title>Chame Taxi PrePago</title>                 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>         <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />         <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>         <link rel="icon" type="image/x-icon" href="https://www.flaticon.com/premium-icon/icons/svg/1361/1361253.svg" />         <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>     <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.mask/1.14.15/jquery.mask.min.js"></script>     <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>     <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>     </head>     <body>         <br />         <div class="container" style="width:100%; max-width:600px">             <h2 align="center">Pré-Pago</h2>             <br />             <div class="panel panel-default">                 <div class="panel-heading"><h4>Registrar</h4></div>                 <div class="panel-body">                     <form method="post" id="register_form">                         <?php echo $message; ?>                         <div class="form-group">                             <label>Nome Completo</label>                             <input type="text" name="user_name" style="text-transform:uppercase" class="form-control" pattern="[a-zA-Z ]+" required />                         </div>                         <div class="form-group">                             <label>E-mail</label>                             <input type="email" name="user_email"  style="text-transform:uppercase" class="form-control" required />                         </div>                         <div class="form-group">                             <label>CEP</label>                             <input type="text" name="campob" id="cep" value="" maxlength="9" onblur="pesquisacep(this.value);" class="form-control">                         </div>                         <div class="form-group"> <table id="myTable" class="table"> <a class="btn btn-primary" onclick="myFunction()" href="#" role="button">Adicionar Autorizado</a>             <thead>                 <tr>                     <th>NOME</th>                     <th>SALDO</th>                 </tr>             </thead>         </table>                         <div class="form-group">                             <input type="submit" name="register" id="register" value="Validar" class="btn btn-info" />                         </div>                     </form>                 </div>             </div>         </div>     </body> </html> JAVASCRIPT 
       
          <script>         var incremento = -1;         function myFunction() {             incremento++;             var table = document.getElementById("myTable");             var row = table.insertRow(0);             var cell1 = row.insertCell(0);             var cell2 = row.insertCell(1);             var cell3 = row.insertCell(2);             var cell4 = row.insertCell(3);             cell1.innerHTML = "NOME";             cell2.innerHTML = '<input type="text" name="name1[${incremento}]" >';             cell3.innerHTML = "SALDO";             cell4.innerHTML = '<input type="text" name="saldo[${incremento}]" size="15px" >';         }     </script>  
    • By gramosiri2
      Oi estou tentando passar um valor através de uma variável em uma query, porém não está mostrando o resultado que eu quero.
       
      Aqui eu pego o ultimo id do pedido
      <?php while($row = $consulta_pedido2->fetch_assoc()){ echo $row['id_pedido']; }?> E aqui eu faço a query e passo variável...
      $query ="SELECT itempedido.id_itempedido, itempedido.valor, ... FROM itempedido INNER JOIN produto ON ... WHERE itempedido.pedido_id = '$row'"; No caso onde está a variável $row, se eu colocar o numero do pedido manualmente, me retorno os itens daquele pedido, agora com a variável não está mostrando, alguma ideia?
×

Important Information

Ao usar o fórum, você concorda com nossos Terms of Use.