Search by

qbnk / frontend-components

qbnk

Shared Frontend Components for Slim-based frontends.

Package info

bitbucket.org/qbnk/frontendcomponents

pkg:composer/qbnk/frontend-components

Statistics

Installs: 569

Dependents: 1

Suggesters: 0

6.4.0 2026-09-03 05:54 UTC

README

Settings sample for the Account-manager

$settings = [
        'account-manager' => [
			'qbank-manager-group-ids' => [20],
			'terms' => 'Lorem ipsum dolor...',
			'account-expire' => '+1 year',      // set false to disable this setting
			'apply-page-group-ids' => [1,2,3],
			'approve-page-group-ids' => [1,2,3,4],
			'custom-options' => [
				'Company' => [
					'array' => false,
					'mandatory' => true
				],
				'Country' => [
					'array' => true,
					'mandatory' => true,
					'multiple' => true,
					'options' => [
						'Sweden',
						'Norway',
						'Denmark'
					]
				]
			]
		]
    ]

How to implement...

The following chapters should explain how certain components are implemented and used in front end projects.

Download multiple fies

Since v3.0 the functionality for downloading multiple media has been updated and DownloadController::downloadMultiple() now requires different parameters. It no longer accepts a template in the parameter, instead, the download templates are set via DownloadController::setDownloadTemplate(). This method accepts a classification (eg. MimeType::CLASSIFICATION_IMAGE) and a template id. When getting the physical files, DownloadController uses DownloadController::getDownloadTemplate() for the medias classification. If you set a template to 0 or null, the original file will be fetched.

The media DownloadController::downloadMultiple() downloads are either passed as an array of MediaResponse or as an array of media ids (that must be numeric).

Example code:

$media = [
    1337,
    999,
    123,
];
// or an array of MediaResponse, eg. from a QBank search

$downloadController = new DownloadController($this->qbankApi);
		
$imageTemplates = (int) $request->getQueryParam('imageTemplates');
$videoTemplate = (int) $request->getQueryParam('videoTemplate');

// If a specific classification has more than one template, call addDownloadTemplate multiple times
foreach($imageTemplates as $imageTemplate) {
    $downloadController->addDownloadTemplate(MimeType::CLASSIFICATION_IMAGE, $imageTemplate);
}
$downloadController->addDownloadTemplate(MimeType::CLASSIFICATION_VIDEO, $videoTemplate);

$downloadController->downloadMultiple($media, $deploymentSiteId, $sessionId, $zipFileName, $deploymentPath, $debug);

DownloadController::downloadMultiple throws a number of exceptions, so it can be a good idea to wrap in it a try-catch that catches Throwable, logs the error and produces a user friendly error message.

DownloadController::setDownloadTemplate currently accepts four (4) classifications, corresponding to: MimeType::CLASSIFICATION_IMAGE, MimeType::CLASSIFICATION_VIDEO, MimeType::CLASSIFICATION_AUDIO, and MimeType::CLASSIFICATION_DOCUMENT which are the four configurable template types in QBank. For other classifications, the original file is always downloaded.

DownloadController::downloadMultiple does not support fetching multiple physical files from the same media, instead this sort of functionality must be implemented in that specific project if needs be.

Middleware\IPAutoLogin

To correctly implement the `IPAutoLogin`, the settings array must contain an array of allowed IPs, as well as a username reflecting a true user with the appropriate access:

$settings[QB_SETTINGS][QB_FRONTEND][QB_IP_AUTO_LOGIN] = [
    'username' => 'apiuser',
    'firstname' => 'Api',
    'lastname' => 'User',
    'allowedIps' => [
        '123.45.67.89',
        '123.45.*.*'
    ]
];

An important note is that, since the `IPAutoLogin creates a session depending on the users IP adress, this must be done before RequireAuthenticatedUser. This is because the RequireAuthenticatedUser middleware looks for an authenticated user (which IPAutoLogin creates). To make it execute before RequireAuthenticatedUser`, add it after - since Slim invokes middleware outside in.

Since v2.6, `IPAutoLogin` supports using wild cards in IP adresses. Use an asterisk (*) to denote wild card portions of the IP address. Note that the plugin currently only supports IPV4 addresses.

// Invoke IPAutoLogin AFTER RequireAuthenticated user
// as Slim invokes middleware from outside and in
$app->group('', function () use ($app) {
    $app->get('/someUrl', SomeClass::class . ':index');
})->add(RequireAuthenticatedUser::class)->add(IPAutoLogin::class);

Middleware\Translation

This middleware implements translation with the `gettext() functions in PHP. Somewhere in routes.php add $app->add(Translation::class);`, so that the middleware is registered.

Firstly, the middleware gets the `HTTP_ACCEPT_LANGUAGE header from the users browser. Secondly it checks for a cookie. If the cookie exists, this takes precedence over the HTTP_ACCEPT_LANGUAGE`.

You must define both the cookie name to get user selected language, as well as the keys to the settings array for the `gettext() configurating functions. This configuration might be added to the default.php` config.

define('QB_FRONTEND_TRANSLATION','frontendtranslation');
$settings[QB_SETTINGS][QB_FRONTEND][QB_FRONTEND_TRANSLATION] = [
    'directory' => realpath(__DIR__ . '/../locales'),
    'domain' => 'messages',
];

You must define the cookie name, this might also be added to `default.php`

define('QB_FRONTEND_LANG_COOKIE','qbankfrontendlanguage');

Lastly, you must be able to parse all source files after calls to `gettext() which should use the translation files. The easiest way is to add a application console to the frontendproject and use the commands php app/console.php gettext:generate and gettext:compile`.

As of 2020-02-04, a well working implementation of the application console can be found in frontends/peab-mediaportal.

Url\FilterPathCanonicalizer and Middleware\CanonicalRedirect

Reduces a filter URL to one canonical form, so the same result set stops being reachable through an unbounded number of distinct URLs. Without it every permutation, casing and stray tracking parameter is a separate URL that costs a full QBank search - which is how crawlers turn a faceted portal into load.

`FilterPathCanonicalizer is pure and framework-free. It is the inverse of the two rules already in this package: FilterController parses a filter path into selections and Item::buildLink()` composes one from them. The identical class ships on the 2.10 line, so it is deliberately written to run on PHP 7.2 upwards.

It guarantees `canon(canon($x)) === canon($x)`. The middleware relies on that to avoid redirect loops, so keep the property if you change the rules.

$canonicalizer = new QBNK\FrontendComponents\Url\FilterPathCanonicalizer([
    // Query parameters worth keeping. Anything not listed is dropped - so an
    // unconfigured whitelist drops them all, which is the canonical default.
    'queryWhitelist' => ['offset', 'query', 'sort'],

    // Must be a positive integer or it is dropped. Covers pagination: without
    // this, ?offset=<anything> regenerates an unbounded URL space.
    'queryPositiveIntegers' => ['offset'],

    // The only values a parameter may take. Anything else is dropped.
    'queryAllowedValues' => ['sort' => ['id', 'popularity']],

    // Only override if your portal configures FilterController separators.
    'separators' => ['propertySeparator' => '/'],

    // Segment order is only free to change when every facet is a flat union.
    // Set false if you use hierarchical property filters and have not verified
    // that reordering them preserves your result set.
    'sortSegments' => true,
]);

// Must run INSIDE the routing middleware, or there is no route to inspect and
// every request passes straight through. Slim's stack is last-added-outermost,
// so add this before addRoutingMiddleware().
$app->add(new QBNK\FrontendComponents\Middleware\CanonicalRedirect(
    $canonicalizer,
    $app->getResponseFactory(),
    'search',   // name of the route carrying the filter path
    '/search'   // that route's path prefix
));
$app->addRoutingMiddleware();

The canonicalizer is also useful on its own: `segments() returns the canonical facet list, which is what a portal counts for a noindex` threshold and what it iterates to build a sitemap of single-facet URLs.

Note that `CanonicalRedirect skips XHR requests. Portals that autoload further results against document.URL` would otherwise pay a redirect per page.