przyjmę, na podstawie pytania, które zadałeś tutaj podobały Ci się komentarze, które podałeś całe zapytanie (brak innych pól, które wyjąłeś tylko po to, aby pokazać przykładowy kod)
dlatego, jeśli potrzebujesz tylko pól określonych w SELECT
oświadczenie, możesz trochę zoptymalizować swoje zapytanie:
po pierwsze, dołączasz za pomocą host_machines
tylko po to, by połączyć cameras
i events
, ale mają ten sam klucz host_machines_idhost_machines
na obu, więc nie jest to potrzebne, możesz bezpośrednio:
INNER JOIN events events
ON (events.host_machines_idhost_machines =
cameras.host_machines_idhost_machines))
po drugie, połącz z ispy.staff
, jedynym używanym polem jest idreceptionist
w WHERE
klauzula, to pole istnieje w events
abyśmy mogli go całkowicie porzucić
ostatnie pytanie tutaj:
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)
powinien wyświetlać te same rekordy, co w pytaniu, bez identycznych wierszy
niektóre duplikaty wideo nadal będą istnieć z powodu relacji jeden do wielu między cameras
i events
teraz po yii strony rzeczy,
musisz zdefiniować pewne relacje w filmach 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');
}
Kontroler wideo i sama funkcja wyszukiwania
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 będzie traktować każdy film jako pojedynczy zapis (w oparciu o pk), co oznacza, że wszystkie duplikaty wideo zostaną usunięte. będziesz mieć pojedyncze filmy, każdy z wieloma wydarzeniami, więc nie będziesz mógł użyć 'event_type'
i 'event_timestamp'
w widoku, ale możesz zadeklarować kilka getterów w Wideo model, aby pokazać te informacje:
public function getEventTypes(){
return implode(', ', ArrayHelper::getColumn($this->events, 'event_type'));
}
public function getEventTimestamps(){
return implode(', ', ArrayHelper::getColumn($this->events, 'event_timestamp'));
}
i wykorzystanie widoku:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'idvideo',
'eventTypes',
'eventTimestamps',
'filelocation',
//['class' => 'yii\grid\ActionColumn'],
],
]); ?>
edytuj :
jeśli chcesz zachować duplikaty wideo, zadeklaruj dwie kolumny z events
wewnątrz Wideo model
public $event_type, $event_timestamp;
zachowaj oryginalny GridView
skonfigurować i dodać select
i indexBy
to do zapytania w 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++);
});
aktualizacja
bezpośredni staff
związek z Video
jest obecnie nieco problematyczny, ponieważ jest więcej niż jeden stół od niego. jest z tym problem tutaj
jednak dodajesz staff
tabeli, łącząc ją z Wydarzeniem model,
public function getStaff() {
return $this->hasOne(Staff::className(), ['idreceptionist' => 'staff_idreceptionist']);
}
co pozwoli ci na zapytanie w ten sposób:
->joinWith(['camera', 'events', 'events.staff'], true, 'INNER JOIN')
Filtrowanie będzie wymagać kilku drobnych aktualizacji kontrolera, widoku i SarchModel
Oto minimalna implementacja:
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;
}
}
kontroler:
public function actionIndex() {
$searchModel = new VideoSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('test', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
i widok
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'],
],
]);