icon.module in Icon API 8
Same filename and directory in other branches
icon.module Provides icon integration with menu items.
File
icon.moduleView source
<?php
/**
* @file
* icon.module
* Provides icon integration with menu items.
*/
use Drupal\Core\Cache\Cache;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ExtensionDiscovery;
define('ICON_ADMIN_PATH', 'admin/config/media/icon');
// Include necessary files. Normally these would all be in the main .module
// file, however it's easier to manage in separate files.
$includes = array(
'bundles',
'cache',
'element',
'render',
'theme',
'utilities',
);
foreach ($includes as $include) {
require_once __DIR__ . "/includes/{$include}.inc";
// TODO - test this - replaced dirname(__FILE__) with __DIR__. Should be functionally equivalent and __DIR__ became available in PHP5.3
}
/**
* Implements hook_hook_info().
*/
function icon_hook_info() {
$hooks = array();
$icon_hooks = array(
'icon_bundles',
'icon_bundle_delete',
'icon_bundle_list_alter',
'icon_permission',
'icon_providers',
'icon_render_hooks',
);
foreach ($icon_hooks as $hook) {
$hooks[$hook] = array(
'group' => 'icon',
);
}
return $hooks;
}
/**
* Implements hook_library().
*/
function icon_library() {
$libaries_path = drupal_get_path('module', 'icon') . '/libraries';
$libraries['icon_selector'] = array(
'title' => 'Icon Selector',
'website' => 'http://drupal.org/project/icon',
'version' => '1.0.0',
'css' => array(
$libaries_path . '/icon_selector/css/icon_selector.css' => array(),
),
'js' => array(
$libaries_path . '/icon_selector/js/icon_selector.js' => array(),
0 => array(
'type' => 'setting',
'data' => array(
'icon_selector' => array(
'bundles' => array_keys(icon_bundles()),
),
),
),
),
);
return $libraries;
}
/**
* Implements hook_menu().
*
* @FIXME - partially fixed.
* This implementation of hook_menu() cannot be automatically converted because
* it contains logic (i.e., branching statements, function calls, object
* instantiation, etc.) You will need to convert it manually. Sorry!
*
* For more information on how to convert hook_menu() to Drupal 8's new routing
* and linking systems, see https://api.drupal.org/api/drupal/core%21includes%21menu.inc/group/menu/8
*/
/* function icon_menu() {
$module_path = drupal_get_path('module', 'icon');
$items = array();
// Fixed = in icon.links.menu.yaml
// $items[ICON_ADMIN_PATH] = array(
// 'title' => 'Icons',
// 'description' => 'Overview of all available icons.',
// 'page callback' => 'drupal_get_form',
// 'page arguments' => array('icon_bundle_overview_form'),
// 'access arguments' => array('administer icons'),
// 'file' => 'admin.inc',
// 'file path' => $module_path . '/includes',
// );
// $items[ICON_ADMIN_PATH . '/overview'] = array(
// 'type' => MENU_DEFAULT_LOCAL_TASK,
// 'title' => 'Bundles',
// 'description' => 'Overview of all available icon bundles.',
// 'weight' => -10,
// );
/* @FIXME there are dynamically created local menu items, based on the icon sets found.
* The proposal is to use discoverable annotated handlers for the sets. Once a set
* has been found, it will need to be added to the menus. But that's not going to happen here.
*
* Note: IconSets used to be called Icon Bundles.
*
* Suggestion - we move these to a table on the overview page.
*
*
$import_providers = icon_providers_support_import();
if (!empty($import_providers)) {
$items[ICON_ADMIN_PATH . '/import'] = array(
'type' => MENU_LOCAL_TASK,
'title' => 'Import',
'description' => 'Import a bundle from a provider.',
'page callback' => 'drupal_get_form',
'page arguments' => array('icon_provider_import_form'),
'access arguments' => array('administer icons'),
'file' => 'import.inc',
'file path' => $module_path . '/includes',
);
}
$items[ICON_ADMIN_PATH . '/bundle/%icon_bundle'] = array(
'title callback' => 'icon_bundle_get_title',
'title arguments' => array(5),
'description' => 'An icon bundle.',
'page callback' => 'icon_bundle_list',
'page arguments' => array(5),
'access arguments' => array('administer icons'),
'theme callback' => 'icon_bundle_get_theme',
'theme arguments' => array(5),
'file' => 'admin.inc',
'file path' => $module_path . '/includes',
);
$items[ICON_ADMIN_PATH . '/bundle/%icon_bundle/icons'] = array(
'type' => MENU_DEFAULT_LOCAL_TASK,
'title' => 'Icons',
'description' => 'Provide an overview of all available icon bundles.',
'weight' => -10,
);
$items[ICON_ADMIN_PATH . '/bundle/%icon_bundle/configure'] = array(
'type' => MENU_LOCAL_TASK,
'title' => 'Configure',
'description' => 'Form callback for configuring an icon bundle.',
'page callback' => 'drupal_get_form',
'page arguments' => array('icon_bundle_configure_form', 5),
'access arguments' => array('administer icons'),
'file' => 'admin.inc',
'file path' => $module_path . '/includes',
);
$items[ICON_ADMIN_PATH . '/bundle/%icon_bundle/delete'] = array(
'title' => 'Delete',
'description' => 'Confirmation page for deleting an icon bundle from the database.',
'page callback' => 'drupal_get_form',
'page arguments' => array('icon_bundle_delete_form', 5),
'type' => MENU_CALLBACK,
'access arguments' => array('administer icons'),
'file' => 'admin.inc',
'file path' => $module_path . '/includes',
);
$items[ICON_ADMIN_PATH . '/bundle/%icon_bundle/reset'] = array(
'title' => 'Reset',
'description' => 'Confirmation page for resetting a module or theme provided bundle that has been overridden in the database.',
'page callback' => 'drupal_get_form',
'page arguments' => array('icon_bundle_reset_form', 5),
'type' => MENU_CALLBACK,
'access arguments' => array('administer icons'),
'file' => 'admin.inc',
'file path' => $module_path . '/includes',
);
// The actual path will be set in hook_menu_alter() but we want the item to be
// defined here to let the menu system fill-in defaults. To ensure we do not
// have path collisions, we just temporarily a child of our admin path.
$view_path_alias = ICON_ADMIN_PATH . '/tmp';
$items[$view_path_alias] = $items[ICON_ADMIN_PATH];
$items[$view_path_alias]['access arguments'] = array('view icons');
$items[$view_path_alias . '/%icon_bundle'] = $items[ICON_ADMIN_PATH . '/bundle/%icon_bundle'];
$items[$view_path_alias . '/%icon_bundle']['access arguments'] = array('view icons');
$items[$view_path_alias . '/%icon_bundle']['title arguments'] = array(1);
$items[$view_path_alias . '/%icon_bundle']['page arguments'] = array(1);
$items[$view_path_alias . '/%icon_bundle']['theme arguments'] = array(1);
return $items;
}
*/
/**
* Implements hook_menu_alter().
*/
// @FIXME This was commented out during auto upgrade
// This will need to be moved into the routing system etc.
/*
*
function icon_menu_alter(&$items) {
// Create a path alias for users with the "view icons" permission.
// @FIXME
// Could not extract the default value because it is either indeterminate, or
// not scalar. You'll need to provide a default value in
// config/install/icon.settings.yml and config/schema/icon.schema.yml.
$view_path_alias = \Drupal::config('icon.settings')->get('icon_api_view_path_alias');
// If variable is not set and path is not taken, set it.
if ($view_path_alias === NULL && empty($items['icons'])) {
$view_path_alias = 'icons';
\Drupal::configFactory()->getEditable('icon.settings')->set('icon_api_view_path_alias', $view_path_alias)->save();
}
$tmp_path = ICON_ADMIN_PATH . '/tmp';
if (!empty($view_path_alias)) {
$items[$view_path_alias] = $items[$tmp_path];
$items[$view_path_alias . '/%icon_bundle'] = $items[$tmp_path . '/%icon_bundle'];
}
unset($items[$tmp_path]);
unset($items[$tmp_path . '/%icon_bundle']);
}
*/
/**
* Implements hook_permission().
*
* Invokes hook_icon_permission() so sub-modules can be grouped together with
* the Icon API module on the permissions table.
*/
// @FIXME This code now moved to icon.permissions.yml but the recursive array aspect which groups things isn't. Hoping that permissions has a grouping mechanism
// sorted yet.
/* function icon_permission() {
return array_merge_recursive(array(
'administer icons' => array(
'title' => t('Administer Icons'),
'description' => t('Grants selected roles full administrative permissions for all aspects of the Icon API. It supersedes all permissions below.'),
'restrict access' => TRUE,
),
'view icons' => array(
'title' => t('View Icons'),
'description' => t('Grants selected roles permission to view all icons in enabled bundles.'),
),
), \Drupal::moduleHandler()->invokeAll('icon_permission'));
}
*/
/**
* Returns information about icons render hooks.
*
* @param string $hook
* (optional) The name of the render hook to return information for. If
* omitted, render hook information provided by all modules and themes will
* be returned.
* @param bool $reset
* Boolean to force reset of the cached data. Default: FALSE.
*
* @return array|false
* An associative array containing render hook information from all modules
* and themes, the information for the render hook specified by $hook, or
* FALSE if the render hook $name is not registered.
*
* @see hook_icon_render_hooks()
*/
function &icon_render_hooks($hook = NULL, $reset = FALSE) {
$hooks =& drupal_static(__FUNCTION__);
if (!isset($hooks) || $reset) {
if (!$reset && ($cache = \Drupal::cache()
->get('icon_render_hooks')) && !empty($cache->data)) {
$hooks = $cache->data;
}
else {
$hooks = array();
// Gather information from extensions that implement
// hook_icon_render_hooks().
foreach (icon_extension_implements('icon_render_hooks') as $extension => $type) {
$extension_hooks = (array) icon_extension_invoke($type, $extension, 'icon_render_hooks');
foreach ($extension_hooks as $render_hook => $data) {
if (!is_string($render_hook) && is_string($data)) {
$render_hook = $data;
$data = array();
}
$data['name'] = $render_hook;
$data['type'] = $type;
$data[$type] = $extension;
if (!isset($data['file'])) {
$data['file'] = 'module' === $type ? $extension . '.module' : 'template.php';
}
if (!isset($data['path'])) {
$data['path'] = drupal_get_path($type, $extension);
}
$hooks[$render_hook] = $data;
}
}
// Allow extensions to alter render hook information.
\Drupal::moduleHandler()
->alter('icon_render_hooks', $hooks);
// Cache the render hook information.
\Drupal::cache()
->set('icon_render_hooks', $hooks);
}
}
if (isset($hook)) {
if (!empty($hooks[$hook])) {
return $hooks[$hook];
}
else {
$false = FALSE;
return $false;
}
}
return $hooks;
}
/**
* Default properties for a bundle definition.
*
* @param array $bundle
* An associative array of bundle information, passed by reference.
* @param string $name
* The machine name of the bundle.
*/
function icon_bundle_defaults(&$bundle = array(), $name = '') {
$bundle += array(
'icons' => array(),
'name' => $name,
'provider' => '',
'settings' => array(),
'status' => 1,
'title' => $name,
'version' => '',
'#attached' => array(),
);
return $bundle;
}
/**
* Returns information about all icon bundles.
*
* @param string $name
* The name of the bundle to load.
* @param bool $reset
* Boolean to force reset of the cached data. Default: FALSE.
*
* @return array|false
* An associative array containing information for all bundles.
*
* @see hook_icon_info()
*/
function icon_bundles($name = NULL, $reset = FALSE) {
$bundles =& drupal_static(__FUNCTION__);
if (!isset($bundles) || $reset) {
if (!$reset && ($cache = \Drupal::cache()
->get('icon_bundles')) && !empty($cache->data)) {
$bundles = $cache->data;
}
else {
$bundles = array();
// Gather information from extensions that implement hook_icon_bundles().
foreach (icon_extension_implements('icon_bundles') as $extension => $type) {
$extension_bundles = (array) icon_extension_invoke($type, $extension, 'icon_bundles');
foreach ($extension_bundles as $bundle_name => $bundle) {
icon_bundle_defaults($bundle, $bundle_name);
if (empty($bundle['provider'])) {
$bundle['provider'] = $extension;
}
// Alphabetically sort the icons.
if (!empty($bundle['icons'])) {
ksort($bundle['icons']);
}
// In cases where themes may provide sprite icons (such as Bootstrap),
// we need to specify the theme to use for this bundle. These types
// of bundles do not attach a separate CSS file with the bundle and
// the sprite classes are instead, generated with the theme's CSS.
// @see icon_bundle_get_theme()
// @see icon_menu().
if ($type === 'theme' && $bundle['render'] === 'sprite' && empty($bundle['#attached']['css'])) {
$bundle['theme'] = $extension;
}
$bundles[$bundle_name] = $bundle;
}
}
// Gather database bundles (which overrides any module implementations).
$database_bundles = \Drupal::database()
->select('icon_bundle', 'b')
->fields('b')
->execute();
foreach ($database_bundles as $database_bundle) {
$bundle = unserialize($database_bundle->bundle);
if ($bundle === FALSE) {
$bundle = array();
}
else {
icon_bundle_defaults($bundle, $bundle['name']);
if (!empty($bundles[$database_bundle->name])) {
$bundle['overridden'] = TRUE;
}
}
$bundle['database'] = TRUE;
$bundle['status'] = (int) $database_bundle->status;
if (isset($bundles[$database_bundle->name])) {
$bundle = array_merge($bundles[$database_bundle->name], $bundle);
}
$bundles[$database_bundle->name] = $bundle;
}
// Allow extensions to alter the bundles.
\Drupal::moduleHandler()
->alter('icon_bundles', $bundles);
// Cache the info.
\Drupal::cache()
->set('icon_bundles', $bundles);
}
}
if (isset($name)) {
if (!empty($bundles[$name])) {
return $bundles[$name];
}
else {
$false = FALSE;
return $false;
}
}
return $bundles;
}
/**
* Delete the icon bundle that matches {icon_bundle}.name in the database.
*
* @param array $bundle
* The icon bundle array.
*
* @return bool
* TRUE if successful, FALSE if bundle does not exist or on failure.
*/
function icon_bundle_delete(array $bundle = array()) {
if (empty($bundle['name']) || !icon_bundle_load($bundle['name'])) {
return FALSE;
}
// Execute the query.
try {
// Execute query and remove database entries.
\Drupal::database()
->delete('icon_bundle')
->condition('name', $bundle['name'])
->execute();
// Delete files if not in code and path starts in public folder and exists.
if (empty($bundle['overridden']) && strpos($bundle['path'], 'public://') === 0 && file_exists($bundle['path'])) {
file_unmanaged_delete_recursive($bundle['path']);
}
// Determine which hook to invoke.
$hook = 'icon_bundle_' . (!empty($bundle['overridden']) ? t('reset') : t('delete'));
// Invoke hook_icon_bundle_reset() or hook_icon_bundle_delete() accordingly.
foreach (icon_extension_implements($hook) as $extension => $type) {
icon_extension_invoke($type, $extension, $hook, $bundle);
}
icon_clear_all_caches();
drupal_set_message(t('The icon bundle %bundle has been successfully !action.', array(
'!action' => !empty($bundle['overridden']) ? t('reset') : t('deleted'),
'%bundle' => $bundle['title'],
)));
return TRUE;
} catch (Exception $e) {
drupal_set_message(t('An error occurred while attempting to !action the icon bundle "%bundle":<br /><code>@message</code>', array(
'!action' => !empty($bundle['overridden']) ? t('reset') : t('delete'),
'%bundle' => $bundle['title'],
'@message' => $e
->getMessage(),
)), 'error');
}
return FALSE;
}
/**
* Disable the icon bundle that matches {icon_bundle}.name in the database.
*
* @param array $bundle
* The icon bundle array.
*
* @return bool
* TRUE if successful, FALSE if the bundle is already disabled or on failure.
*/
function icon_bundle_disable(array $bundle = array()) {
$bundle['status'] = 0;
if (icon_bundle_save($bundle)) {
drupal_set_message(t('The icon bundle %bundle has been disabled.', array(
'%bundle' => $bundle['name'],
)));
icon_clear_all_caches();
return TRUE;
}
drupal_set_message(t('An error occurred while attemping to disable the icon bundle: %bundle.', array(
'%bundle' => $bundle['name'],
)), 'error');
return FALSE;
}
/**
* Enable the icon bundle that matches {icon_bundle}.name in the database.
*
* @param array $bundle
* The icon bundle array.
*
* @return bool
* TRUE if successful, FALSE if the bundle is already enabled or on failure.
*/
function icon_bundle_enable(array $bundle = array()) {
$bundle['status'] = 1;
if (icon_bundle_save($bundle)) {
drupal_set_message(t('The icon bundle %bundle has been enabled.', array(
'%bundle' => $bundle['name'],
)));
icon_clear_all_caches();
return TRUE;
}
drupal_set_message(t('An error occurred while attemping to enable the icon bundle: %bundle.', array(
'%bundle' => $bundle['name'],
)), 'error');
return FALSE;
}
/**
* Helper function to return the proper theme.
*
* Necessary for displaying a list of icons of a specific bundle.
*/
function icon_bundle_get_theme($bundle, $global = FALSE) {
$theme = \Drupal::theme()
->getActiveTheme()
->getName();
return !empty($bundle['theme']) && !$global ? $bundle['theme'] : $theme;
}
/**
* Helper function to return the page title for bundles.
*/
function icon_bundle_get_title($bundle) {
return !empty($bundle['title']) ? $bundle['title'] : t('Bundle');
}
/**
* Load a specific bundle.
*
* @param string $name
* The name of the bundle to load.
*
* @return array
* An associative array of bundle information as returned from
* icon_bundles().
*/
function icon_bundle_load($name) {
$loaded =& drupal_static(__FUNCTION__, array());
if (empty($loaded[$name])) {
$loaded[$name] = icon_bundles($name);
}
return $loaded[$name];
}
/**
* Save an icon bundle in the {icon_bundle} table.
*
* @param array $bundle
* The icon bundle array.
*
* @return int|false
* If the save failed, returns FALSE. If successful, returns SAVED_NEW or
* SAVED_UPDATED, depending on the drupal_write_record() operation
* that was performed.
*/
function icon_bundle_save(array $bundle = array()) {
if (empty($bundle['name'])) {
return FALSE;
}
// Allow extensions to alter the bundle before it's saved.
\Drupal::moduleHandler()
->alter('icon_bundle_save', $bundle);
$primary_keys = array();
$record = array(
'name' => $bundle['name'],
);
$existing_bundle = icon_bundle_load($bundle['name']);
if (!$existing_bundle) {
$existing_bundle = array();
}
// If the existing bundle is from the database, update the record.
if (!empty($existing_bundle['database'])) {
$primary_keys[] = 'name';
}
// Determine if there are differences between an existing bundle and this one.
$diff = icon_array_diff_recursive($existing_bundle, $bundle);
// If the status has changed, update the status field.
if (isset($diff['status'])) {
$record['status'] = (int) $bundle['status'];
// Remove status from $diff to determine if anything else needs to be saved.
unset($diff['status']);
}
// If there are still differences, replace the entire {icon_bundle}.bundle
// field with the updated bundle array.
if (!empty($diff)) {
$record['bundle'] = $bundle;
}
// Only write to the database if the record exists and needs to be saved.
if (isset($record['status']) || isset($record['bundle'])) {
$status = \Drupal::database()
->merge('icon_bundle')
->key(array(
'name' => $record['name'],
))
->fields(array(
'bundle' => $record['bundle'],
'status' => $record['status'],
))
->execute();
if ($status) {
icon_clear_all_caches();
return $status;
}
}
return FALSE;
}
/**
* Default properties for a provider definition.
*
* @param array $provider
* An associative array of provider information, passed by reference.
* @param string $name
* The machine name of the provider.
*
* @return array|false
* An associative array containing information about a provider
*/
function icon_provider_defaults(&$provider = array(), $name = '') {
$provider += array(
'default bundle' => array(),
'name' => $name,
'title' => $name,
'url' => '',
);
return $provider;
}
/**
* Returns information about all icon providers.
*
* @param string $name
* The name of the provider to load.
* @param bool $reset
* Boolean to force reset of the cached data. Default: FALSE.
*
* @return array|false
* An associative array containing information for all providers.
*
* @see hook_icon_info()
*/
function icon_providers($name = NULL, $reset = FALSE) {
$providers =& drupal_static(__FUNCTION__);
if (!isset($providers) || $reset) {
if (!$reset && ($cache = \Drupal::cache()
->get('icon_providers')) && !empty($cache->data)) {
$providers = $cache->data;
}
else {
$providers = array();
// Invoke hook_icon_providers().
foreach (icon_extension_implements('icon_providers') as $extension => $type) {
$extension_providers = (array) icon_extension_invoke($type, $extension, 'icon_providers');
foreach ($extension_providers as $provider_name => $provider) {
if ($provider_name === 'automatic') {
drupal_set_message(t('The !type %extension tried to specify a provider with the name: %name. This is a reserved name and cannot be used, please rename your provider.', array(
'!type' => $type,
'%extension' => $extension,
'%name' => $provider_name,
)), 'warning');
continue;
}
icon_provider_defaults($provider, $provider_name);
$provider['name'] = $provider_name;
$provider['type'] = $type;
$provider[$type] = $extension;
$providers[$provider_name] = $provider;
}
}
// Allow extensions to alter the providers.
\Drupal::moduleHandler()
->alter('icon_providers', $providers);
// Cache the info.
\Drupal::cache()
->set('icon_providers', $providers);
}
}
if (!empty($name)) {
if (!empty($providers[$name])) {
return $providers[$name];
}
return FALSE;
}
return $providers;
}
/**
* Returns information about whether a provider supports importing.
*
* @todo make this "JSON importing"?
*
* @param string $name
* The name of the provider to load.
*
* @return array|false
* Returns an array of providers that support importing or just $name if it
* was provided. Returns FALSE if there are no providers or specific $name
* does not exist.
*/
function icon_providers_support_import($name = NULL) {
$providers =& drupal_static(__FUNCTION__);
if (!isset($providers)) {
$providers = array();
foreach (icon_providers() as $provider) {
if (icon_extension_hook($provider['type'], $provider[$provider['type']], 'icon_' . $provider['name'] . '_import_validate') && icon_extension_hook($provider['type'], $provider[$provider['type']], 'icon_' . $provider['name'] . '_import_process')) {
$providers[$provider['name']] = $provider;
}
}
}
if (!empty($name)) {
if (!empty($providers[$name])) {
return $providers[$name];
}
return FALSE;
}
return $providers;
}
/**
* Load a specific provider.
*
* @param string $name
* The name of the provider to load.
*
* @return array
* An associative array of provider information as returned from
* icon_providers().
*/
function icon_provider_load($name) {
$loaded =& drupal_static(__FUNCTION__, array());
if (empty($loaded[$name])) {
if (($cache = \Drupal::cache('cache_icon_providers')
->get($name)) && !empty($cache->data)) {
$loaded[$name] = $cache->data;
}
else {
$provider = icon_providers($name);
\Drupal::cache('cache_icon_providers')
->set($name, $provider);
$loaded[$name] = $provider;
}
}
return $loaded[$name];
}
Functions
Name | Description |
---|---|
icon_bundles | Returns information about all icon bundles. |
icon_bundle_defaults | Default properties for a bundle definition. |
icon_bundle_delete | Delete the icon bundle that matches {icon_bundle}.name in the database. |
icon_bundle_disable | Disable the icon bundle that matches {icon_bundle}.name in the database. |
icon_bundle_enable | Enable the icon bundle that matches {icon_bundle}.name in the database. |
icon_bundle_get_theme | Helper function to return the proper theme. |
icon_bundle_get_title | Helper function to return the page title for bundles. |
icon_bundle_load | Load a specific bundle. |
icon_bundle_save | Save an icon bundle in the {icon_bundle} table. |
icon_hook_info | Implements hook_hook_info(). |
icon_library | Implements hook_library(). |
icon_providers | Returns information about all icon providers. |
icon_providers_support_import | Returns information about whether a provider supports importing. |
icon_provider_defaults | Default properties for a provider definition. |
icon_provider_load | Load a specific provider. |
icon_render_hooks | Returns information about icons render hooks. |
Constants
Name | Description |
---|---|
ICON_ADMIN_PATH |