Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
70.59% |
12 / 17 |
CRAP | |
80.45% |
144 / 179 |
| CreateAction | |
0.00% |
0 / 1 |
|
70.59% |
12 / 17 |
56.82 | |
80.45% |
144 / 179 |
| run | |
100.00% |
1 / 1 |
4 | |
100.00% |
16 / 16 |
|||
| validateAccess | |
0.00% |
0 / 1 |
8.12 | |
61.11% |
11 / 18 |
|||
| prepareMatrix | |
100.00% |
1 / 1 |
2 | |
100.00% |
17 / 17 |
|||
| createMeeting | |
0.00% |
0 / 1 |
10.36 | |
74.42% |
32 / 43 |
|||
| findAvailableTable | |
100.00% |
1 / 1 |
4 | |
100.00% |
7 / 7 |
|||
| getNewTable | |
0.00% |
0 / 1 |
30.00 | |
0.00% |
0 / 15 |
|||
| findParticipantModel | |
0.00% |
0 / 1 |
2.15 | |
66.67% |
2 / 3 |
|||
| findUserParticipantModel | |
0.00% |
0 / 1 |
2.15 | |
66.67% |
2 / 3 |
|||
| findParticipantEventSpans | |
100.00% |
1 / 1 |
1 | |
100.00% |
8 / 8 |
|||
| findParticipantMeetingsCount | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
| findAllParticipantMeetings | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
| findAllParticipantSpecialTables | |
100.00% |
1 / 1 |
1 | |
100.00% |
10 / 10 |
|||
| findTables | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
| findBusyTables | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
| findSelectedBusyTables | |
100.00% |
1 / 1 |
1 | |
100.00% |
6 / 6 |
|||
| findBusyTablesStats | |
100.00% |
1 / 1 |
1 | |
100.00% |
7 / 7 |
|||
| findSelectedBusyTablesStats | |
100.00% |
1 / 1 |
1 | |
100.00% |
8 / 8 |
|||
| <?php namespace frontend\controllers\meeting; | |
| use Yii; | |
| use frontend\models\CreateMeetingForm; | |
| use frontend\models\MeetingTimeAvailability; | |
| use common\models\Meeting; | |
| use common\models\Organization; | |
| use common\models\Participant; | |
| use common\models\Event; | |
| use common\models\EventSpan; | |
| use common\models\Table; | |
| use yii\base\Action; | |
| use yii\filters\AccessControl; | |
| use yii\filters\VerbFilter; | |
| use yii\web\BadRequestHttpException; | |
| use yii\web\ForbiddenHttpException; | |
| use yii\web\NotFoundHttpException; | |
| /** | |
| * Creates a new Meeting model. | |
| * If creation is successful, the browser will be redirected to the 'view' page. | |
| * @param integer $participant | |
| * @return mixed | |
| */ | |
| class CreateAction extends Action | |
| { | |
| private $event; | |
| private $hostParticipant; | |
| private $guestParticipant; | |
| private $eventSpans; | |
| private $eventSpansMatrix; | |
| /** | |
| * @param integer $participant | |
| * @return Page | |
| */ | |
| public function run($participant) | |
| { | |
| $this->event = Event::find()->active()->one(); | |
| $this->hostParticipant = $this->findUserParticipantModel(Yii::$app->user->id); | |
| $this->guestParticipant = $this->findParticipantModel($participant); | |
| $this->validateAccess(); | |
| $this->prepareMatrix(); | |
| $form = new CreateMeetingForm(); | |
| $form->host_participant_id = $this->hostParticipant->id; | |
| $form->guest_participant_id = $this->guestParticipant->id; | |
| if ($form->load(Yii::$app->request->post()) && $form->validate()) { | |
| if ($this->createMeeting($form) == true) { | |
| return $this->controller->redirect(['index']); | |
| } | |
| } | |
| // Wyswietlenie formularza tworzenia spotkania | |
| return $this->controller->render('create', [ | |
| 'model' => $form, | |
| 'partner' => $this->guestParticipant, | |
| 'eventSpans' => $this->eventSpans, | |
| 'eventSpansMatrix' => $this->eventSpansMatrix, | |
| ]); | |
| } | |
| /** | |
| * @return null|Flash | |
| * @throws ForbiddenHttpException if the user has no "createMeeting" permition | |
| * @throws ForbiddenHttpException if the guest is support only | |
| * @throws ForbiddenHttpException if the host and guest are the same participant | |
| * @throws ForbiddenHttpException if the host already meet guest | |
| */ | |
| protected function validateAccess() | |
| { | |
| if(!Yii::$app->user->can('createMeeting')) | |
| throw new ForbiddenHttpException(Yii::t('app', 'You are not allowed to perform this action.')); | |
| // If host and guest is the same participant | |
| if($this->hostParticipant->id == $this->guestParticipant->id) | |
| throw new ForbiddenHttpException(Yii::t('app', 'You are not allowed to perform this action. You can not have meeting with youself.')); | |
| // If guest is support only participant | |
| if($this->guestParticipant->is_support_only == true) | |
| throw new ForbiddenHttpException(Yii::t('app', 'You are not allowed to perform this action. You can not have meeting with supporting particiapnt {guest}.', | |
| ['guest' => $this->guestParticipant->user->fullname] | |
| )); | |
| // If they already have meeting | |
| $meetingsCount = $this->findParticipantMeetingsCount($this->hostParticipant, $this->guestParticipant); | |
| if($meetingsCount > 0) | |
| throw new ForbiddenHttpException(Yii::t('app', 'You are not allowed to perform this action. You already have one meeting with {guest}.', | |
| ['guest' => $this->guestParticipant->user->fullname] | |
| )); | |
| Yii::trace('start finding common event spans'); | |
| // Get my & partner event spans | |
| $this->eventSpans = $this->findParticipantEventSpans($this->hostParticipant, $this->guestParticipant); | |
| if(empty($this->eventSpans)){ | |
| Yii::info('there are no common event spans'); | |
| return Yii::$app->session->setFlash('warning', Yii::t('app', 'There are no available time for your meeting with {guest}.', | |
| ['guest' => $this->guestParticipant->user->fullname] | |
| )); | |
| } | |
| } | |
| /** | |
| * @return null | |
| */ | |
| protected function prepareMatrix() | |
| { | |
| $matrixModel = new MeetingTimeAvailability(); | |
| // Get special tables | |
| $specialTables = $this->findAllParticipantSpecialTables([$this->hostParticipant->id, $this->guestParticipant->id]); | |
| $specialTablesCount = count($specialTables); | |
| Yii::trace('start createMatrix'); | |
| $matrixModel->createMatrix($this->eventSpans, $specialTablesCount); | |
| // Get my | partner meetings | |
| $meetings = $this->findAllParticipantMeetings([$this->hostParticipant->id, $this->guestParticipant->id]); | |
| Yii::trace('start unsetWhenMeeting'); | |
| $matrixModel->unsetWhenMeeting($meetings); | |
| // Get busy tables quantity (with special tables if needed) | |
| $busyTimeTables = []; | |
| if ($specialTablesCount > 0) { | |
| $busyTimeTables = $this->findSelectedBusyTablesStats($specialTables); | |
| } else { | |
| $busyTimeTables = $this->findBusyTablesStats(); | |
| } | |
| Yii::trace('start substractBusyTableStats'); | |
| $matrixModel->substractBusyTableStats($busyTimeTables); | |
| Yii::trace('event span time matrix has been created'); | |
| $this->eventSpansMatrix = $matrixModel->getMatrix(); | |
| } | |
| /** | |
| * @param CreateMeetingForm $form | |
| * @return null|Page | |
| */ | |
| protected function createMeeting($form) | |
| { | |
| Yii::trace('start creating meeting'); | |
| $esId = $form->event_span_id; | |
| if(!array_key_exists($esId, $this->eventSpans)){ | |
| Yii::warning('Selected span does not exist!'); | |
| return false; | |
| } | |
| $estOn = $form->event_span_time_on; | |
| if(!isset($this->eventSpansMatrix[$esId][$estOn])){ | |
| Yii::warning('Selected time does not exist!'); | |
| Yii::$app->session->setFlash('info', Yii::t('app', 'Selected time is not available.')); | |
| return false; | |
| } | |
| $eventSpan = $this->eventSpans[$esId]; | |
| $times = $this->eventSpansMatrix[$esId]; | |
| Yii::trace('start looking for free my special table'); | |
| // Sprawdzamy czy ja mam wolne specjalne stoliki | |
| $form->table_id = $this->findAvailableTable( | |
| $specialTables = $this->findAllParticipantSpecialTables([$this->hostParticipant->id]), | |
| $this->findSelectedBusyTables($eventSpan->id, $estOn, $specialTables) | |
| ); | |
| Yii::trace('start looking for free partner special table'); | |
| // Sprawdzamy czy partner ma wolne specjalne stoliki | |
| if(empty($form->table_id)){ | |
| $form->table_id = $this->findAvailableTable( | |
| $specialTables = $this->findAllParticipantSpecialTables([$this->guestParticipant->id]), | |
| $this->findSelectedBusyTables($eventSpan->id, $estOn, $specialTables) | |
| ); | |
| } | |
| Yii::trace('start looking for free common special table'); | |
| // Jesli nie znaleziono specjalnego miejsca | |
| if(empty($form->table_id)){ | |
| $form->table_id = $this->findAvailableTable( | |
| $tables = $this->findTables(), | |
| $busyTables = $this->findBusyTables($eventSpan->id, $estOn) | |
| ); | |
| // Jesli nie ma dostepnych wolnych miejsc | |
| if(empty($form->table_id)){ | |
| $table = $this->getNewTable($eventSpan, $busyTables, $tables); | |
| if(empty($table)){ | |
| Yii::warning('There are not exist free table!'); | |
| Yii::$app->getSession()->setFlash('warning', Yii::t('app', 'No more tables are available. You need to select other time.')); | |
| return false; | |
| } | |
| $form->table_id = $table->id; | |
| } | |
| } | |
| Yii::trace('start saving meeting'); | |
| if(($model = $form->createMeeting()) !== null){ | |
| Yii::trace('meeting has been created'); | |
| if(Yii::$app->params['meeting.confirm.isRequired']){ | |
| $model->sendHostConfirmationEmail(); | |
| Yii::$app->getSession()->setFlash('success', Yii::t('app', 'Check your email account to confirm meeting invitation.')); | |
| }else{ | |
| $this->controller->run('confirm-invitation', ['token' => $model->host_confirmation_token]); | |
| Yii::$app->getSession()->setFlash('success', Yii::t('app', 'Meeting invitation has been sended to guest.')); | |
| } | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * @param Table[]|array[][] $tables indexBy Table.id | |
| * @param Table[] $busyTables | |
| * @return null|Page | |
| */ | |
| protected function findAvailableTable($tables, $busyTables) | |
| { | |
| foreach($busyTables as $busyTable){ | |
| if(isset($tables[$busyTable->id])){ | |
| unset($tables[$busyTable->id]); | |
| } | |
| } | |
| if(count($tables) > 0){ | |
| $tableIds = array_keys($tables); | |
| return $tableIds[0]; | |
| } | |
| return null; | |
| } | |
| /** | |
| * @param EventSpan $eventSpan | |
| * @param Table[] $busyTables | |
| * @param Table[] $tables | |
| * @return null|Table | |
| */ | |
| protected function getNewTable($eventSpan, $busyTables, $tables) | |
| { | |
| if(count($busyTables) < $eventSpan->tables_quantity){ | |
| $esOn = 1; | |
| foreach($busyTables as $busyTable){ | |
| if($busyTable->on == $esOn){ | |
| $esOn++; | |
| }else{ | |
| break; | |
| } | |
| } | |
| $table = new Table(); | |
| $table->on = $esOn; | |
| $table->name = strval($esOn); | |
| $table->is_special = false; | |
| if($table->save()){ | |
| return $table; | |
| }else{ | |
| Yii::error('Table can not be created!'); | |
| } | |
| }else{ | |
| Yii::warning('No more tables can be created!'); | |
| } | |
| return null; | |
| } | |
| /** | |
| * Finds the Organization model based on its primary key value. | |
| * If the model is not found, a 404 HTTP exception will be thrown. | |
| * @param integer $id | |
| * @return Organization the loaded model | |
| * @throws NotFoundHttpException if the model cannot be found | |
| */ | |
| protected function findParticipantModel($id) | |
| { | |
| if (($model = Participant::findOne($id)) !== null) { | |
| return $model; | |
| } else { | |
| throw new NotFoundHttpException('The requested page does not exist.'); | |
| } | |
| } | |
| /** | |
| * Finds the Participant model based on its primary key value. | |
| * If the model is not found, a 404 HTTP exception will be thrown. | |
| * @param integer $user_id | |
| * @return Participant the loaded model | |
| * @throws NotFoundHttpException if the model cannot be found | |
| */ | |
| protected function findUserParticipantModel($user_id) | |
| { | |
| if (($model = Participant::findOne(['user_id' => $user_id])) !== null) { | |
| return $model; | |
| } else { | |
| throw new NotFoundHttpException('The requested page does not exist.'); | |
| } | |
| } | |
| /** | |
| * @param Participant $participant1 | |
| * @param Participant $participant2 | |
| * @return EventSpan[] indexBy EventSpan.id | |
| */ | |
| protected function findParticipantEventSpans($participant1, $participant2) | |
| { | |
| $eventSpans1 = $participant1 | |
| ->getEventSpans() | |
| ->orderBy('date', 'time_from') | |
| ->indexBy('id') | |
| ->all(); | |
| $eventSpans2 = $participant2 | |
| ->getEventSpans() | |
| ->indexBy('id') | |
| ->all(); | |
| return array_intersect_key($eventSpans1, $eventSpans2); | |
| } | |
| /** | |
| * @param Participant $participant1 | |
| * @param Participant $participant2 | |
| * @return integer | |
| */ | |
| protected function findParticipantMeetingsCount($participant1, $participant2) | |
| { | |
| return Meeting::find() | |
| ->isHostOrGuest($participant1->id) | |
| ->isHostOrGuest($participant2->id) | |
| ->count(); | |
| } | |
| /** | |
| * @param integer[] $participants | |
| * @return array[][] | |
| */ | |
| protected function findAllParticipantMeetings($participants) | |
| { | |
| return Meeting::find() | |
| ->select('event_span_id, event_span_time_on') | |
| ->isHostOrGuest($participants) | |
| ->all(); | |
| } | |
| /** | |
| * @param integer[] $participants | |
| * @return array[][] indexBy Table.id | |
| */ | |
| protected function findAllParticipantSpecialTables($participants) | |
| { | |
| return (new \yii\db\Query()) | |
| ->select('s.id') | |
| ->from(['s' => Table::tableName()]) | |
| ->innerJoin(['cs' => '{{%organization_table}}'], 'cs.table_id = s.id') | |
| ->innerJoin(['c' => Organization::tableName()], 'c.id = cs.organization_id') | |
| ->innerJoin(['e' => Participant::tableName()], 'e.organization_id = c.id') | |
| ->where(['=', 's.is_special', true]) | |
| ->andWhere(['e.id' => $participants]) | |
| ->indexBy('id') | |
| ->all(); | |
| } | |
| /** | |
| * @return Table[] indexBy Table.id | |
| */ | |
| protected function findTables() | |
| { | |
| return Table::find() | |
| ->isSpecial(false) | |
| ->orderBy('on') | |
| ->indexBy('id') | |
| ->all(); | |
| } | |
| /** | |
| * @param integer $event_span_id | |
| * @param integer $event_span_time_on | |
| * @return Table[] | |
| */ | |
| protected function findBusyTables($event_span_id, $event_span_time_on) | |
| { | |
| return Table::find() | |
| ->isSpecial(false) | |
| ->isBusyOnSpanAndTime($event_span_id, $event_span_time_on) | |
| ->orderBy('on') | |
| ->all(); | |
| } | |
| /** | |
| * @param integer $event_span_id | |
| * @param integer $event_span_time_on | |
| * @return array[][] | |
| */ | |
| protected function findSelectedBusyTables($event_span_id, $event_span_time_on, $tables) | |
| { | |
| return Meeting::find() | |
| ->select('table_id AS id') | |
| ->andWhere(['=', 'event_span_id', $event_span_id]) | |
| ->andWhere(['=', 'event_span_time_on', $event_span_time_on]) | |
| ->andWhere(['IN', 'table_id', $tables]) | |
| ->all(); | |
| } | |
| /** | |
| * @return array[][] | |
| */ | |
| protected function findBusyTablesStats() | |
| { | |
| return (new \yii\db\Query()) | |
| ->select('m.event_span_id, m.event_span_time_on, COUNT(m.table_id) AS busy_tables_quantity') | |
| ->from(['m' => Meeting::tableName()]) | |
| ->innerJoin(['s' => Table::tableName()], 's.id = m.table_id') | |
| ->where(['=', 's.is_special', false]) | |
| ->groupBy('m.event_span_id, m.event_span_time_on') | |
| ->all(); | |
| } | |
| /** | |
| * @param integer[] $tables | |
| * @return array[][] | |
| */ | |
| protected function findSelectedBusyTablesStats($tables) | |
| { | |
| return (new \yii\db\Query()) | |
| ->select('m.event_span_id, m.event_span_time_on, COUNT(m.table_id) AS busy_tables_quantity') | |
| ->from(['m' => Meeting::tableName()]) | |
| ->innerJoin(['s' => Table::tableName()], 's.id = m.table_id') | |
| ->where(['=', 's.is_special', false]) | |
| ->orWhere(['in', 's.id', $tables]) | |
| ->groupBy('m.event_span_id, m.event_span_time_on') | |
| ->all(); | |
| } | |
| } |