Bonjour,
J'ai deux tables:
CREATE TABLE `tvs` (
`TV_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`TV_NOM` varchar(255) NOT NULL,
`TV_SLIDE` varchar(255) DEFAULT NULL,
`TV_SLIDE_VERSION` int(10) unsigned DEFAULT NULL,
`TV_WIDTH` smallint(6) NOT NULL,
`TV_HEIGHT` smallint(6) NOT NULL,
`TV_REFRESH_TIME` int(11) NOT NULL,
`TV_DATE_DERNIÈRE_CONNEXION` datetime DEFAULT NULL,
PRIMARY KEY (`TV_ID`),
KEY `TV_NOM` (`TV_NOM`(191))
) ENGINE=InnoDB;
CREATE TABLE `slides` (
`SLIDE_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`SL_SLIDE` varchar(255) NOT NULL,
PRIMARY KEY (`SLIDE_ID`)
) ENGINE=InnoDB;
Pour relier ces deux tables, j'ai une table de relations:
CREATE TABLE `slides_tvs` (
`TV_ID` int(10) unsigned NOT NULL,
`SLIDE_ID` int(10) unsigned NOT NULL,
`TS_JOURS_SEMAINE` bit(7) NOT NULL,
`TS_DATE_DÉBUT` date NOT NULL,
`TS_DATE_FIN` date NOT NULL,
`TS_HEURE_DÉBUT` time NOT NULL,
`TS_HEURE_FIN` time NOT NULL,
PRIMARY KEY (`TV_ID`,`SLIDE_ID`),
KEY `TS_JOURS_SEMAINE` (`TS_JOURS_SEMAINE`),
KEY `TS_DATE_DÉBUT` (`TS_DATE_DÉBUT`),
KEY `TS_DATE_FIN` (`TS_DATE_FIN`),
KEY `TS_HEURE_DÉBUT` (`TS_HEURE_DÉBUT`),
KEY `TS_HEURE_FIN` (`TS_HEURE_FIN`),
KEY `slides_tvs_ibfk_slide_id` (`SLIDE_ID`),
CONSTRAINT `slides_tvs_ibfk_slide_id` FOREIGN KEY (`SLIDE_ID`) REFERENCES `slides` (`SLIDE_ID`),
CONSTRAINT `slides_tvs_ibfk_tv_id` FOREIGN KEY (`TV_ID`) REFERENCES `tvs` (`TV_ID`)
) ENGINE=InnoDB;
J'ai donc créé deux classes "Tables":
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class TvsTable extends Table {
public function initialize(array $config) {
$this->belongsToMany('Slides', [
'joinTable' => 'slides_tvs',
'foreignKey' => 'tv_id',
'targetForeignKey' => 'slide_id'
]);
}
}
?>
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class SlidesTable extends Table {
public function initialize(array $config) {
$this->belongsToMany('Tvs', [
'joinTable' => 'slides_tvs',
'foreignKey' => 'slide_id',
'targetForeignKey' => 'tv_id'
]);
}
}
?>
Dans mon controller voici mon code:
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\ORM\TableRegistry;
use Cake\Event\Event;
use Cake\Auth\BaseAuthenticate;
use Cake\Auth\DefaultPasswordHasher;
use Cake\View\Helper\HtmlHelper;
use App\Model\Entity\TvsEntity;
class TvsController extends AppController {
public function ModifierTv($id) {
$query_tv = TableRegistry::get('tvs');
$rows_tv = $query_tv->find('all')->where(['tv_id' => 1])->contain(['Slides'])->all();
debug($rows_tv);
debug($rows_tv->first()->slides);
}
}
?>
Et je me retrouve avec une propriété Slides dans "$rows_tv" mais qui est désespérément vide...
Alors qu'il existe une relation pour l'id_tv = 1 avec un slide...
De plus quand je regarde les "Sql-log" je vois:
SELECT SlidesTvs.slide_id AS `SlidesTvs__slide_id`, SlidesTvs.TV_ID AS `SlidesTvs__TV_ID`, SlidesTvs.SLIDE_ID AS `SlidesTvs__SLIDE_ID`, SlidesTvs.TS_JOURS_SEMAINE AS `SlidesTvs__TS_JOURS_SEMAINE`, SlidesTvs.TS_DATE_DÉBUT AS `SlidesTvs__TS_DATE_DÉBUT`, SlidesTvs.TS_DATE_FIN AS `SlidesTvs__TS_DATE_FIN`, SlidesTvs.TS_HEURE_DÉBUT AS `SlidesTvs__TS_HEURE_DÉBUT`, SlidesTvs.TS_HEURE_FIN AS `SlidesTvs__TS_HEURE_FIN`, Slides.SLIDE_ID AS `Slides__SLIDE_ID`, Slides.SL_SLIDE AS `Slides__SL_SLIDE` FROM slides Slides INNER JOIN slides_tvs SlidesTvs ON Slides.SLIDE_ID = (SlidesTvs.slide_id) WHERE SlidesTvs.tv_id in ('1')
Et cette requête renvoie bien un résultat...
Quelqu'un peut-il m'aider ?
Merci d'avance,
Alain
Bonjour à tous,
J'ai finalement trouvé la solution.
1) Dans mes routes, j'avais écris:
Router::connect('/', ['controller' => 'tvs', 'action' => 'login']);
Alors qu'il fallait indiquer:
Router::connect('/', ['controller' => 'Tvs', 'action' => 'login']);
Si vous ne mettez pas le première lettre du controller en majuscule, ça fonctionne sauf que lorsque vous voulez accéder au modèle par défaut depuis votre controller, là cela ne fonctionne plus...
2) Il faut mettre les noms des champs de la base de données en minuscule... c'est ce qui empêchait le belongsToMany de fonctionner...
Merci à tous,
Bonjour.
Alors pour commencer, évites le plus possible de mettre des noms de champs en majuscule ainsi qu'avec des accents.
Ensuite, comment se fait-il que tu aies deux clés primaire dans la table de relation ?
Pour terminer, pourquoi est-ce que tu fais un TableRegistry
pour le modèle Tvs alors que tu es dans le controller Tvs ?
Ta requête n'est pas correcte, fais plutôt :
$tvs = $this->Tvs->find()->where(['Tvs.tv_id' => 1])->contain(['Slides']);
Bonjour Lartak,
Merci pour ta réponse.
Concerant ta remarques pour les majuscules, j'en tiendrais compte à l'avenir. Pour les accents, j'ai bien essayé de retirer le È du champ "TV_DATE_DERNIÈRE_CONNEXION" cela n'a pas résolu mon problème.
Si la table slides_tvs est la table de relation entre la table tvs et la table slides... Il me semble normal de créer une clé primaire sur les champs qui référencent respectivement chaqune des deux tables pour éviter que l'on puisse créer deux fois la même relation...
Je suis débutant en CakePhp et même si j'ai déjà pas mal épluché la doc, je ne connais pas encore toutes les utilisations que je peux faire en respectant les pré-requis.
En lisant la ligne de code que tu m'as donné, j'imagine donc que dans le controller de même nom que la table que je cherche à atteindre, je devrais pouvoir y accéder en faisant "$this->Tvs" au lieu de TableRegistry::get('tvs')...
Néanmoins que j'ajoute dans mon controller Tvs ta ligne de code j'obtiens l'erreur suivante:
Error: Call to a member function find() on boolean
File C:\xampp\htdocs\rtvslides\src\Controller\TvsController.php
Peut-être peux-tu me dire pourquoi?
Re-bonjour Lartak,
Ta ligne de code fonctionne si j'ajoute les lignes suivantes dans mon controller:
public function initialize() {
parent::initialize();
$this->loadModel('Tvs');
}
Mais lorsque j'affiche:
debug($this->Tvs->find('all')->where(['Tvs.tv_id' => 1])->contain(['Slides'])->all());
La propriété 'Slides' est à nouveau un tableau vide...
Il me semble normal de créer une clé primaire sur les champs qui référencent respectivement chaqune des deux tables pour éviter que l'on puisse créer deux fois la même relation...
Dans une table, tu ne dois pas pouvoir créer deux clés primaire normalement.
Une clé primaire est censé être unique dans une table.
j'imagine donc que dans le controller de même nom que la table que je cherche à atteindre, je devrais pouvoir y accéder en faisant "$this->Tvs" au lieu de TableRegistry::get('tvs')...
C'est exact, il est inutile de vouloir charger un modèle qui est déja lié.
Pour charger un modèle qui n'est pas lié, tu peux très bien utiliser $this->loadModel('ModelName')
à la place de TableRegistry::get('ModelName')
.
Pour finir, tu as trop de use
inutile, tu peux enlever tout ça :
use Cake\ORM\TableRegistry;
use Cake\Auth\BaseAuthenticate;
use Cake\Auth\DefaultPasswordHasher;
use Cake\View\Helper\HtmlHelper;
use App\Model\Entity\TvsEntity;
Mais lorsque j'affiche:
Mais c'est quoi tout ces all
?
Et pourquoi tu fais un $this->loadModel('Tvs')
alors que c'est le modèle courant ?
Lartak,
Alors le 'all' comme paramètre à la fonction find()... J'avoue ne pas trop savoir à quoi il sert... Je l'ai vu écris à plusieurs reprises mais que tu le mettes ou que tu l'enlèves ne semble pas affecter le résultat...
Pour le "...->all()":
1) Soit tu écris exactement ta ligne de code et tu obtiens en retour un objet "Cake\ORM\Query" que tu dois itérer pour obtenir les résultats. Ce que j'ai fait ici mais à nouveau la propriété "Slides" de "$testRow" reste vide:
$testQuery = $this->Tvs->find()->where(['Tvs.tv_id' => 1])->contain(['Slides']);
debug($testQuery);
foreach ($testQuery as $testRow) {
debug($testRow);
}
2) Soit pour éviter d'avoir à itérer les résultats tu ajoutes "...->all()" et tu obtiens sans itération un objet "Cake\ORM\ResultSet" qui te retourne tous les résultats de ta requête...
Sauf que là, tu mets deux fois la clé all, ce qui est totalement inutile.
Que tu la mette une fois, je veux bien, mais pas deux fois.
Lartak,
Il subsiste un comportement anormal et je ne comprends pas pourquoi.
J'ai créé un nouvelle table indépendante (j'ai mis tous les champs en minuscule):
CREATE TABLE `televisions` (
`tv_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`tv_nom` varchar(255) NOT NULL,
`tv_slide` varchar(255) DEFAULT NULL,
`tv_slide_version` int(10) unsigned DEFAULT NULL,
`tv_widht` smallint(6) NOT NULL,
`tv_height` smallint(6) NOT NULL,
`tv_refresh_time` int(11) NOT NULL,
`tv_date_derniere_connexion` datetime DEFAULT NULL,
PRIMARY KEY (`tv_id`),
KEY `TV_NOM` (`tv_nom`(191))
) ENGINE=InnoDB;
J'ai créé un nouveau controller:
<?php
namespace App\Controller;
use App\Controller\AppController;
class TelevisionsController extends AppController {
public function index() {
debug($this->Televisions);
}
}
?>
Forcément j'ai créé un vue "index.ctp" dans lequel je n'ai rien mis...
J'ai ajouté une route:
Router::connect('/tv2', ['controller' => 'televisions', 'action' => 'index']);
Et lorsque j'accède à http://.../tv2
$this->Televisions vaut false à nouveau comme si cakePhp ne chargeait pas le modèle par défaut...
J'ai oublié qques choses?
Pour que cela fonctionne je dois obligatoirement ajouter dans le controller:
public function initialize() {
parent::initialize();
$this->loadModel('Televisions');
}