CodeIgniter Datamapper – Selecionando objetos que não tenham determinados relacionamentos

Faz tempo que trabalho com Code Igniter e gosto muito do Datamapper (leia mais sobre este ORM aqui). Hoje surgiu uma necessidade nova em um projeto e achei interessante o suficiente para compartilhar aqui. Em uma relação many to manycomo selecionar objetos que não tenham um relacionamento específico?

Por exemplo, tenho os models product e category, com relacionamento de muitos para muitos nos dois casos (um produto pode ter várias categorias e uma categoria pode ter vários produtos).

Como selecionar produtos que não estejam na categoria canecas, por exemplo?

A resposta curta é: subqueries.

// query para pegar todos os produtos que tem categoria "canecas"
$sub_products = new Product();
$sub_products->select('id')->where_related_category('name', 'canecas');
// Agora usando subqueries, pega todos que não estão na categoria
$products = new Product();
$products->where_not_in_subquery('id', $sub_products)->get();

E se você precisa selecionar por exemplo todos os produtos que não estão relacionados com nenhuma categoria é só fazer um select que atenda na sua subquery, como por exemplo:

$sub_products->select('id')->where_related_category('id > 0');

Tem uma solução diferente? Deixa aí nos comentários!

File upload e image crop com CodeIgniter

Nada de muitas explicações sobre como implementar, vamos para um exemplo… o CodeIgniter possui classes para upload de arquivos e manipulação de imagens.

Para começar, crie a seguinte view chamada form.php:

<!DOCTYPE html>
<html lang="pt-br">
<head>
    <title>Upload e crop de imagem – CI</title>
</head>
<body>
<h1>Upload e crop de imagem – CI</h1>
<form action="/index.php/imagem/upload" enctype="multipart/form-data" method="post">
    <input type="file" name="userfile" />
    <button>enviar</button>
</form>
</body>
</html>

Então, crie o seguinte controller.

<?php
class Imagem extends Controller {

    function Imagem() {
        parent::Controller();   
    }
   
    function index() {
        $this->load->view("form");
    }

    function upload() {
        //parametriza as preferências
        $config["upload_path"] = "/var/www/uploads/";
        $config["allowed_types"] = "gif|jpg|png";
        $config["overwrite"] = TRUE;
        $this->load->library("upload", $config);
        //em caso de sucesso no upload
        if ($this->upload->do_upload()) {
            //renomeia a foto
            $nomeorig = $config["upload_path"] . "/" . $this->upload->file_name;
            $nomedestino = $config["upload_path"] . "/minhafoto" .  $this->upload->file_ext;
            rename($nomeorig, $nomedestino);
           
            //define opções de crop
            $config["image_library"] = "gd2";
            $config["source_image"] = $nomedestino;
            $config["width"] = 300;
            $config["height"] = 300;
            $this->load->library("image_lib", $config);
            $this->image_lib->crop();
           
        } else {
            echo $this->upload->display_errors();
        }

    }
}

O método index() apenas retorna para a view form.php. Já o método upload é que faz a mágica.

Nele, você configura as preferências do upload (caminho do arquivo a ser salvo, tipos de arquivo, etc…). Se o upload for feito com sucesso, renomeamos o arquivo e usando a classe de manipulação de imagens (deve ser feita a configuração das preferências, como qual a biblioteca a ser usada, dimensões e afins). Voi