Passed
Push — master ( 212654...8aa330 )
by Angel Fernando Quiroz
11:04
created

XApiPlugin::generateLaunchUrl()   A

Complexity

Conditions 6
Paths 3

Size

Total Lines 30
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 3
nop 9
dl 0
loc 30
rs 9.2222
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\XApiToolLaunch;
6
use Doctrine\ORM\EntityManager;
7
use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver;
8
use Doctrine\ORM\ORMException;
9
use GuzzleHttp\RequestOptions;
10
use Http\Adapter\Guzzle6\Client;
11
use Http\Message\MessageFactory\GuzzleMessageFactory;
12
use Symfony\Component\Uid\Uuid;
13
use Xabbuh\XApi\Client\Api\StatementsApiClientInterface;
14
use Xabbuh\XApi\Client\XApiClientBuilder;
15
use Xabbuh\XApi\Model\Agent;
16
use Xabbuh\XApi\Model\IRI;
17
use Xabbuh\XApi\Serializer\Symfony\Serializer;
18
19
/**
20
 * Class XApiPlugin.
21
 */
22
class XApiPlugin extends Plugin
23
{
24
    public const SETTING_LRS_URL = 'lrs_url';
25
    public const SETTING_LRS_AUTH_USERNAME = 'lrs_auth_username';
26
    public const SETTING_LRS_AUTH_PASSWORD = 'lrs_auth_password';
27
    public const SETTING_CRON_LRS_URL = 'cron_lrs_url';
28
    public const SETTING_CRON_LRS_AUTH_USERNAME = 'cron_lrs_auth_username';
29
    public const SETTING_CRON_LRS_AUTH_PASSWORD = 'cron_lrs_auth_password';
30
    public const SETTING_UUID_NAMESPACE = 'uuid_namespace';
31
    public const SETTING_LRS_LP_ITEM_ACTIVE = 'lrs_lp_item_viewed_active';
32
    public const SETTING_LRS_LP_ACTIVE = 'lrs_lp_end_active';
33
    public const SETTING_LRS_QUIZ_ACTIVE = 'lrs_quiz_active';
34
    public const SETTING_LRS_QUIZ_QUESTION_ACTIVE = 'lrs_quiz_question_active';
35
    public const SETTING_LRS_PORTFOLIO_ACTIVE = 'lrs_portfolio_active';
36
37
    public const STATE_FIRST_LAUNCH = 'first_launch';
38
    public const STATE_LAST_LAUNCH = 'last_launch';
39
40
    /**
41
     * XApiPlugin constructor.
42
     */
43
    protected function __construct()
44
    {
45
        $version = '0.3 (beta)';
46
        $author = [
47
            'Angel Fernando Quiroz Campos <[email protected]>',
48
        ];
49
        $settings = [
50
            self::SETTING_UUID_NAMESPACE => 'text',
51
52
            self::SETTING_LRS_URL => 'text',
53
            self::SETTING_LRS_AUTH_USERNAME => 'text',
54
            self::SETTING_LRS_AUTH_PASSWORD => 'text',
55
56
            self::SETTING_CRON_LRS_URL => 'text',
57
            self::SETTING_CRON_LRS_AUTH_USERNAME => 'text',
58
            self::SETTING_CRON_LRS_AUTH_PASSWORD => 'text',
59
60
            self::SETTING_LRS_LP_ITEM_ACTIVE => 'boolean',
61
            self::SETTING_LRS_LP_ACTIVE => 'boolean',
62
            self::SETTING_LRS_QUIZ_ACTIVE => 'boolean',
63
            self::SETTING_LRS_QUIZ_QUESTION_ACTIVE => 'boolean',
64
            self::SETTING_LRS_PORTFOLIO_ACTIVE => 'boolean',
65
        ];
66
67
        parent::__construct(
68
            $version,
69
            implode(', ', $author),
70
            $settings
71
        );
72
    }
73
74
    /**
75
     * @return \XApiPlugin
76
     */
77
    public static function create()
78
    {
79
        static $result = null;
80
81
        return $result ? $result : $result = new self();
82
    }
83
84
    /**
85
     * Process to install plugin.
86
     */
87
    public function install()
88
    {
89
        $this->installInitialConfig();
90
        $this->addCourseTools();
91
    }
92
93
    /**
94
     * Process to uninstall plugin.
95
     */
96
    public function uninstall()
97
    {
98
        $this->deleteCourseTools();
99
    }
100
101
    /**
102
     * @param string|null $lrsUrl
103
     * @param string|null $lrsAuthUsername
104
     * @param string|null $lrsAuthPassword
105
     *
106
     * @return \Xabbuh\XApi\Client\Api\StateApiClientInterface
107
     */
108
    public function getXApiStateClient($lrsUrl = null, $lrsAuthUsername = null, $lrsAuthPassword = null)
109
    {
110
        return $this
111
            ->createXApiClient($lrsUrl, $lrsAuthUsername, $lrsAuthPassword)
112
            ->getStateApiClient();
113
    }
114
115
    public function getXApiStatementClient(): StatementsApiClientInterface
116
    {
117
        return $this->createXApiClient()->getStatementsApiClient();
118
    }
119
120
    public function getXapiStatementCronClient(): StatementsApiClientInterface
121
    {
122
        $lrsUrl = $this->get(self::SETTING_CRON_LRS_URL);
123
        $lrsUsername = $this->get(self::SETTING_CRON_LRS_AUTH_USERNAME);
124
        $lrsPassword = $this->get(self::SETTING_CRON_LRS_AUTH_PASSWORD);
125
126
        return $this
127
            ->createXApiClient(
128
                empty($lrsUrl) ? null : $lrsUrl,
129
                empty($lrsUsername) ? null : $lrsUsername,
130
                empty($lrsPassword) ? null : $lrsPassword
131
            )
132
            ->getStatementsApiClient();
133
    }
134
135
    /**
136
     * @param string $variable
137
     *
138
     * @return array
139
     */
140
    public function getLangMap($variable)
141
    {
142
        $platformLanguage = api_get_setting('platformLanguage');
143
        $platformLanguageIso = api_get_language_isocode($platformLanguage);
144
145
        $map = [];
146
        $map[$platformLanguageIso] = $this->getLangFromFile($variable, $platformLanguage);
147
148
        try {
149
            $interfaceLanguage = api_get_interface_language();
0 ignored issues
show
Bug introduced by
The function api_get_interface_language was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

149
            $interfaceLanguage = /** @scrutinizer ignore-call */ api_get_interface_language();
Loading history...
150
        } catch (Exception $e) {
151
            return $map;
152
        }
153
154
        if (!empty($interfaceLanguage) && $platformLanguage !== $interfaceLanguage) {
155
            $interfaceLanguageIso = api_get_language_isocode($interfaceLanguage);
156
157
            $map[$interfaceLanguageIso] = $this->getLangFromFile($variable, $interfaceLanguage);
158
        }
159
160
        return $map;
161
    }
162
163
    /**
164
     * @param string $value
165
     * @param string $type
166
     *
167
     * @return \Xabbuh\XApi\Model\IRI
168
     */
169
    public function generateIri($value, $type)
170
    {
171
        return IRI::fromString(
172
            api_get_path(WEB_PATH)."xapi/$type/$value"
173
        );
174
    }
175
176
    /**
177
     * @param int $courseId
178
     */
179
    public function addCourseToolForTinCan($courseId)
180
    {
181
        // The $link param is set to "../plugin" as a hack to link correctly to the plugin URL in course tool.
182
        // Otherwise, the link en the course tool will link to "/main/" URL.
183
        $this->createLinkToCourseTool(
184
            $this->get_lang('ToolTinCan'),
185
            $courseId,
186
            'sessions_category.png',
187
            '../plugin/xapi/start.php',
188
            0,
189
            'authoring'
190
        );
191
    }
192
193
    /**
194
     * @param string $language
195
     *
196
     * @return mixed|string
197
     */
198
    public static function extractVerbInLanguage(Xabbuh\XApi\Model\LanguageMap $languageMap, $language)
199
    {
200
        $iso = self::findLanguageIso($languageMap->languageTags(), $language);
201
202
        $text = current($languageMap);
203
204
        if (isset($languageMap[$iso])) {
205
            $text = trim($languageMap[$iso]);
206
        } elseif (isset($languageMap['und'])) {
207
            $text = $languageMap['und'];
208
        }
209
210
        return $text;
211
    }
212
213
    /**
214
     * @param string $needle
215
     *
216
     * @return string
217
     */
218
    public static function findLanguageIso(array $haystack, $needle)
219
    {
220
        if (in_array($needle, $haystack)) {
221
            return $needle;
222
        }
223
224
        foreach ($haystack as $language) {
225
            if (strpos($language, $needle) === 0) {
226
                return $language;
227
            }
228
        }
229
230
        return $haystack[0];
231
    }
232
233
    public function generateLaunchUrl(
234
        $type,
235
        $launchUrl,
236
        $activityId,
237
        Agent $actor,
238
        $attemptId,
239
        $customLrsUrl = null,
240
        $customLrsUsername = null,
241
        $customLrsPassword = null,
242
        $viewSessionId = null
243
    ) {
244
        $lrsUrl = $customLrsUrl ?: $this->get(self::SETTING_LRS_URL);
245
        $lrsAuthUsername = $customLrsUsername ?: $this->get(self::SETTING_LRS_AUTH_USERNAME);
246
        $lrsAuthPassword = $customLrsPassword ?: $this->get(self::SETTING_LRS_AUTH_PASSWORD);
247
248
        $queryData = [
249
            'endpoint' => trim($lrsUrl, "/ \t\n\r\0\x0B"),
250
            'actor' => Serializer::createSerializer()->serialize($actor, 'json'),
251
            'registration' => $attemptId,
252
        ];
253
254
        if ('tincan' === $type) {
255
            $queryData['auth'] = 'Basic '.base64_encode(trim($lrsAuthUsername).':'.trim($lrsAuthPassword));
256
            $queryData['activity_id'] = $activityId;
257
        } elseif ('cmi5' === $type) {
258
            $queryData['fetch'] = api_get_path(WEB_PLUGIN_PATH).'xapi/cmi5/token.php?session='.$viewSessionId;
259
            $queryData['activityId'] = $activityId;
260
        }
261
262
        return $launchUrl.'?'.http_build_query($queryData, null, '&', PHP_QUERY_RFC3986);
263
    }
264
265
    /**
266
     * @return \Doctrine\ORM\EntityManager|null
267
     */
268
    public static function getEntityManager()
269
    {
270
        $em = Database::getManager();
271
272
        $prefixes = [
273
            __DIR__.'/../php-xapi/repository-doctrine-orm/metadata' => 'XApi\Repository\Doctrine\Mapping',
274
        ];
275
276
        $driver = new SimplifiedXmlDriver($prefixes);
277
        $driver->setGlobalBasename('global');
278
279
        $config = Database::getDoctrineConfig(api_get_configuration_value('root_sys'));
280
        $config->setMetadataDriverImpl($driver);
281
282
        try {
283
            return EntityManager::create($em->getConnection()->getParams(), $config);
284
        } catch (ORMException $e) {
285
            api_not_allowed(true, $e->getMessage());
286
        }
287
288
        return null;
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294
    public function getAdminUrl()
295
    {
296
        $webPath = api_get_path(WEB_PLUGIN_PATH).$this->get_name();
297
298
        return "$webPath/admin.php";
299
    }
300
301
    public function getLpResourceBlock(int $lpId)
302
    {
303
        $cidReq = api_get_cidreq(true, true, 'lp');
304
        $webPath = api_get_path(WEB_PLUGIN_PATH).'xapi/';
305
        $course = api_get_course_entity();
306
        $session = api_get_session_entity();
307
308
        $tools = Database::getManager()
309
            ->getRepository(XApiToolLaunch::class)
310
            ->findByCourseAndSession($course, $session);
311
312
        $importIcon = Display::return_icon('import_scorm.png');
313
        $moveIcon = Display::url(
314
            Display::return_icon('move_everywhere.png', get_lang('Move'), [], ICON_SIZE_TINY),
315
            '#',
316
            ['class' => 'moved']
317
        );
318
319
        $return = '<ul class="lp_resource"><li class="lp_resource_element">'
320
            .$importIcon
321
            .Display::url(
322
                get_lang('Import'),
323
                $webPath."tool_import.php?$cidReq&".http_build_query(['lp_id' => $lpId])
324
            )
325
            .'</li>';
326
327
        foreach ($tools as $tool) {
328
            $toolAnchor = Display::url(
329
                Security::remove_XSS($tool->getTitle()),
330
                api_get_self()."?$cidReq&"
331
                    .http_build_query(
332
                        ['action' => 'add_item', 'type' => TOOL_XAPI, 'file' => $tool->getId(), 'lp_id' => $lpId]
333
                    ),
334
                ['class' => 'moved']
335
            );
336
337
            $return .= Display::tag(
338
                'li',
339
                $moveIcon.$importIcon.$toolAnchor,
340
                [
341
                    'class' => 'lp_resource_element',
342
                    'data_id' => $tool->getId(),
343
                    'data_type' => TOOL_XAPI,
344
                    'title' => $tool->getTitle(),
345
                ]
346
            );
347
        }
348
349
        $return .= '</ul>';
350
351
        return $return;
352
    }
353
354
    /**
355
     * @throws \Exception
356
     */
357
    private function installInitialConfig()
358
    {
359
        $uuidNamespace = Uuid::v1()->toRfc4122();
360
361
        $pluginName = $this->get_name();
362
        $urlId = api_get_current_access_url_id();
363
364
        api_add_setting(
365
            $uuidNamespace,
366
            $pluginName.'_'.self::SETTING_UUID_NAMESPACE,
367
            $pluginName,
368
            'setting',
369
            'Plugins',
370
            $pluginName,
371
            '',
372
            '',
373
            '',
374
            $urlId,
375
            1
376
        );
377
378
        api_add_setting(
379
            api_get_path(WEB_PATH).'plugin/xapi/lrs.php',
380
            $pluginName.'_'.self::SETTING_LRS_URL,
381
            $pluginName,
382
            'setting',
383
            'Plugins',
384
            $pluginName,
385
            '',
386
            '',
387
            '',
388
            $urlId,
389
            1
390
        );
391
    }
392
393
    /**
394
     * @param string|null $lrsUrl
395
     * @param string|null $lrsAuthUsername
396
     * @param string|null $lrsAuthPassword
397
     *
398
     * @return \Xabbuh\XApi\Client\XApiClientInterface
399
     */
400
    private function createXApiClient($lrsUrl = null, $lrsAuthUsername = null, $lrsAuthPassword = null)
401
    {
402
        $baseUrl = $lrsUrl ?: $this->get(self::SETTING_LRS_URL);
403
        $lrsAuthUsername = $lrsAuthUsername ?: $this->get(self::SETTING_LRS_AUTH_USERNAME);
404
        $lrsAuthPassword = $lrsAuthPassword ?: $this->get(self::SETTING_LRS_AUTH_PASSWORD);
405
406
        $clientBuilder = new XApiClientBuilder();
407
        $clientBuilder
408
            ->setHttpClient(Client::createWithConfig([RequestOptions::VERIFY => false]))
409
            ->setRequestFactory(new GuzzleMessageFactory())
410
            ->setBaseUrl(trim($baseUrl, "/ \t\n\r\0\x0B"))
411
            ->setAuth(trim($lrsAuthUsername), trim($lrsAuthPassword));
412
413
        return $clientBuilder->build();
414
    }
415
416
    private function addCourseTools()
417
    {
418
        $courses = Database::getManager()
419
            ->createQuery('SELECT c.id FROM ChamiloCoreBundle:Course c')
420
            ->getResult();
421
422
        foreach ($courses as $course) {
423
            $this->addCourseToolForTinCan($course['id']);
424
        }
425
    }
426
427
    private function deleteCourseTools()
428
    {
429
        Database::getManager()
430
            ->createQuery('DELETE FROM ChamiloCourseBundle:CTool t WHERE t.category = :category AND t.link LIKE :link')
431
            ->execute(['category' => 'authoring', 'link' => '../plugin/xapi/start.php%']);
432
    }
433
}
434