Bonjour à tous,

Je viens poster sur le forum car je ne trouve pas de solution à mon problème.
Dans l'idée, je souhaite faire du versionning sur les champs d'une table et ainsi garder les précédentes versions pour revenir en arrière par exemple.

Partant de là, j'ai créé deux tables "objets" et "items" :

CREATE TABLE IF NOT EXISTS `objets` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
)
CREATE TABLE IF NOT EXISTS `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `objet_id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `value` varchar(255) NOT NULL,
  `version` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
)

Mes models :

class Objet extends AppModel{
    public $hasMany = array('Item');
}
class Item extends AppModel{
    public $belongsTo = 'Objet';
}

Une vue:

echo $this->Form->create('Objet');
    echo $this->Form->input('id');
    echo $this->Form->input('name');
    foreach($this->request->data'Item'] as $item){
        echo $this->Form->input('Item.'.$item'id'].'.id');
        echo $this->Form->input('Item.'.$item'id'].'.value', array('label'=>$item'name']));
    }
echo $this->Form->end('Save');

Et mon controller :

class ObjetsController extends AppController{
    public $scaffold;
    public function vu($id){
        $this->Objet->id = $id;
        $d = $this->Objet->read();
        debug($d);
    }
}

Donc je récupère bien mon objet et ses items.
Mais mon problème c'est que je veux récupérer que la dernière version des différents champs dans la table items, cad que je dois récupérer toutes les entrées où "objet_id" égal id de mon Objet, faire une sorte de select distinct sur la colonne "name" où la colonne version a la valeur la plus haute.
Je sais pas si ca parait clair tout ca ...
Peut-être je m'y prend de travers ...

Auriez vous une petite idée pour m'aider ?

Merci d'avance !
See you :)

5 réponses


aschelch
Réponse acceptée

Bonjour,

La traduction de la requête est :

$this->Item->find('all', array(
    'conditions' => array('Item.object_id' => 1),
    'joins' => array(
        array(
            'table' => '(SELECT t.name, MAX(t.version) as derniere_version FROM version t WHERE t.object_id=1 GROUP BY t.name)',
            'alias' => 'w',
            'type' => 'RIGHT',
            'conditions' => array('w.name = Item.name AND w.derniere_version = Item.version')                   
        )
    )
));

Ce n'est pas possible de faire cette requête directement avec un $this->Objet->find() car 'contain' ne peut pas contenir des jointures.
Donc tu as plusieurs possibilités :

  • Faire un callback afterFind() et utiliser la requête que je t'ai donnée juste au-dessus.

  • Faire une fonction dans ton model Object. Exemple:

    public function getObjectAndNewestItems($id){
    $res = $this->find('first', array('conditions'=>array('Object.id'=>$id), 'contain'=>false));
    $res'Item'] = $this->Item->find( ... ); // Requête juste au-dessus
    // ou
    $res'Item'] = $this->Item->findNewestItems($id); // Si tu met la requête dans le model Item
    return $res;
    }

=)

Boobha
Auteur

A mon avis ... vu le nombre de lu et le nombre de réponse, cad zéro, j'ai du mal m'expliquer ^^

Ma base :

ID OBJET_ID NAME VALUE VERSION
1 1 ville paris 1
2 1 pays france 1
3 1 ville nantes 2
4 2 ville blois 1
5 2 pays france 1

Pour résumer, comment faire une requête qui va récupèrer les entrées de cette table en considérant que le champ NAME doit être unique(select distinct), que le champ VERSION doit avoir plus plus grosse valeur(MAX) et que le champ OBJET_ID doit être égal à l'ID de mon objet(objet_id=id).

Donc la si je veux récup les entrées pou l'objet 1, ca devrait me retourner les entrées suivantes:
ID 2 et 3.

Merci

See you :D

Bonjour,

Dans ton exemple, pour récupérer les entrées 2 et 3, voila ce qu'il faut faire :

  • Récupérer le nom et la version la plus grande pour chaque nom où l'object_id est égal à 1

  • Récupérer les autre champs grâce a une jointure

En sql, ca donne :

SELECT v.* FROM version v 
RIGHT JOIN
    (SELECT t.name, MAX(t.version) as derniere_version FROM version t WHERE t.object_id=1 GROUP BY t.name) w
ON (w.name = v.name AND w.dernier_version= v.version)
WHERE v.object_id = 1

J'espère avoir répondu a ta question :)

Bonne journée

Boobha
Auteur

Hello Aschelch !

Merci pour ta réponse, c'est une bien belle requête :)
Est ce que tu saurais me la traduire en Cakephp via un $this->Item->find(...) ?
ou encore mieux via un :

$this->Objet->find('first', array(
    'conditions' => array('id'=>1),
    'contain' => array(
        'Item' => array(
            'conditions' => array(
                'Item.objet_id' => 1,
                ... (c'est là où je n'y arrive pas)
            )
       )
   )
);

Merci !

See You :)

Boobha
Auteur

Super merci beaucoup aschelch !
Ca marche nikel :D
Je n'aurais jamais trouvé solo ... bravo à toi ^^