je suppose, sur la base de la question que vous avez posée ici vous avez aimé dans les commentaires que vous avez fourni l'intégralité de la requête (pas d'autres champs, que vous avez retirés juste pour montrer un exemple de code)
donc, si vous n'avez besoin que des champs spécifiés dans SELECT
déclaration, vous pouvez optimiser un peu votre requête :
tout d'abord, vous vous joignez à host_machines
uniquement pour lier les cameras
et events
, mais ont la même clé host_machines_idhost_machines
sur les deux, donc ce n'est pas nécessaire, vous pouvez directement :
INNER JOIN events events
ON (events.host_machines_idhost_machines =
cameras.host_machines_idhost_machines))
deuxièmement, la jointure avec ispy.staff
, le seul champ utilisé est idreceptionist
dans WHERE
clause, ce champ existe dans events
ainsi que nous pouvons le supprimer complètement
la requête finale ici :
SELECT videos.idvideo, videos.filelocation, events.event_type, events.event_timestamp
FROM videos videos
INNER JOIN cameras cameras
ON videos.cameras_idcameras = cameras.idcameras
INNER JOIN events events
ON events.host_machines_idhost_machines =
cameras.host_machines_idhost_machines
WHERE (events.staff_idreceptionist = 182)
AND (events.event_type IN (23, 24))
AND (events.event_timestamp BETWEEN videos.start_time
AND videos.end_time)
devrait afficher les mêmes enregistrements que celui de votre question, sans aucune ligne identique
certains doublons vidéo existeront toujours en raison d'une relation un à plusieurs entre cameras
et events
maintenant du côté yii des choses,
vous devez définir quelques relations sur les Vidéos modèle
// this is pretty straight forward, `videos`.`cameras_idcameras` links to a
// single camera (one-to-one)
public function getCamera(){
return $this->hasOne(Camera::className(), ['idcameras' => 'cameras_idcameras']);
}
// link the events table using `cameras` as a pivot table (one-to-many)
public function getEvents(){
return $this->hasMany(Event::className(), [
// host machine of event => host machine of camera (from via call)
'host_machines_idhost_machines' => 'host_machines_idhost_machines'
])->via('camera');
}
le contrôleur vidéo et la fonction de recherche elle-même
public function actionIndex() {
// this will be the query used to create the ActiveDataProvider
$query =Video::find()
->joinWith(['camera', 'events'], true, 'INNER JOIN')
->where(['event_type' => [23, 24], 'staff_idreceptionist' => 182])
->andWhere('event_timestamp BETWEEN videos.start_time AND videos.end_time');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
return $this->render('index', [
'dataProvider' => $dataProvider,
]);
}
yii traitera chaque vidéo comme un seul enregistrement (basé sur pk), ce qui signifie que tous les doublons vidéo sont supprimés. vous aurez des vidéos uniques, chacune avec plusieurs événements, vous ne pourrez donc pas utiliser 'event_type'
et 'event_timestamp'
dans la vue, mais vous pouvez déclarer des getters dans Vidéo modèle pour afficher cette information :
public function getEventTypes(){
return implode(', ', ArrayHelper::getColumn($this->events, 'event_type'));
}
public function getEventTimestamps(){
return implode(', ', ArrayHelper::getColumn($this->events, 'event_timestamp'));
}
et la vue utilise :
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'idvideo',
'eventTypes',
'eventTimestamps',
'filelocation',
//['class' => 'yii\grid\ActionColumn'],
],
]); ?>
modifier :
si vous souhaitez conserver les doublons vidéo, déclarez les deux colonnes de events
à l'intérieur de la Vidéo modèle
public $event_type, $event_timestamp;
conserver le GridView
d'origine setup, et ajoutez un select
et indexBy
cela à la requête à l'intérieur de VideoController :
$q = Video::find()
// spcify fields
->addSelect(['videos.idvideo', 'videos.filelocation', 'events.event_type', 'events.event_timestamp'])
->joinWith(['camera', 'events'], true, 'INNER JOIN')
->where(['event_type' => [23, 24], 'staff_idreceptionist' => 182])
->andWhere('event_timestamp BETWEEN videos.start_time AND videos.end_time')
// force yii to treat each row as distinct
->indexBy(function () {
static $count;
return ($count++);
});
mettre à jour
un staff
direct relation avec Video
est actuellement quelque peu problématique car il y a plus d'une table loin d'elle.
cependant, vous ajoutez le staff
tableau en le liant à l'événement modèle,
public function getStaff() {
return $this->hasOne(Staff::className(), ['idreceptionist' => 'staff_idreceptionist']);
}
qui vous permettra d'interroger comme ceci :
->joinWith(['camera', 'events', 'events.staff'], true, 'INNER JOIN')
Filtrage nécessitera quelques petites mises à jour sur le contrôleur, la vue et un SarchModel
voici une implémentation minimale :
class VideoSearch extends Video
{
public $eventType;
public $eventTimestamp;
public $username;
public function rules() {
return array_merge(parent::rules(), [
[['eventType', 'eventTimestamp', 'username'], 'safe']
]);
}
public function search($params) {
// add/adjust only conditions that ALWAYS apply here:
$q = parent::find()
->joinWith(['camera', 'events', 'events.staff'], true, 'INNER JOIN')
->where([
'event_type' => [23, 24],
// 'staff_idreceptionist' => 182
// im guessing this would be the username we want to filter by
])
->andWhere('event_timestamp BETWEEN videos.start_time AND videos.end_time');
$dataProvider = new ActiveDataProvider(['query' => $q]);
if (!$this->validate())
return $dataProvider;
$this->load($params);
$q->andFilterWhere([
'idvideo' => $this->idvideo,
'events.event_type' => $this->eventType,
'events.event_timestamp' => $this->eventTimestamp,
'staff.username' => $this->username,
]);
return $dataProvider;
}
}
contrôleur :
public function actionIndex() {
$searchModel = new VideoSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('test', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
et la vue
use yii\grid\GridView;
use yii\helpers\ArrayHelper;
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'idvideo',
'filelocation',
[
'attribute' => 'eventType', // from VideoSearch::$eventType (this is the one you filter by)
'value' => 'eventTypes' // from Video::getEventTypes() that i suggested yesterday
// in hindsight, this could have been named better, like Video::formatEventTypes or smth
],
[
'attribute' => 'eventTimestamp',
'value' => 'eventTimestamps'
],
[
'attribute' => 'username',
'value' => function($video){
return implode(', ', ArrayHelper::map($video->events, 'idevent', 'staff.username'));
}
],
//['class' => 'yii\grid\ActionColumn'],
],
]);