Completed
Push — master ( 506c79...7daaad )
by Julito
12:09
created

countSuccessAttemptsInLearningPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 2
dl 0
loc 12
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\ExtraField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, ExtraField. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
5
use Chamilo\CoreBundle\Entity\ExtraFieldValues;
6
use Chamilo\PluginBundle\Entity\WhispeakAuth\LogEvent;
7
use Chamilo\PluginBundle\Entity\WhispeakAuth\LogEventLp;
8
use Chamilo\PluginBundle\Entity\WhispeakAuth\LogEventQuiz;
9
use Chamilo\CoreBundle\Entity\User;
10
use Symfony\Component\Filesystem\Filesystem;
11
12
/**
13
 * Class WhispeakAuthPlugin.
14
 */
15
class WhispeakAuthPlugin extends Plugin implements \Chamilo\CoreBundle\Hook\Interfaces\HookPluginInterface
16
{
17
    const SETTING_ENABLE = 'enable';
18
    const SETTING_MAX_ATTEMPTS = 'max_attempts';
19
    const SETTING_2FA = '2fa';
20
    const SETTING_API_URL = 'api_url';
21
    const SETTING_TOKEN = 'token';
22
23
    const EXTRAFIELD_AUTH_UID = 'whispeak_auth_uid';
24
    const EXTRAFIELD_LP_ITEM = 'whispeak_lp_item';
25
    const EXTRAFIELD_QUIZ_QUESTION = 'whispeak_quiz_question';
26
27
    const SESSION_FAILED_LOGINS = 'whispeak_failed_logins';
28
    const SESSION_2FA_USER = 'whispeak_user_id';
29
    const SESSION_LP_ITEM = 'whispeak_lp_item';
30
    const SESSION_QUIZ_QUESTION = 'whispeak_quiz_question';
31
    const SESSION_AUTH_PASSWORD = 'whispeak_auth_password';
32
    const SESSION_SENTENCE_TEXT = 'whispeak_sentence_text';
33
34
    /**
35
     * StudentFollowUpPlugin constructor.
36
     */
37
    protected function __construct()
38
    {
39
        parent::__construct(
40
            '0.1',
41
            'Angel Fernando Quiroz',
42
            [
43
                self::SETTING_ENABLE => 'boolean',
44
                self::SETTING_API_URL => 'text',
45
                self::SETTING_TOKEN => 'text',
46
                self::SETTING_MAX_ATTEMPTS => 'text',
47
                self::SETTING_2FA => 'boolean',
48
            ]
49
        );
50
    }
51
52
    /**
53
     * Get the admin URL for the plugin if Plugin::isAdminPlugin is true.
54
     *
55
     * @return string
56
     */
57
    public function getAdminUrl()
58
    {
59
        $webPath = api_get_path(WEB_PLUGIN_PATH).$this->get_name();
60
61
        return "$webPath/admin.php";
62
    }
63
64
    /**
65
     * @return WhispeakAuthPlugin
66
     */
67
    public static function create()
68
    {
69
        static $result = null;
70
71
        return $result ? $result : $result = new self();
72
    }
73
74
    public function install()
75
    {
76
        $this->installExtraFields();
77
        $this->installEntities();
78
        $this->installHook();
79
    }
80
81
    public function uninstall()
82
    {
83
        $this->uninstallHook();
84
        $this->uninstallExtraFields();
85
        $this->uninstallEntities();
86
    }
87
88
    /**
89
     * @return string
90
     */
91
    public function getEntityPath()
92
    {
93
        return api_get_path(SYS_PATH).'src/Chamilo/PluginBundle/Entity/'.$this->getCamelCaseName();
94
    }
95
96
    /**
97
     * @return ExtraField
98
     */
99
    public static function getAuthUidExtraField()
100
    {
101
        $em = Database::getManager();
102
        $efRepo = $em->getRepository('ChamiloCoreBundle:ExtraField');
103
104
        /** @var ExtraField $extraField */
105
        $extraField = $efRepo->findOneBy(
106
            [
107
                'variable' => self::EXTRAFIELD_AUTH_UID,
108
                'extraFieldType' => ExtraField::USER_FIELD_TYPE,
109
            ]
110
        );
111
112
        return $extraField;
113
    }
114
115
    /**
116
     * @return ExtraField
117
     */
118
    public static function getLpItemExtraField()
119
    {
120
        $efRepo = Database::getManager()->getRepository('ChamiloCoreBundle:ExtraField');
121
122
        /** @var ExtraField $extraField */
123
        $extraField = $efRepo->findOneBy(
124
            [
125
                'variable' => self::EXTRAFIELD_LP_ITEM,
126
                'extraFieldType' => ExtraField::LP_ITEM_FIELD_TYPE,
127
            ]
128
        );
129
130
        return $extraField;
131
    }
132
133
    /**
134
     * @return ExtraField
135
     */
136
    public static function getQuizQuestionExtraField()
137
    {
138
        $efRepo = Database::getManager()->getRepository('ChamiloCoreBundle:ExtraField');
139
140
        /** @var ExtraField $extraField */
141
        $extraField = $efRepo->findOneBy(
142
            [
143
                'variable' => self::EXTRAFIELD_QUIZ_QUESTION,
144
                'extraFieldType' => ExtraField::QUESTION_FIELD_TYPE,
145
            ]
146
        );
147
148
        return $extraField;
149
    }
150
151
    /**
152
     * @param int $userId
153
     *
154
     * @return ExtraFieldValues
155
     */
156
    public static function getAuthUidValue($userId)
157
    {
158
        $extraField = self::getAuthUidExtraField();
159
        $em = Database::getManager();
160
        $efvRepo = $em->getRepository('ChamiloCoreBundle:ExtraFieldValues');
161
162
        /** @var ExtraFieldValues $value */
163
        $value = $efvRepo->findOneBy(['field' => $extraField, 'itemId' => $userId]);
164
165
        return $value;
166
    }
167
168
    /**
169
     * Get the whispeak_lp_item value for a LP item ID.
170
     *
171
     * @param int $lpItemId
172
     *
173
     * @return array|false
174
     */
175
    public static function getLpItemValue($lpItemId)
176
    {
177
        $efv = new ExtraFieldValue('lp_item');
178
        $value = $efv->get_values_by_handler_and_field_variable($lpItemId, self::EXTRAFIELD_LP_ITEM);
179
180
        return $value;
181
    }
182
183
    /**
184
     * @param int $lpItemId
185
     *
186
     * @return bool
187
     */
188
    public static function isLpItemMarked($lpItemId)
189
    {
190
        if (!self::create()->isEnabled()) {
191
            return false;
192
        }
193
194
        $value = self::getLpItemValue($lpItemId);
195
196
        return !empty($value) && !empty($value['value']);
197
    }
198
199
    /**
200
     * Get the whispeak_quiz_question value for a quiz question ID.
201
     *
202
     * @param int $questionId
203
     *
204
     * @return array|false
205
     */
206
    public static function getQuizQuestionValue($questionId)
207
    {
208
        $efv = new ExtraFieldValue('question');
209
        $value = $efv->get_values_by_handler_and_field_variable($questionId, self::EXTRAFIELD_QUIZ_QUESTION);
210
211
        return $value;
212
    }
213
214
    /**
215
     * @param int $questionId
216
     *
217
     * @return bool
218
     */
219
    public static function isQuizQuestionMarked($questionId)
220
    {
221
        if (!self::create()->isEnabled()) {
222
            return false;
223
        }
224
225
        $value = self::getQuizQuestionValue($questionId);
226
227
        return !empty($value) && !empty($value['value']);
228
    }
229
230
    /**
231
     * @param int $questionId
232
     *
233
     * @return bool
234
     */
235
    public static function questionRequireAuthentify($questionId)
236
    {
237
        $isMarked = self::isQuizQuestionMarked($questionId);
238
239
        if (!$isMarked) {
240
            return false;
241
        }
242
243
        $questionInfo = ChamiloSession::read(self::SESSION_QUIZ_QUESTION, []);
244
245
        if (empty($questionInfo)) {
246
            return true;
247
        }
248
249
        if ((int) $questionId !== $questionInfo['question']) {
250
            return true;
251
        }
252
253
        if (false === $questionInfo['passed']) {
254
            return true;
255
        }
256
257
        return false;
258
    }
259
260
    /**
261
     * @param int $userId
262
     *
263
     * @return bool
264
     */
265
    public static function checkUserIsEnrolled($userId)
266
    {
267
        $value = self::getAuthUidValue($userId);
268
269
        if (empty($value)) {
270
            return false;
271
        }
272
273
        return !empty($value->getValue());
274
    }
275
276
    /**
277
     * @return string
278
     */
279
    public static function getEnrollmentUrl()
280
    {
281
        return api_get_path(WEB_PLUGIN_PATH).'whispeakauth/enrollment.php';
282
    }
283
284
    /**
285
     * @param string $uid
286
     *
287
     * @throws \Doctrine\ORM\OptimisticLockException
288
     */
289
    public function saveEnrollment(User $user, $uid)
290
    {
291
        $em = Database::getManager();
292
        $extraFieldValue = self::getAuthUidValue($user->getId());
293
294
        if (empty($extraFieldValue)) {
295
            $extraField = self::getAuthUidExtraField();
296
            $now = new DateTime('now', new DateTimeZone('UTC'));
297
298
            $extraFieldValue = new ExtraFieldValues();
299
            $extraFieldValue
300
                ->setField($extraField)
301
                ->setItemId($user->getId())
302
                ->setUpdatedAt($now);
303
        }
304
305
        $extraFieldValue->setValue($uid);
306
307
        $em->persist($extraFieldValue);
308
        $em->flush();
309
    }
310
311
    /**
312
     * @return bool
313
     */
314
    public function toolIsEnabled()
315
    {
316
        return 'true' === $this->get(self::SETTING_ENABLE);
317
    }
318
319
    /**
320
     * Access not allowed when tool is not enabled.
321
     *
322
     * @param bool $printHeaders Optional. Print headers.
323
     */
324
    public function protectTool($printHeaders = true)
325
    {
326
        if ($this->toolIsEnabled()) {
327
            return;
328
        }
329
330
        api_not_allowed($printHeaders);
331
    }
332
333
    /**
334
     * Get the max_attemtps option.
335
     *
336
     * @return int
337
     */
338
    public function getMaxAttempts()
339
    {
340
        return (int) $this->get(self::SETTING_MAX_ATTEMPTS);
341
    }
342
343
    /**
344
     * Install hook when saving the plugin configuration.
345
     *
346
     * @return WhispeakAuthPlugin
347
     */
348
    public function performActionsAfterConfigure()
349
    {
350
        $observer = WhispeakConditionalLoginHook::create();
351
352
        if ('true' === $this->get(self::SETTING_2FA)) {
353
            HookConditionalLogin::create()->attach($observer);
354
        } else {
355
            HookConditionalLogin::create()->detach($observer);
356
        }
357
358
        return $this;
359
    }
360
361
    /**
362
     * This method will call the Hook management insertHook to add Hook observer from this plugin.
363
     */
364
    public function installHook()
365
    {
366
        $observer = WhispeakMyStudentsLpTrackingHook::create();
367
        HookMyStudentsLpTracking::create()->attach($observer);
368
369
        $observer = WhispeakMyStudentsQuizTrackingHook::create();
370
        HookMyStudentsQuizTracking::create()->attach($observer);
371
    }
372
373
    /**
374
     * This method will call the Hook management deleteHook to disable Hook observer from this plugin.
375
     */
376
    public function uninstallHook()
377
    {
378
        $observer = WhispeakConditionalLoginHook::create();
379
        HookConditionalLogin::create()->detach($observer);
380
381
        $observer = WhispeakMyStudentsLpTrackingHook::create();
382
        HookMyStudentsLpTracking::create()->detach($observer);
383
    }
384
385
    /**
386
     * @param int $userId
387
     *
388
     * @throws \Doctrine\ORM\OptimisticLockException
389
     *
390
     * @return bool
391
     */
392
    public static function deleteEnrollment($userId)
393
    {
394
        $extraFieldValue = self::getAuthUidValue($userId);
395
396
        if (empty($extraFieldValue)) {
397
            return false;
398
        }
399
400
        $em = Database::getManager();
401
        $em->remove($extraFieldValue);
402
        $em->flush();
403
404
        return true;
405
    }
406
407
    /**
408
     * Check if the WhispeakAuth plugin is installed and enabled.
409
     *
410
     * @param bool $checkEnabled Check if, additionnally to being installed, the plugin is enabled
411
     *
412
     * @return bool
413
     */
414
    public function isEnabled($checkEnabled = false)
415
    {
416
        return parent::isEnabled() && 'true' === api_get_plugin_setting('whispeakauth', self::SETTING_ENABLE);
417
    }
418
419
    /**
420
     * @param int $lpItemId
421
     *
422
     * @return bool
423
     */
424
    public static function isAllowedToSaveLpItem($lpItemId)
425
    {
426
        if (!self::isLpItemMarked($lpItemId)) {
427
            return true;
428
        }
429
430
        $markedItem = ChamiloSession::read(self::SESSION_LP_ITEM, []);
431
432
        if (empty($markedItem)) {
433
            return true;
434
        }
435
436
        if ((int) $lpItemId !== (int) $markedItem['lp_item']) {
437
            return true;
438
        }
439
440
        return false;
441
    }
442
443
    /**
444
     * Display a error message.
445
     *
446
     * @param string|null $error Optional. The message text
447
     */
448
    public static function displayNotAllowedMessage($error = null)
449
    {
450
        $error = empty($error) ? get_lang('NotAllowed') : $error;
451
452
        echo Display::return_message($error, 'error', false);
453
454
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
455
    }
456
457
    /**
458
     * @param int $questionId
459
     *
460
     * @throws Exception
461
     *
462
     * @return string
463
     */
464
    public static function quizQuestionAuthentify($questionId, Exercise $exercise)
465
    {
466
        ChamiloSession::write(
467
            self::SESSION_QUIZ_QUESTION,
468
            [
469
                'quiz' => (int) $exercise->iId,
470
                'question' => (int) $questionId,
471
                'url_params' => $_SERVER['QUERY_STRING'],
472
                'passed' => false,
473
            ]
474
        );
475
476
        $template = new Template('', false, false, false, true, false, false);
477
        $template->assign('question', $questionId);
478
        $template->assign('exercise', $exercise->iId);
479
        $content = $template->fetch('whispeakauth/view/quiz_question.html.twig');
480
481
        echo $content;
482
    }
483
484
    /**
485
     * @param int $status
486
     * @param int $userId
487
     * @param int $lpItemId
488
     * @param int $lpId
489
     *
490
     * @throws \Doctrine\ORM\ORMException
491
     * @throws \Doctrine\ORM\OptimisticLockException
492
     * @throws \Doctrine\ORM\TransactionRequiredException
493
     *
494
     * @return LogEventLp|null
495
     */
496
    public function addAttemptInLearningPath($status, $userId, $lpItemId, $lpId)
497
    {
498
        $em = Database::getManager();
499
500
        $user = api_get_user_entity($userId);
501
        $lpItem = $em->find('ChamiloCourseBundle:CLpItem', $lpItemId);
502
        $lp = $em->find('ChamiloCourseBundle:CLp', $lpId);
503
504
        if (empty($lp) || empty($lpItem)) {
505
            return null;
506
        }
507
508
        $logEvent = new LogEventLp();
509
        $logEvent
510
            ->setLpItem($lpItem)
511
            ->setLp($lp)
512
            ->setUser($user)
513
            ->setDatetime(
514
                api_get_utc_datetime(null, false, true)
515
            )
516
            ->setActionStatus($status);
517
518
        $em->persist($logEvent);
519
        $em->flush();
520
521
        return $logEvent;
522
    }
523
524
    /**
525
     * @param int $status
526
     * @param int $userId
527
     * @param int $questionId
528
     * @param int $quizId
529
     *
530
     * @throws \Doctrine\ORM\ORMException
531
     * @throws \Doctrine\ORM\OptimisticLockException
532
     * @throws \Doctrine\ORM\TransactionRequiredException
533
     *
534
     * @return LogEventQuiz|null
535
     */
536
    public function addAttemptInQuiz($status, $userId, $questionId, $quizId)
537
    {
538
        $em = Database::getManager();
539
540
        $user = api_get_user_entity($userId);
541
        $question = $em->find('ChamiloCourseBundle:CQuizQuestion', $questionId);
542
        $quiz = $em->find('ChamiloCourseBundle:CQuiz', $quizId);
543
544
        if (empty($quiz) || empty($question)) {
545
            return null;
546
        }
547
548
        $logEvent = new LogEventQuiz();
549
        $logEvent
550
            ->setQuestion($question)
551
            ->setQuiz($quiz)
552
            ->setUser($user)
553
            ->setDatetime(
554
                api_get_utc_datetime(null, false, true)
555
            )
556
            ->setActionStatus($status);
557
558
        $em->persist($logEvent);
559
        $em->flush();
560
561
        return $logEvent;
562
    }
563
564
    /**
565
     * @param int $status
566
     * @param int $userId
567
     *
568
     * @throws \Doctrine\ORM\ORMException
569
     * @throws \Doctrine\ORM\OptimisticLockException
570
     * @throws \Doctrine\ORM\TransactionRequiredException
571
     *
572
     * @return LogEvent|null
573
     */
574
    public function addAuthenticationAttempt($status, $userId)
575
    {
576
        $em = Database::getManager();
577
578
        $user = api_get_user_entity($userId);
579
580
        $logEvent = new LogEvent();
581
        $logEvent
582
            ->setUser($user)
583
            ->setDatetime(
584
                api_get_utc_datetime(null, false, true)
585
            )
586
            ->setActionStatus($status);
587
588
        $em->persist($logEvent);
589
        $em->flush();
590
591
        return $logEvent;
592
    }
593
594
    /**
595
     * @param int $lpId
596
     * @param int $userId
597
     *
598
     * @throws \Doctrine\ORM\Query\QueryException
599
     *
600
     * @return string
601
     */
602
    public static function countAllAttemptsInLearningPath($lpId, $userId)
603
    {
604
        $query = Database::getManager()
605
            ->createQuery(
606
                'SELECT COUNT(log) AS c FROM ChamiloPluginBundle:WhispeakAuth\LogEventLp log
607
                WHERE log.lp = :lp AND log.user = :user'
608
            )
609
            ->setParameters(['lp' => $lpId, 'user' => $userId]);
610
611
        $totalCount = (int) $query->getSingleScalarResult();
612
613
        return $totalCount;
614
    }
615
616
    /**
617
     * @param int $lpId
618
     * @param int $userId
619
     *
620
     * @throws \Doctrine\ORM\Query\QueryException
621
     *
622
     * @return string
623
     */
624
    public static function countSuccessAttemptsInLearningPath($lpId, $userId)
625
    {
626
        $query = Database::getManager()
627
            ->createQuery(
628
                'SELECT COUNT(log) AS c FROM ChamiloPluginBundle:WhispeakAuth\LogEventLp log
629
                WHERE log.lp = :lp AND log.user = :user AND log.actionStatus = :status'
630
            )
631
            ->setParameters(['lp' => $lpId, 'user' => $userId, 'status' => LogEvent::STATUS_SUCCESS]);
632
633
        $totalCount = (int) $query->getSingleScalarResult();
634
635
        return $totalCount;
636
    }
637
638
    /**
639
     * @param int $quizId
640
     * @param int $userId
641
     *
642
     * @throws \Doctrine\ORM\Query\QueryException
643
     *
644
     * @return string
645
     */
646
    public static function countAllAttemptsInQuiz($quizId, $userId)
647
    {
648
        $query = Database::getManager()
649
            ->createQuery(
650
                'SELECT COUNT(log) AS c FROM ChamiloPluginBundle:WhispeakAuth\LogEventQuiz log
651
                WHERE log.quiz = :quiz AND log.user = :user'
652
            )
653
            ->setParameters(['quiz' => $quizId, 'user' => $userId]);
654
655
        $totalCount = (int) $query->getSingleScalarResult();
656
657
        return $totalCount;
658
    }
659
660
    /**
661
     * @param int $quizId
662
     * @param int $userId
663
     *
664
     * @throws \Doctrine\ORM\Query\QueryException
665
     *
666
     * @return string
667
     */
668
    public static function countSuccessAttemptsInQuiz($quizId, $userId)
669
    {
670
        $query = Database::getManager()
671
            ->createQuery(
672
                'SELECT COUNT(log) AS c FROM ChamiloPluginBundle:WhispeakAuth\LogEventQuiz log
673
                WHERE log.quiz = :quiz AND log.user = :user AND log.actionStatus = :status'
674
            )
675
            ->setParameters(['quiz' => $quizId, 'user' => $userId, 'status' => LogEvent::STATUS_SUCCESS]);
676
677
        $totalCount = (int) $query->getSingleScalarResult();
678
679
        return $totalCount;
680
    }
681
682
    /**
683
     * @return string
684
     */
685
    public function getApiUrl()
686
    {
687
        $url = $this->get(self::SETTING_API_URL);
688
689
        return trim($url, " \t\n\r \v/").'/';
690
    }
691
692
    /**
693
     * Install extra fields for user, learning path and quiz question.
694
     */
695
    private function installExtraFields()
696
    {
697
        UserManager::create_extra_field(
698
            self::EXTRAFIELD_AUTH_UID,
699
            \ExtraField::FIELD_TYPE_TEXT,
700
            $this->get_lang('Whispeak uid'),
701
            ''
702
        );
703
704
        LpItem::createExtraField(
705
            self::EXTRAFIELD_LP_ITEM,
706
            \ExtraField::FIELD_TYPE_CHECKBOX,
707
            $this->get_lang('MarkForSpeechAuthentication'),
708
            '0',
709
            true,
710
            true
711
        );
712
713
        $extraField = new \ExtraField('question');
714
        $params = [
715
            'variable' => self::EXTRAFIELD_QUIZ_QUESTION,
716
            'field_type' => \ExtraField::FIELD_TYPE_CHECKBOX,
717
            'display_text' => $this->get_lang('MarkForSpeechAuthentication'),
718
            'default_value' => '0',
719
            'changeable' => true,
720
            'visible_to_self' => true,
721
            'visible_to_others' => false,
722
        ];
723
724
        $extraField->save($params);
725
    }
726
727
    /**
728
     * Install the Doctrine's entities.
729
     */
730
    private function installEntities()
731
    {
732
        $pluginEntityPath = $this->getEntityPath();
733
734
        if (!is_dir($pluginEntityPath)) {
735
            if (!is_writable(dirname($pluginEntityPath))) {
736
                Display::addFlash(
737
                    Display::return_message(get_lang('ErrorCreatingDir').": $pluginEntityPath", 'error')
738
                );
739
740
                return;
741
            }
742
743
            mkdir($pluginEntityPath, api_get_permissions_for_new_directories());
744
        }
745
746
        $fs = new Filesystem();
747
        $fs->mirror(__DIR__.'/Entity/', $pluginEntityPath, null, ['override']);
748
749
        $schema = Database::getManager()->getConnection()->getSchemaManager();
750
751
        if (false === $schema->tablesExist('whispeak_log_event')) {
752
            $sql = "CREATE TABLE whispeak_log_event (
753
                    id INT AUTO_INCREMENT NOT NULL,
754
                    user_id INT NOT NULL,
755
                    lp_item_id INT DEFAULT NULL,
756
                    lp_id INT DEFAULT NULL,
757
                    question_id INT DEFAULT NULL,
758
                    quiz_id INT DEFAULT NULL,
759
                    datetime DATETIME NOT NULL,
760
                    action_status SMALLINT NOT NULL,
761
                    discr VARCHAR(255) NOT NULL,
762
                    INDEX IDX_A5C4B9FFA76ED395 (user_id),
763
                    INDEX IDX_A5C4B9FFDBF72317 (lp_item_id),
764
                    INDEX IDX_A5C4B9FF68DFD1EF (lp_id),
765
                    INDEX IDX_A5C4B9FF1E27F6BF (question_id),
766
                    INDEX IDX_A5C4B9FF853CD175 (quiz_id),
767
                    PRIMARY KEY(id)
768
                ) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB";
769
            Database::query($sql);
770
            $sql = "ALTER TABLE whispeak_log_event ADD CONSTRAINT FK_A5C4B9FFA76ED395
771
                FOREIGN KEY (user_id) REFERENCES user (id)";
772
            Database::query($sql);
773
            $sql = "ALTER TABLE whispeak_log_event ADD CONSTRAINT FK_A5C4B9FFDBF72317
774
                FOREIGN KEY (lp_item_id) REFERENCES c_lp_item (iid)";
775
            Database::query($sql);
776
            $sql = "ALTER TABLE whispeak_log_event ADD CONSTRAINT FK_A5C4B9FF68DFD1EF
777
                FOREIGN KEY (lp_id) REFERENCES c_lp (iid)";
778
            Database::query($sql);
779
            $sql = "ALTER TABLE whispeak_log_event ADD CONSTRAINT FK_A5C4B9FF1E27F6BF
780
                FOREIGN KEY (question_id) REFERENCES c_quiz_question (iid)";
781
            Database::query($sql);
782
            $sql = "ALTER TABLE whispeak_log_event ADD CONSTRAINT FK_A5C4B9FF853CD175
783
                FOREIGN KEY (quiz_id) REFERENCES c_quiz (iid)";
784
            Database::query($sql);
785
        }
786
    }
787
788
    /**
789
     * Uninstall extra fields for user, learning path and quiz question.
790
     */
791
    private function uninstallExtraFields()
792
    {
793
        $em = Database::getManager();
794
795
        $authIdExtrafield = self::getAuthUidExtraField();
796
797
        if (!empty($authIdExtrafield)) {
798
            $em
799
                ->createQuery('DELETE FROM ChamiloCoreBundle:ExtraFieldValues efv WHERE efv.field = :field')
800
                ->execute(['field' => $authIdExtrafield]);
801
802
            $em->remove($authIdExtrafield);
803
            $em->flush();
804
        }
805
806
        $lpItemExtrafield = self::getLpItemExtraField();
807
808
        if (!empty($lpItemExtrafield)) {
809
            $em
810
                ->createQuery('DELETE FROM ChamiloCoreBundle:ExtraFieldValues efv WHERE efv.field = :field')
811
                ->execute(['field' => $lpItemExtrafield]);
812
813
            $em->remove($lpItemExtrafield);
814
            $em->flush();
815
        }
816
817
        $quizQuestionExtrafield = self::getQuizQuestionExtraField();
818
819
        if (!empty($quizQuestionExtrafield)) {
820
            $em
821
                ->createQuery('DELETE FROM ChamiloCoreBundle:ExtraFieldValues efv WHERE efv.field = :field')
822
                ->execute(['field' => $quizQuestionExtrafield]);
823
824
            $em->remove($quizQuestionExtrafield);
825
            $em->flush();
826
        }
827
    }
828
829
    /**
830
     * Uninstall the Doctrine's entities.
831
     */
832
    private function uninstallEntities()
833
    {
834
        $pluginEntityPath = $this->getEntityPath();
835
836
        $fs = new Filesystem();
837
838
        if ($fs->exists($pluginEntityPath)) {
839
            $fs->remove($pluginEntityPath);
840
        }
841
842
        $table = Database::get_main_table('whispeak_log_event');
843
        $sql = "DROP TABLE IF EXISTS $table";
844
        Database::query($sql);
845
    }
846
}
847