Skip to content
Snippets Groups Projects
Unverified Commit 297b3ca5 authored by Michael Lee's avatar Michael Lee Committed by GitHub
Browse files

Merge pull request #399 from ASCWebServices/mobile_device_detection

Re-add mobile_device_detection without composer (removal broke sites)
parents 3df30a09 1cbc5405
No related branches found
No related tags found
No related merge requests found
Showing
with 1044 additions and 0 deletions
CONTENTS OF THIS FILE
---------------------
* Introduction
* Requirements
* Installation
* Configuration
* Usage
* Maintainers
INTRODUCTION
------------
"Mobile device detection" module can detect any mobile device. You can use it
via service or "Views". This module integrate with "Views" and you can easily
to switch "Views display" for different devices.
* For a full description of the module, visit the project page:
https://www.drupal.org/project/mobile_device_detection
REQUIREMENTS
------------
-No special requirements.
INSTALLATION
------------
* Module: Install as you would normally install a contributed Drupal module.
See: https://www.drupal.org/documentation/install/modules-themes/modules-8
for further information.
CONFIGURATION
-------------
The module has no menu or modifiable settings. There is no configuration.
USAGE
-------------
Initialization
$detection_service = \Drupal::service('mobile_device_detection.object');
You can to use a couple of methods to check devices
if($detection_service->isMobile()){
If is mobile then you can get object
$detection_service->getObject();
}
if($detection_service->isTablet()){
If is tablet then you can get object
$detection_service->getObject();
}
MAINTAINERS
-----------
Current maintainers:
* Victor Isaikin - https://www.drupal.org/u/depthinteractive
* Site - https://depthinteractive.ru
This diff is collapsed.
condition.plugin.mobile_device_detection_condition_plugin:
type: condition.plugin
label: 'Show it on special devices'
mapping:
devices:
type: sequence
sequence:
type: string
name: Mobile Device Detection
type: module
description: 'This module can detect any mobile devices.'
package: Other
core_version_requirement: ^8 || ^9
dependencies:
- drupal:views
<?php
/**
* @file
* Default install and uninstall functions which set up default data.
*/
/**
* Implements hook_install().
*/
function mobile_device_detection_install() {
// Enable mobile_device_detection plugin.
$config = \Drupal::service('config.factory')->getEditable('views.settings');
$display_extenders = $config->get('display_extenders') ?: [];
$display_extenders[] = 'mobile_device_detection';
$config->set('display_extenders', $display_extenders);
$config->save();
}
/**
* Implements hook_uninstall().
*/
function mobile_device_detection_uninstall() {
// Disable mobile_device_detection plugin.
$config = \Drupal::service('config.factory')->getEditable('views.settings');
$display_extenders = $config->get('display_extenders') ?: [];
$key = array_search('mobile_device_detection', $display_extenders);
if ($key !== FALSE) {
unset($display_extenders[$key]);
$config->set('display_extenders', $display_extenders);
$config->save();
}
}
<?php
/**
* @file
* Controls the visual building blocks, views a page is constructed with.
*/
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\views\ViewExecutable;
/**
* Implements hook_help().
*/
function mobile_device_detection_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.mobile_device_detection':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('"Mobile device detection" module can detect any mobile device. You can use it via service or "Views". This module integrate with "Views" and you can easily to switch "Views display" for different devices.') . '</p>';
$output .= '<p>' . t('For more information, see the <a href="https://www.drupal.org/project/mobile_device_detection">Mobile device detection</a>.') . '</p>';
$output .= '<h3>' . t('Usage') . '</h3>';
$output .= '<p>' . t('Initialization:') . '</p>';
$output .= '<p>' . t('$detection_service = \Drupal::service("mobile_device_detection.object");') . '</p>';
$output .= '<hr>';
$output .= '<p>' . t('Implementation:') . '</p>';
$output .= '<p>' . t('if($detection_service->isMobile()) { $detection_service->getObject(); }') . '</p>';
$output .= '<p>' . t('if($detection_service->isTablet()) { $detection_service->getObject(); }') . '</p>';
return $output;
}
}
/**
* Implements hook_views_post_execute().
*/
function mobile_device_detection_views_post_execute(ViewExecutable $view) {
$display = $view->getDisplay();
$extenders = $display->getExtenders();
if (!isset($extenders['mobile_device_detection'])) {
return;
}
if (!$extenders['mobile_device_detection']->getDevices()) {
return;
}
$devices = array_filter($extenders['mobile_device_detection']->getDevices());
if (!empty($devices)) {
\Drupal::service('page_cache_kill_switch')->trigger();
$view->element['#cache']['contexts'] = ['cache_context.session'];
$view->element['#cache']['max-age'] = 0;
$entity = \Drupal::service('mobile_device_detection.object');
$view->build_info['fail'] = TRUE;
foreach ($devices as $key => $value) {
if ($key != 'desktop') {
$func = 'is' . ucfirst($value);
if (is_callable([$entity, $func]) && $entity->$func()) {
$view->build_info['fail'] = FALSE;
}
}
else {
if (!$entity->isMobile() && !$entity->isTablet()) {
$view->build_info['fail'] = FALSE;
}
}
}
}
}
services:
mobile_device_detection.properties:
class: Drupal\mobile_device_detection\Object\MobileDeviceDetectionAttributes
mobile_device_detection.object:
class: Drupal\mobile_device_detection\Object\MobileDeviceDetection
arguments: ['@mobile_device_detection.properties', '@request_stack']
# plugin_extender
mobile_device_detection.plugin_extender:
class: Drupal\mobile_device_detection\Plugin\views\display_extender\MobileDeviceDetectionExtenderPlugin
<?php
namespace Drupal\mobile_device_detection\Object;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* MobileDeviceDetection object.
*/
class MobileDeviceDetection {
/**
* A default attributes instance.
*
* @var \Drupal\mobile_device_detection\Object\MobileDeviceDetectionAttributes
*/
private $attributes;
/**
* Request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
public $request;
/**
* The MobileDeviceDetectionObject mobileHeaders.
*
* @var array
*/
private $mobileHeaders;
/**
* The MobileDeviceDetectionObject cloudHeaders.
*
* @var array
*/
private $cloudHeaders;
/**
* The MobileDeviceDetectionObject userAgentHeaders.
*
* @var array
*/
private $userAgentHeaders;
/**
* The MobileDeviceDetectionObject object.
*
* @var object
*/
private $object;
/**
* The constructoror.
*/
public function __construct($attributes, $request) {
$this->setAttributes($attributes);
$this->setRequest($request);
$this->init();
}
/**
* Initialization.
*/
private function init() {
$this->object = new \stdClass();
$this->object->type = NULL;
$headers = $this->getRequest()->getCurrentRequest()->server->all();
$this->setMobileHeaders($headers);
$this->setCloudHeaders($headers);
$this->setUserAgentHeaders($this->getAttributes()->get('user_agent_headers'));
if ($this->check('mobile')) {
$this->object->type = 'mobile';
}
if ($this->check('tablet')) {
$this->object->type = 'tablet';
}
}
/**
* Get object.
*/
public function getObject() {
if (isset($this->object->type)) {
$this->getOperatingSystem();
$this->getBrowser();
return $this->object;
}
}
/**
* Is checking mobile or not.
*/
public function isMobile() {
return ($this->object->type === 'mobile') ? TRUE : FALSE;
}
/**
* Is checking tablet or not.
*/
public function isTablet() {
return ($this->object->type === 'tablet') ? TRUE : FALSE;
}
/**
* Set attributes.
*/
protected function setAttributes($attributes) {
$this->attributes = $attributes;
}
/**
* Get attributes.
*/
protected function getAttributes() {
return $this->attributes;
}
/**
* Set request.
*/
protected function setRequest($request) {
$this->request = $request;
}
/**
* Get request.
*/
protected function getRequest() {
return $this->request;
}
/**
* Set headers.
*/
protected function setMobileHeaders($headers) {
array_walk($headers, function (&$v, $k) {
if (substr($k, 0, 5) === 'HTTP_') {
$this->mobileHeaders[$k] = $v;
}
});
}
/**
* Get headers.
*/
protected function getMobileHeaders() {
return $this->mobileHeaders;
}
/**
* Set cloud headers.
*/
protected function setCloudHeaders($headers) {
array_walk($headers, function (&$v, $k) {
if (substr(strtolower($k), 0, 16) === 'http_cloudfront_') {
$this->cloudHeaders[strtoupper($k)] = $v;
}
});
}
/**
* Get cloud headers.
*/
protected function getCloudHeaders() {
return $this->cloudHeaders;
}
/**
* Set user agent headers.
*/
protected function setUserAgentHeaders($headers) {
$this->userAgentHeaders = implode(' ', array_intersect_key($this->getMobileHeaders(), array_flip($headers)));
if (!$this->userAgentHeaders && !empty($this->getCloudHeaders())) {
$this->userAgentHeaders = 'Amazon CloudFront';
}
}
/**
* Get user agent headers.
*/
protected function getUserAgentHeaders() {
return $this->userAgentHeaders;
}
/**
* Is checking which kind of device using.
*/
private function check($type) {
if ($this->getUserAgentHeaders() === 'Amazon CloudFront') {
$headers = $this->setCloudHeaders($this->getRequest()->getCurrentRequest()->server->all());
if (array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $headers) && $headers['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') {
return TRUE;
}
}
switch ($type) {
case 'mobile':
$options = array_merge($this->getAttributes()->get('phone_devices'));
$headers = array_intersect_key($this->getAttributes()->get('mobile_headers'), $this->getMobileHeaders());
foreach ($headers as $key => $value) {
foreach ($value as $v) {
if (strpos($this->getMobileHeaders()[$key], $v) !== FALSE) {
return TRUE;
}
}
}
goto device_detect;
break;
case 'tablet':
$options = array_merge($this->getAttributes()->get('tablet_devices'));
case 'deviceDetect':
device_detect:
$device = false;
foreach ($options as $value) {
if (!empty($value)) {
if ($this->match($value)) {
$device = TRUE;
}
}
}
if ($device) {
foreach ($this->getAttributes()->get('browsers') as $value) {
if (!empty($value)) {
if ($this->match($value)) {
return TRUE;
}
}
}
}
break;
}
return FALSE;
}
/**
* Get operating system.
*/
private function getOperatingSystem() {
$this->object->OS = $this->get($this->getAttributes()->get('operating_systems'));
$this->version($this->object->OS);
}
/**
* Get browser.
*/
private function getBrowser() {
$this->object->browser = $this->get($this->getAttributes()->get('browsers'));
$this->version($this->object->browser);
}
/**
* Get options.
*/
private function get($options) {
foreach ($options as $key => $value) {
if (!empty($value)) {
if ($this->match($value)) {
return $key;
}
}
}
}
/**
* Match headers.
*/
private function match($value) {
return (bool) preg_match(sprintf('#%s#is', $value), $this->getUserAgentHeaders(), $matches);
}
/**
* Versions.
*/
private function version($name) {
$properties = (array) $this->getAttributes()->get('properties')[$name];
foreach ($properties as $value) {
$pattern = str_replace('[VER]', $this->getAttributes()->get('VER'), $value);
preg_match(sprintf('#%s#is', $pattern), $this->getUserAgentHeaders(), $matches);
if (!empty($matches)) {
$this->object->$name[] = $matches;
}
}
}
}
<?php
namespace Drupal\mobile_device_detection\Object;
use Symfony\Component\Yaml\Yaml;
/**
* MobileDeviceDetectionAttributes class.
*/
class MobileDeviceDetectionAttributes {
/**
* {@inheritdoc}
*/
public function get($attribute = NULL) {
$file = __DIR__ . '/../../config/attributes/attributes.yml';
if (!file_exists($file)) {
return FALSE;
}
$attributes = Yaml::parse(file_get_contents($file))['attributes'];
if (!is_null($attribute)) {
return $attributes[$attribute];
}
return $attributes;
}
}
<?php
namespace Drupal\mobile_device_detection\Plugin\Condition;
use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Form\FormStateInterface;
/**
* This main class which add ability to determine device.
*
* @Condition(
* id = "mobile_device_detection_condition_plugin",
* label = @Translation("Show it on special devices"),
* )
*/
class MobileDeviceDetectionConditionPlugin extends ConditionPluginBase {
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$form['negate'] = [];
$form['devices'] = [
'#type' => 'checkboxes',
'#title' => $this->t('When the device is determined'),
'#default_value' => $this->configuration['devices'],
'#options' => [
'mobile' => $this->t('Mobile'),
'tablet' => $this->t('Tablet'),
'desktop' => $this->t('Desktop'),
],
'#description' => $this->t('If you select no devices, the condition will evaluate to TRUE for all devices.'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [
'devices' => [],
] + parent::defaultConfiguration();
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['devices'] = array_filter($form_state->getValue('devices'));
parent::submitConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function summary() {
$devices = $this->configuration['devices'];
if (count($devices) > 1) {
$devices = implode(', ', $devices);
}
else {
$devices = reset($devices);
}
if (!empty($this->configuration['negate'])) {
return $this->t('The device is not @devices', ['@devices' => $devices]);
}
else {
return $this->t('The device is @devices', ['@devices' => $devices]);
}
}
/**
* {@inheritdoc}
*/
public function evaluate() {
if (empty($this->configuration['devices']) && !$this->isNegated()) {
return TRUE;
}
\Drupal::service('page_cache_kill_switch')->trigger();
$entity = \Drupal::service('mobile_device_detection.object');
foreach ($this->configuration['devices'] as $key => $value) {
if ($key != 'desktop') {
$func = 'is' . ucfirst($value);
if (is_callable([$entity, $func]) && $entity->$func()) {
return TRUE;
}
}
else {
if (!$entity->isMobile() && !$entity->isTablet()) {
return TRUE;
}
}
}
return FALSE;
}
}
<?php
namespace Drupal\mobile_device_detection\Plugin\views\display_extender;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase;
/**
* Default display extender plugin. It is extends Views display.
*
* @ingroup views_display_extender_plugins
*
* @ViewsDisplayExtender(
* id = "mobile_device_detection",
* title = @Translation("Mobile device detection display extender"),
* help = @Translation("Mobile device detection settings for this view."),
* no_ui = TRUE
* )
*/
class MobileDeviceDetectionExtenderPlugin extends DisplayExtenderPluginBase {
/**
* Provide the key options for this plugin.
*/
public function defineOptionsAlter(&$options) {
$options['device_detection'] = [
'contains' => [
'title' => ['default' => ''],
'description' => ['default' => ''],
],
];
}
/**
* Provide the default summary for options and category in the views UI.
*/
public function optionsSummary(&$categories, &$options) {
$categories['device_detection'] = [
'title' => $this->t('Show "View" on special devices'),
'column' => 'second',
];
$options['device_detection'] = [
'category' => 'other',
'title' => $this->t('Show "View" on special devices'),
'value' => $this->getDevices() ? implode(', ', $this->getDevices()) : $this->t('none'),
];
}
/**
* Provide a form to edit options for this plugin.
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
if ($form_state->get('section') == 'device_detection') {
$form['#title'] .= $this->t('Show "View" on special devices');
$form['device_detection']['#type'] = 'container';
$form['device_detection']['#tree'] = TRUE;
$form['device_detection']['devices'] = [
'#type' => 'checkboxes',
'#options' => [
'mobile' => $this->t('Mobile'),
'tablet' => $this->t('Tablet'),
'desktop' => $this->t('Desktop'),
],
'#default_value' => $this->getDevices() ? $this->getDevices() : [],
'#title' => $this->t('Select device'),
];
}
}
/**
* Validate the options form.
*/
public function validateOptionsForm(&$form, FormStateInterface $form_state) {}
/**
* Handle any special handling on the validate form.
*/
public function submitOptionsForm(&$form, FormStateInterface $form_state) {
if ($form_state->get('section') == 'device_detection') {
$device_detection = $form_state->getValue('device_detection');
$this->options['device_detection'] = $device_detection;
}
}
/**
* Set up any variables on the view prior to execution.
*/
public function preExecute() {}
/**
* Inject anything into the query that the display_extender handler needs.
*/
public function query() {}
/**
* Static member function to list which sections are defaultable.
*/
public function defaultableSections(&$sections, $section = NULL) {}
/**
* Get the selected devices for this display.
*/
public function getDevices() {
$devices = isset($this->options['device_detection']) ? $this->options['device_detection'] : NULL;
if ($devices && isset($devices['devices'])) {
$devices = array_filter($devices['devices'], function ($var) {
return($var != FALSE);
});
}
return $devices;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment