Jeg vil antage, baseret på det spørgsmål, du stillede her du kunne lide i kommentarer, at du har angivet hele forespørgslen (ingen andre felter, som du tog ud bare for at vise eksempelkode)
derfor, hvis du kun har brug for de felter, der er angivet i SELECT
sætning, kan du optimere din forespørgsel en del:
Først og fremmest deltager du med host_machines
kun for at linke cameras
og events
, men har den samme nøgle host_machines_idhost_machines
på begge, så det er ikke nødvendigt, kan du direkte:
INNER JOIN events events
ON (events.host_machines_idhost_machines =
cameras.host_machines_idhost_machines))
for det andet joinforbindelsen med ispy.staff
, det eneste anvendte felt er idreceptionist
i WHERE
klausul, det felt findes i events
også, så vi kan droppe det fuldstændigt
den sidste forespørgsel her:
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)
skal udsende de samme poster som den i dit spørgsmål, uden nogen identiske rækker
nogle videoduplikater vil stadig eksistere på grund af en til mange relationer mellem cameras
og events
nu til yii-siden af tingene,
du skal definere nogle relationer på Videoer model
// 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');
}
VideoController og selve søgefunktionen
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 vil behandle hver video som en enkelt post (baseret på pk), hvilket betyder, at alle videoduplikater fjernes. du vil have enkelte videoer, hver med flere begivenheder, så du vil ikke være i stand til at bruge 'event_type'
og 'event_timestamp'
i visningen, men du kan erklære nogle getters i Video model for at vise disse oplysninger:
public function getEventTypes(){
return implode(', ', ArrayHelper::getColumn($this->events, 'event_type'));
}
public function getEventTimestamps(){
return implode(', ', ArrayHelper::getColumn($this->events, 'event_timestamp'));
}
og visningen brug:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'idvideo',
'eventTypes',
'eventTimestamps',
'filelocation',
//['class' => 'yii\grid\ActionColumn'],
],
]); ?>
rediger :
hvis du vil beholde videoduplikaterne, skal du angive de to kolonner fra events
inde i Video model
public $event_type, $event_timestamp;
behold den originale GridView
opsætning, og tilføj en select
og indexBy
dette til forespørgslen inde i 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++);
});
opdatering
en direkte staff
forhold til Video
er i øjeblikket noget problematisk, da det er mere end et bord væk fra det. der er et problem om det her
dog tilføjer du staff
tabellen ved at linke den til Begivenheden model,
public function getStaff() {
return $this->hasOne(Staff::className(), ['idreceptionist' => 'staff_idreceptionist']);
}
der giver dig mulighed for at forespørge sådan her:
->joinWith(['camera', 'events', 'events.staff'], true, 'INNER JOIN')
Filtrering vil kræve nogle små opdateringer på controlleren, view og en SarchModel
her er en minimal implementering:
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;
}
}
controller:
public function actionIndex() {
$searchModel = new VideoSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('test', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
og udsigten
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'],
],
]);