Salvando objetos com ID definido no Data Mapper (CI)

Desde que comecei a estudar e utilizar o Code Igniter eu recomendo o uso do ORM Data Mapper, que facilita a vida nas consultas ao banco de dados (leia: tutorial do Data Mapper no Code Igniter), esta semana ele mais uma vez se mostrou muito útil enquanto eu fazia a migração do banco antigo do And After para o novo.

Depois de dominar (yeaaaah) relacionamento de tabelas com o Code Igniter (usando o Data Mapper) e finalizar o sistema do And After neste framework estou fazendo a migração de todo o conteúdo para a nova plataforma: textos, comentários, cadastro de usuários, logs, tags, blogs…

Achei que seria extremamente trabalhoso, pois toda a estrutura de banco foi alterada – recomecei o sistema do zero sem pensar na migração, fiz isso para evitar "puxadinhos" e gambiarras (que com o crescimento de sistema, estava cheio) e desenvolver tudo direito, do zero, um sistema novo.

No ônibus voltando para São Paulo fiz em alguns minutos a migração dos usuários e iniciei a dos textos (que será um pouco mais complicada devido aos relacionamentos), mas tive um problema com o Data Mapper: não perder os ID"s dos objetos que estão sendo migrados.

Como salvar um objeto com um ID existente?

O Data Mapper usa o atributo ID do objeto para verificar se ele deve fazer um insert ou um update, se o objeto ID existe ele fará um UPDATE, portanto você não consegue setar o ID de um objeto e usar o $object->save();, pois ele fará um update mesmo que o objeto não exista (e não vai acontecer nada no seu banco).

Para isso o Data Mapper tem a função save_as_new, segue um exemplo abaixo:

$user = new User();
$user->id = 1;
$user->login = "Admin";
$user->password = "password";
$success = $user->save_as_new();

Se não deu nenhum problema no seu banco (neste caso ele deveria estar limpo) você acabou de criar um usuário "Admin" com o id 1na sua tabela.

Problemas comuns

Após fazer a migração pode acontecer problemas ao tentar salvar novos objetos na tabela, isso pode acontecer porque o auto_increment (do ID) não foi atualizado – e está tentando inserir um novo objeto na tabela com um ID que já foi registrado "na mão".

Para facilitar o entendimento vamos a ao exemplo do caso da migração do And After. Existem aproximadamente 1.500 usuários cadastrados no site, após a migração o último ID utilizado na tabela de usuários foi o 1600 (devido a usuários excluídos, testes no banco, etc).

Preciso avisar a minha tabela que o próximo auto_increment (ID) é 1601, e não 1 (que seria o primeiro inserido de forma "natural", sem ID setado). O código abaixo executa esta atualização no banco:

// Update MySQL AUTO_INCREMENT:
$user->db->query("ALTER TABLE `users` AUTO_INCREMENT = 1601;");

Agora a migração da tabela users está completa e é possível utilizar ela normalmente.

Para mais dúvidas sobre o save leia a documentação do data mapper (EN).

Arredondamento de números no PHP

Estava desenvolvendo a paginação do And After em PHP (utilizando o Code Igniter com Data Mapper) e para isso era necessário calcular o número de páginas que seria necessário para exibir todos os posts de uma busca, tag ou categoria. A fórmula para isso é simples:

Total de itens que serão exibidos / máximo de itens por página

No caso de paginação o arredondamento deve ser sempre para cima – a última página mesmo que não tenha o número máximo de itens, deve existir.

Jabulani

Redondinho redondinho…

Vamos ao código!

Arredondamento de um número inteiro em PHP

Bom, seguem as formas mais simples para arredondamento e escolha da forma de arredondamento (automático, para cima, para baixo) que encontei no PHP:

Arredondamento automático

Round é a função básica para arredondamento automático:

echo round(7.3);    //  7
echo round(2.999);  //  3
echo round(-6.12);  //  -6

Arredondamento para cima

No caso da paginação, utilizei ceil, que arredonda sempre para o próximo número inteiro:

echo ceil(4.3);    // 5
echo ceil(9.999);  // 10
echo ceil(-3.14);  // -3

Arredondamento para baixo

O floor é "o contrário" do ceil, ele arredonda para o primeiro número inteiro anterior ao número passado.

echo floor(4.3);   // 4
echo floor(9.999); // 9
echo floor(-3.14); // -4

 

É isso, espero que isso tenha esclarecido a você questões sobre o arredondamento numérico em php, existem outras funções similares porém acredito que com estas 3 seja possível desenvolver o necessário no quesito "arredondar".

Espero que ajude, sugestões e críticas nos comentários! 🙂

Mercado de trabalho – A vaga de PHP é sua…

As vezes vejo no Twitter algumas oportunidades de emprego para desenvolvedores, repasso algumas no twitter do O Desenvolvedor (follow us!) e tem algumas que são muito engraçadas tristes.

Exemplo de uma que li recentemente, de uma agência de SP e RJ:

Para uma vaga de web-developer Júnior:

Pré-requisitos:

  • Sólidos conhecimentos de HTML/CSS (W3C), JavaScript (Ajax), PHP e MySQL;

  • Experiência com administração remota de plataformas UN*X;

  • Entendimento de linguagens de programação de uso genérico (C/C++/Java/Perl/Python/etc);

  • Capacidade de elaborar soluções próprias em programação;

  • Possuir um portfólio online.

Desejável conhecimento de:

  • ActionScript 3;

  • Frameworks de JavaScript (jQuery/YUI/etc);

  • Shell scripting;

  • Especificações do protocolo HTTP/1.1;

  • Uso das APIs dos webservices (Flickr/Google/Twitter/YouTube/etc);

  • WordPress (elaboração de temas e/ou plugins).

 

Destaque para "linguagens de programação de uso genérico (C/C++/Java/Perl/Python)", especificações do protocolo HTTP/1.1 e shell scripting.

Oportunidade de trabalho…

A oportunidade existe desde que você seja um back-front-end developer com conhecimentos em gerenciamento e protocolo de redes, domine frameworks e algumas linguagenzinhas genéricas que vão do ASP, PHP, Python até o Cobol.

Profissional transformer
(ou o famoso tapa-buraco)

 

Mas nem tudo é tristeza, ainda existem algumas empresas que conseguem dividir e focar em pessoas com conhecimentos específicos. Mas só algumas, enquanto isso o Roberto Justus tem uma mensagem a você, que está procurando uma vaga de programador PHP:

 

E você, quer compartilhar sua opinião sobre o mercado de trabalho para programadores? Comenta aí!

Como pegar o IP de um usuário com o PHP

Sem rodeios, sem mimimi´s, este deve ser o post mais curto já visto aqui no O Desenvolvedor, uma função para pegar o IP do usuário utilizando o PHP.

Usando getenv (para pegar "variáveis do ambiente"):

// Example use of getenv()
$ip getenv("REMOTE_ADDR");

 

E usando a variável superGlobal $_SERVER


// Or simply use a Superglobal ($_SERVER or $_ENV)
$ip $_SERVER["REMOTE_ADDR"];

 

Pronto, simples assim.

Precisei disto para um controle em um método do novo And After e resolvi compartilhar, apesar já ser de conhecimento de qualquer um que domine o PHP pode ajudar alguns n00bs como eu, que ainda não conhecem a sintaxe de cabo a rabo.

 

Direto do PHP Manual

Relacionamento de tabelas no Data Mapper (CI)

Se você não entendeu muito bem o post explicando como melhorar as recomendações de posts relacionados com o Data Mapper, este tutorial poderá ajudar.

Criei um material para apoiar a documentação do Data Mapper sobre o relacionamento de tabelas no banco de dados. Se você não está entendendo nada, recomendo que antes de continuar você leia:

  1. Usando o Data Mapper no Code Igniter – como instalar e configurar o Data Mapper
  2. Entendo o relacionamento de banco de dados

 

Nomenclatura das tabelas relacionais no Data Mapper

O primeiro passo para fazer o relacionamento de tabelas funcionar é estruturar o banco de dados para isso. Para ilustrar este post vamos criar um relacionamento "one to many" de usuários para posts.

Na nossa estrutura do banco de dados temos a tabela users e a tabela posts.

Por regra do Data Mapper as tabelas de relacionamento devem ser estruturadas da seguinte forma:

  1. Nome da primeira tabela do relacionamento (ordem alfabética)
  2. Underline "_"
  3. Nome da segunda tabela do relacionamento

No nosso caso temos as tabelas "users" e "posts", portanto nossa tabela de relacionamento que deve ser criada no banco de dados se chamará "posts_users" e terá três colunas:

id - INT, auto increment

user_id - INT

post_id - INT

Pronto, com esta tabela criada no nosso banco de dados podemos configurar nossas classes "User" e "Post" no Data Mapper.

 

Configurando as classes para relacionamento

Continuando o exemplo anterior da classe User, vamos adicionar a configuração de relacionamento, ela ficará assim:

class User extends DataMapper {
    var $table = "users";

    var $has_many= "posts, comments";

    function User()
    {
        parent::DataMapper();
    }
}

E agora nossa clase Post:

class Post extends DataMapper {
    var $table = "posts";

    var $has_one= "user";
    var $has_many= "comments";

    function User()
    {
        parent::DataMapper();
    }
}

 

Pronto, suas tabelas estão relacionadas pelo Data Mapper e você pode usufruir as facilidades do ORM para criar "innerjoins" que eu não entendo!

 

Salvando dados de relacionamento

Para salvar um relacionamento é simples, criamos os dois objetos que vamos relacionar e usamos o método save do Data Mapper.

É mais fácil exemplificar do que explicar:


$u = new User();
$u->where("login", "odesenvolvedor")->get();

$p = new Post();
$p->title = "Novo post"; $p->content = "Conteúdo html do nosso post"

// Salvamos o novo post e relacionamos ao nosso User
$p->save($u);

Para relacionar dois objetos já existentes a lógica é a mesma:

$u = new User();
$u->where("login", "odesenvolvedor")->get();

$p = new Post();
$p->
where("title", "Novo Post"); $p->get();

// Relacionamos o Post que já existia ao nosso User
$p->save($u);

Este é o básico do relacionamento de dados utilizando o Data Mapper. Para entender recomendo a leitura da documentação do DM.

Para um exemplo prático mais avançado veja como selecionar posts mais relevantes através da comparação de tags.