styles.module 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. <?php
  2. /**
  3. * @file
  4. * Bundles similar display formatters together.
  5. */
  6. // A registry of variable_get defaults.
  7. include_once('includes/styles.variables.inc');
  8. // Include get_called_class() for PHP < 5.3.
  9. if(!function_exists('get_called_class')) {
  10. include_once('includes/php/get_called_class.inc');
  11. }
  12. /**
  13. * Implements hook_field_formatter_info().
  14. */
  15. function styles_field_formatter_info() {
  16. $info = array();
  17. foreach (styles_default_styles() as $field_type => $styles) {
  18. foreach ($styles['styles'] as $style) {
  19. $style_name = $style['name'];
  20. $info['styles_' . $field_type . '_' . $style_name] = array(
  21. 'label' => t('@field style: @style', array('@field' => ucfirst($field_type), '@style' => $style_name)),
  22. 'field types' => array($field_type),
  23. 'behaviors' => array(
  24. 'multiple values' => FIELD_BEHAVIOR_DEFAULT,
  25. ),
  26. 'theme' => array('function' => 'theme_styles_field_formatter')
  27. );
  28. }
  29. }
  30. return $info;
  31. }
  32. /**
  33. * Implements hook_field_formatter_view().
  34. */
  35. function styles_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  36. $element = array('#formatter' => $display['type']);
  37. foreach ($items as $delta => $item) {
  38. // @todo The variable name 'object' is misleading, but retained for
  39. // backwards compatibility until a broader refactoring of the Styles
  40. // module. For now, it's the $item array cast to an object. For File and
  41. // Image fields, this is a fully loaded file object, because
  42. // file_field_load() loads the referenced file and merges its properties
  43. // into $item, but for other field types, it may simply be raw field data.
  44. $element[$delta] = array('#markup' => theme('styles_field_formatter', array('element' => $element, 'object' => (object) $item, 'delta' => $delta, 'entity' => $entity)));
  45. }
  46. return $element;
  47. }
  48. /**
  49. * Implements hook_theme().
  50. */
  51. function styles_theme($existing, $type, $theme, $path) {
  52. return array(
  53. 'styles' => array(
  54. 'variables' => array('field_type' => NULL, 'style_name' => NULL, 'object' => NULL, 'instance' => NULL),
  55. 'template' => 'styles',
  56. 'path' => $path . '/themes',
  57. 'file' => 'styles.theme.inc',
  58. ),
  59. 'styles_field_formatter' => array(
  60. 'variables' => array('render element' => 'element', 'element' => NULL, 'object' => NULL),
  61. 'path' => $path . '/themes',
  62. 'file' => 'styles.theme.inc',
  63. ),
  64. );
  65. }
  66. /**
  67. * Return all available containers for a specific field type.
  68. *
  69. * Modules implementing this hook should supply an array for each field type
  70. * that it supports, with at least two keys: 'containers', containing an
  71. * associated array described below, and 'filter callback' => A function to call
  72. * with the field object to determine which container to implement.
  73. *
  74. * Each container under a field type should be an associative array with the
  75. * following keys:
  76. * 'class' => The class to instantiate when filtering to this container.
  77. * 'filter match' => (Optional) A value to pass to the filter callback
  78. * to match the field object against this container.
  79. *
  80. * Example implementation of hook_styles_default_containers():
  81. * array(
  82. * 'emvideo' => array(
  83. * 'filter callback' => 'my_styles_emvideo_filter',
  84. * 'containers' => array(
  85. * 'brightcove' => array(
  86. * 'class' => 'BrightcoveStyles',
  87. * 'filter match' => array('brightcove'),
  88. * ),
  89. * 'vimeo' => array(
  90. * 'class' => 'VimeoStyles',
  91. * 'filter match' => array('vimeo'),
  92. * ),
  93. * 'youtube' => array(
  94. * 'class' => 'YouTubeStyles',
  95. * 'filter match' => array('youtube', 'my_youtube'),
  96. * ),
  97. * ),
  98. * ),
  99. * );
  100. *
  101. * @param string $return_type
  102. * (Optional) The field type, such as file or nodereference.
  103. * @param boolean $reset
  104. * (Optional) If TRUE, then we reset the cache.
  105. */
  106. function styles_default_containers($return_type = NULL, $reset = FALSE) {
  107. $styles = &drupal_static(__FUNCTION__);
  108. // Grab from cache or build the array.
  109. if (!isset($styles) || $reset) {
  110. if (($cache = cache_get('styles_default_containers', 'cache_styles')) && !$reset) {
  111. $styles = $cache->data;
  112. }
  113. else {
  114. $styles = array();
  115. styles_module_load_all_includes();
  116. foreach (module_implements('styles_default_containers') as $module) {
  117. $module_styles = module_invoke($module, 'styles_default_containers');
  118. foreach ($module_styles as $field_type => $container) {
  119. $styles[$field_type] = isset($styles[$field_type]) ? $styles[$field_type] : array();
  120. // Pull out existing containers before the merge.
  121. $containers = isset($styles[$field_type]['containers']) ? $styles[$field_type]['containers'] : array();
  122. // Merge in the module defined containers.
  123. $styles[$field_type] = array_merge($styles[$field_type], $container);
  124. $styles[$field_type]['containers'] = isset($styles[$field_type]['containers']) ? $styles[$field_type]['containers'] : array();
  125. $styles[$field_type]['containers'] = array_merge($containers, $styles[$field_type]['containers']);
  126. foreach ($container['containers'] as $style_name => $style) {
  127. $style['name'] = $style_name;
  128. $style['module'] = $module;
  129. $style['storage'] = STYLES_STORAGE_DEFAULT;
  130. $styles[$field_type]['containers'][$style_name] = $style;
  131. }
  132. }
  133. }
  134. drupal_alter('styles_default_containers', $styles);
  135. cache_set('styles_default_containers', $styles, 'cache_styles');
  136. }
  137. }
  138. if (isset($return_type)) {
  139. return $styles[$return_type];
  140. }
  141. return $styles;
  142. }
  143. /**
  144. * Return all available styles for a specific field type.
  145. *
  146. * Each style under a field type should be an associative array with the
  147. * following optional keys:
  148. * 'description' => An untranslated human readable description for the style.
  149. * 'default theme' => The theme to call for display if there is no preset
  150. * returned when filtering the field.
  151. * 'default theme arguments' => Any arguments to pass after the first (of
  152. * the field's object itself).
  153. *
  154. * Example implementation of hook_styles_default_styles():
  155. * array(
  156. * 'nodereference' => array(
  157. * 'styles' => array(
  158. * 'thumbnail' => array(
  159. * 'description' => 'Representative thumbnails linking to the content page.',
  160. * 'default theme' => 'my_styles_default_thumbnail',
  161. * ),
  162. * 'small' => array(
  163. * 'description' => 'Small images linking to the content page.',
  164. * 'default theme' => 'my_styles_default_thumbnail',
  165. * ),
  166. * 'teaser' => array(
  167. * 'description' => 'A short summary of the content.',
  168. * 'default theme' => 'node_view',
  169. * 'default theme arguments' => array(TRUE),
  170. * ),
  171. * ),
  172. * ),
  173. * );
  174. *
  175. * This will create those styles, allowing
  176. *
  177. * @param string $field_type
  178. * (Optional) The field type, such as filefield or nodereference.
  179. * @param boolean $reset
  180. * (Optional) If TRUE, then we reset the cache.
  181. */
  182. function styles_default_styles($return_type = NULL, $reset = FALSE) {
  183. $styles = &drupal_static(__FUNCTION__);
  184. // Grab from cache or build the array.
  185. if (!isset($styles) || $reset) {
  186. if (($cache = cache_get('styles_default_styles', 'cache_styles')) && !$reset) {
  187. $styles = $cache->data;
  188. }
  189. else {
  190. $styles = array();
  191. styles_module_load_all_includes();
  192. foreach (module_implements('styles_default_styles') as $module) {
  193. $module_styles = module_invoke($module, 'styles_default_styles');
  194. foreach ($module_styles as $field_type => $container) {
  195. $styles[$field_type] = isset($styles[$field_type]) ? $styles[$field_type] : array();
  196. $containers = isset($styles[$field_type]['styles']) ? $styles[$field_type]['styles'] : array();
  197. $styles[$field_type] = array_merge($styles[$field_type], $container);
  198. $styles[$field_type]['styles'] = isset($styles[$field_type]['styles']) ? $styles[$field_type]['styles'] : array();
  199. $styles[$field_type]['styles'] = array_merge($containers, $styles[$field_type]['styles']);
  200. foreach ($container['styles'] as $style_name => $style) {
  201. $style['name'] = $style_name;
  202. $style['module'] = $module;
  203. $style['storage'] = STYLES_STORAGE_DEFAULT;
  204. $style['field_type'] = $field_type;
  205. $style['description'] = isset($style['description']) ? $style['description'] : '';
  206. $styles[$field_type]['styles'][$style_name] = $style;
  207. }
  208. }
  209. }
  210. // Add user defined & overridden styles next.
  211. $user_styles = db_select('styles', NULL, array('fetch' => PDO::FETCH_ASSOC))
  212. ->fields('styles')
  213. ->orderBy('name')
  214. ->execute()
  215. ->fetchAllAssoc('name', PDO::FETCH_ASSOC);
  216. foreach ($user_styles as $style_name => $style) {
  217. $field_type = $style['field_type'];
  218. $style['module'] = NULL;
  219. $style['storage'] = STYLES_STORAGE_NORMAL;
  220. if (isset($styles[$field_type]['styles'][$style_name]['module'])) {
  221. $style['module'] = $styles[$field_type]['styles'][$style_name]['module'];
  222. $style['storage'] = STYLES_STORAGE_OVERRIDE;
  223. }
  224. $styles[$field_type]['styles'][$style_name] = $style;
  225. }
  226. drupal_alter('styles_default_styles', $styles);
  227. cache_set('styles_default_styles', $styles, 'cache_styles');
  228. }
  229. }
  230. if (isset($return_type)) {
  231. return $styles[$return_type];
  232. }
  233. return $styles;
  234. }
  235. /**
  236. * Return all available presets for field type containers.
  237. *
  238. * Each container under a field type should be an associative array with the
  239. * following keys:
  240. * 'default preset' => The preset to select by default, which may be
  241. * overridden later.
  242. * 'presets' => An associative array keyed by the preset name, each with
  243. * an array of effects to be passed to the implementing class on display.
  244. *
  245. * Example implementation of hook_styles_default_presets():
  246. * array(
  247. * 'filefield' => array(
  248. * 'containers' => array(
  249. * 'imagefield' => array(
  250. * 'default preset' => 'imagecache_thumbnail_linked',
  251. * 'presets' => array(
  252. * 'imagecache_thumbnail_linked' => array(
  253. * 'title' => '[node-title]',
  254. * 'alt' => '[file-description]',
  255. * 'imagecache_preset' => 'thumbnail',
  256. * 'link' => '[node-path]',
  257. * ),
  258. * 'link_to_file' => array(
  259. * 'title' => '[file-title-raw]',
  260. * 'link' => '[file-path]',
  261. * ),
  262. * ),
  263. * ),
  264. * ),
  265. * );
  266. *
  267. * @param string $field_type
  268. * (Optional) The field type, such as filefield or nodereference.
  269. * @param boolean $reset
  270. * (Optional) If TRUE, then we reset the cache.
  271. */
  272. function styles_default_presets($return_type = NULL, $reset = FALSE) {
  273. $styles = &drupal_static(__FUNCTION__);
  274. // Grab from cache or build the array.
  275. if (!isset($styles) || $reset) {
  276. if (($cache = cache_get('styles_default_presets', 'cache_styles')) && !$reset) {
  277. $styles = $cache->data;
  278. }
  279. else {
  280. $styles = array();
  281. styles_module_load_all_includes();
  282. foreach (module_implements('styles_default_presets') as $module) {
  283. $module_styles = module_invoke($module, 'styles_default_presets');
  284. foreach ($module_styles as $field_type => $container) {
  285. $all_styles = styles_default_styles($field_type);
  286. $styles[$field_type] = isset($styles[$field_type]) ? $styles[$field_type] : array();
  287. $containers = isset($styles[$field_type]['containers']) ? $styles[$field_type]['containers'] : array();
  288. $styles[$field_type] = array_merge($styles[$field_type], $container);
  289. $styles[$field_type]['containers'] = isset($styles[$field_type]['containers']) ? $styles[$field_type]['containers'] : array();
  290. $styles[$field_type]['containers'] = array_merge($containers, $styles[$field_type]['containers']);
  291. foreach ($container['containers'] as $style_name => $style) {
  292. $style['name'] = $style_name;
  293. $style['module'] = $module;
  294. $style['storage'] = STYLES_STORAGE_DEFAULT;
  295. $style['styles'] = isset($style['styles']) ? $style['styles'] : array();
  296. $default_preset = isset($style['default preset']) ? $style['default preset'] : '';
  297. foreach ($all_styles['styles'] as $container_style_name => $container_style) {
  298. if (!isset($style['styles'][$container_style_name])) {
  299. $style['styles'][$container_style_name] = array(
  300. 'default preset' => $default_preset,
  301. );
  302. }
  303. }
  304. $styles[$field_type]['containers'][$style_name] = $style;
  305. }
  306. }
  307. }
  308. // Add user-defined and overridden presets.
  309. $query = db_select('styles_preset_instances', 'spi');
  310. $query->join('styles', 's', 's.sid = spi.sid');
  311. $query->join('styles_presets', 'p', 'p.pid = spi.pid');
  312. $query->addField('spi', 'sid');
  313. $query->addField('spi', 'pid');
  314. $query->addField('s', 'name', 'style_name');
  315. $query->addField('p', 'name', 'preset_name');
  316. $query->addField('p', 'field_type', 'field_type');
  317. $query->addField('p', 'container_name', 'container_name');
  318. $user_styles = $query->execute();
  319. foreach ($user_styles as $style) {
  320. if (isset($styles[$style->field_type]) && isset($styles[$style->field_type]['containers'][$style->container_name]) && isset($styles[$style->field_type]['containers'][$style->container_name]['presets'][$style->preset_name]) && isset($styles[$style->field_type]['containers'][$style->container_name]['styles'][$style->style_name])) {
  321. $styles[$style->field_type]['containers'][$style->container_name]['styles'][$style->style_name]['preset'] = $style->preset_name;
  322. }
  323. }
  324. drupal_alter('styles_default_presets', $styles);
  325. cache_set('styles_default_presets', $styles, 'cache_styles');
  326. }
  327. }
  328. if (isset($return_type)) {
  329. return $styles[$return_type];
  330. }
  331. return $styles;
  332. }
  333. /**
  334. * Load all registered module/styles.inc and modules/includes/styles.inc files.
  335. */
  336. function styles_module_load_all_includes() {
  337. foreach (styles_get_registered_classes() as $class) {
  338. module_load_include('inc', $class['module'], 'styles');
  339. module_load_include('inc', $class['module'], $class['module'] .'/styles');
  340. module_load_include('inc', $class['module'], 'includes/'. $class['module'] .'.styles');
  341. module_load_include('inc', $class['module'], 'includes/styles/'. $class['module'] .'.styles');
  342. }
  343. }
  344. /**
  345. * Builds a registry of Style classes.
  346. *
  347. * Each module supporting a Style will need to implement
  348. * hook_styles_register, which will need to return an associated array keyed by
  349. * the style class name, with an array containing the following key => value
  350. * pairs:
  351. * 'field_types' => An array of field types to apply this style to.
  352. * The following key => value pairs are optional, which will otherwise be
  353. * automatically derived:
  354. * 'name' => The human-readable name of the style.
  355. * 'description' => A description of the style.
  356. * 'path' => The path where the class file resides.
  357. * 'file' => The file containing the class definition.
  358. * 'module' => The module defining the class.
  359. * The following key => value pair will be automatically set to the association
  360. * and cannot be overridden:
  361. * 'class_name' => The actual name of the class.
  362. *
  363. * @param string $style
  364. * (Optional) The style of the specific class registration to return.
  365. * @param boolean $reset
  366. * (Optional) If TRUE, then reset the registration.
  367. * @return array
  368. * If $style is specified, then return only the specified class definition, or
  369. * NULL if there is no such registered class. Otherwise, return the entire
  370. * class definition registry.
  371. */
  372. function styles_get_registered_classes($return_style = NULL, $reset = FALSE) {
  373. $registered_classes = &drupal_static(__FUNCTION__);
  374. if ($reset || !isset($registered_classes)) {
  375. $registered_classes = array();
  376. // Build our media object class registry.
  377. foreach (module_implements('styles_register') as $module) {
  378. foreach (module_invoke($module, 'styles_register') as $style => $class) {
  379. $registered_classes[$style] = is_array($class) ? $class : array();
  380. $registered_classes[$style]['class_name'] = $style;
  381. if (!isset($registered_classes[$style]['name'])) {
  382. $registered_classes[$style]['name'] = t($style);
  383. }
  384. if (!isset($registered_classes[$style]['description'])) {
  385. $registered_classes[$style]['description'] = t('Class definition for @style.', array('@style' => $style));
  386. }
  387. if (!isset($registered_classes[$style]['path'])) {
  388. $registered_classes[$style]['path'] = drupal_get_path('module', $module);
  389. }
  390. if (!isset($registered_classes[$style]['file'])) {
  391. $registered_classes[$style]['file'] = $style .'.inc';
  392. }
  393. if (!isset($registered_classes[$style]['module'])) {
  394. $registered_classes[$style]['module'] = $module;
  395. }
  396. }
  397. }
  398. }
  399. if (isset($return_style)) {
  400. return $registered_classes[$style];
  401. }
  402. return $registered_classes;
  403. }
  404. /**
  405. * Implementation of hook_init().
  406. */
  407. function styles_init() {
  408. // Load all registered class definitions.
  409. styles_get_registered_classes();
  410. }
  411. /**
  412. * Return the registered Styles class definition specified by name.
  413. *
  414. * @param string $class_name
  415. * (Optional) The name of the class definition to return. If NULL, then return
  416. * all class definitions.
  417. * @param boolean $reset
  418. * (Optional) If TRUE, then reset the static array of class definitions.
  419. * @return mixed
  420. * Either the specified Styles class definition, or all defined definitions
  421. * if $class_name is NULL.
  422. */
  423. function styles_get_styles_class_by_class_name($class_name = NULL, $reset = FALSE) {
  424. $classes = &drupal_static(__FUNCTION__);
  425. if (!isset($classes) || $reset) {
  426. $classes = array();
  427. $registered_classes = styles_get_registered_classes();
  428. foreach ($registered_classes as $scheme => $class) {
  429. $classes[$class['class_name']] = $class;
  430. }
  431. }
  432. if (isset($class_name) && isset($classes[$class_name])) {
  433. return $classes[$class_name];
  434. }
  435. else if (!isset($class_name)) {
  436. return $classes;
  437. }
  438. }
  439. function styles_instance($variables) {
  440. static $id = 0;
  441. $variables['id'] = $id++;
  442. $field_type = $variables['field_type'];
  443. $style_name = $variables['style_name'];
  444. $object = $variables['object'];
  445. // Grab the containers for this field type.
  446. $containers = styles_default_containers($field_type);
  447. $variables['containers'] = $containers['containers'];
  448. $callback = $containers['filter callback'];
  449. // Find the correct container for this field type's styles.
  450. if (function_exists($callback)) {
  451. $container = call_user_func_array($callback, array($variables['object'], $variables));
  452. $variables['container'] = $container && isset($variables['containers'][$container]) ? $variables['containers'][$container] : array();
  453. }
  454. else {
  455. $variables['container'] = array();
  456. }
  457. // Grab the styles.
  458. $styles = styles_default_styles($field_type);
  459. $variables['styles'] = $styles['styles'];
  460. $variables['style'] = $style_name && isset($variables['styles'][$style_name]) ? $variables['styles'][$style_name] : array();
  461. // Grab the presets.
  462. $presets = styles_default_presets($field_type);
  463. $variables['presets'] = $container && isset($presets['containers'][$container]) ? $presets['containers'][$container] : array();
  464. $variables['preset_style'] = isset($variables['presets']['styles'][$style_name]) ? $variables['presets']['styles'][$style_name] : array();
  465. $variables['default preset'] = (isset($variables['preset_style']['default preset']) ? $variables['preset_style']['default preset'] : (isset($variables['presets']['default preset']) ? $variables['presets']['default preset'] : ''));
  466. $variables['preset'] = isset($variables['preset_style']['selected preset']) ? $variables['preset_style']['selected preset'] : (isset($variables['preset_style']['preset']) ? $variables['preset_style']['preset'] : $variables['default preset']);
  467. $variables['effects'] = ($variables['preset'] !== '') && isset($variables['presets']['presets'][$variables['preset']]) ? $variables['presets']['presets'][$variables['preset']] : array();
  468. // Instantiate the class and render the output.
  469. if ($class = $variables['container']['class']) {
  470. return new $variables['container']['class']($variables['object'], $variables['effects'], $variables);
  471. }
  472. }
  473. /**
  474. * Load a style by style name or ID. May be used as a loader for menu items.
  475. *
  476. * @param $field_type
  477. * The field type for this style.
  478. * @param $name
  479. * The name of the style.
  480. * @param $sid
  481. * Optional. The numeric id of a style if the name is not known.
  482. * @param $include
  483. * If set, this loader will restrict to a specific type of style, may be
  484. * one of the defined style storage constants.
  485. * @return
  486. * A style array containing the following keys:
  487. * - "sid": The unique style ID.
  488. * - "name": The unique style name.
  489. * If the style name or ID is not valid, an empty array is returned.
  490. */
  491. function styles_style_load($field_type, $name = NULL, $sid = NULL, $include = NULL) {
  492. $styles = styles_default_styles($field_type);
  493. // If retrieving by name.
  494. if (isset($name) && isset($styles['styles'][$name])) {
  495. $style = $styles['styles'][$name];
  496. }
  497. // If retrieving by style id.
  498. if (!isset($name) && isset($sid)) {
  499. foreach ($styles['styles'] as $name => $database_style) {
  500. if (isset($database_style['sid']) && $database_style['sid'] == $sid) {
  501. $style = $database_style;
  502. break;
  503. }
  504. }
  505. }
  506. // Restrict to the specific type of flag. This bitwise operation basically
  507. // states "if the storage is X, then allow".
  508. if (isset($style) && (!isset($include) || ($style['storage'] & (int) $include))) {
  509. return $style;
  510. }
  511. // Otherwise the style was not found.
  512. return array();
  513. }
  514. /**
  515. * Save a style/preset instance.
  516. *
  517. * @param string $field_type
  518. * The field type of the style/preset to save.
  519. * @param string $container_name
  520. * The container.
  521. * @param string $style_name
  522. * The name of the style to save to.
  523. * @param string $preset_name
  524. * The name of the preset.
  525. * @param boolean $delete_only
  526. * If TRUE, then we delete only, rather than saving.
  527. *
  528. * @return boolean
  529. * Return TRUE, or FALSE if the save was not successful.
  530. *
  531. * @TODO: Throw an error instead?
  532. */
  533. function styles_style_save_preset($field_type, $container_name, $style_name, $preset_name, $delete_only = FALSE) {
  534. $query = db_select('styles_presets', 'p');
  535. $query->addField('p', 'pid');
  536. $query->condition('p.name', $preset_name);
  537. $query->condition('p.field_type', $field_type);
  538. $query->condition('p.container_name', $container_name);
  539. $result = $query->execute();
  540. foreach ($result as $preset) {
  541. $preset = (array)$preset;
  542. }
  543. if (empty($preset)) {
  544. $preset = array(
  545. 'name' => $preset_name,
  546. 'field_type' => $field_type,
  547. 'container_name' => $container_name
  548. );
  549. drupal_write_record('styles_presets', $preset);
  550. }
  551. $styles = styles_default_styles($field_type);
  552. if (!isset($styles['styles'][$style_name])) {
  553. return FALSE;
  554. }
  555. else {
  556. $style = $styles['styles'][$style_name];
  557. }
  558. if (!isset($style['sid'])) {
  559. return FALSE;
  560. }
  561. // Delete old style/preset instances for this container.
  562. // Unfortunately, we can't use joins with DeleteQuery. See following comment.
  563. db_query("DELETE FROM {styles_preset_instances} WHERE {styles_preset_instances}.sid = :sid AND EXISTS (SELECT * FROM {styles} s, {styles_presets} p WHERE s.sid = {styles_preset_instances}.sid AND p.pid = {styles_preset_instances}.pid AND s.field_type = p.field_type AND p.container_name = :container_name);", array(':sid' => $style['sid'], ':container_name' => $container_name));
  564. // @TODO: See if there's a way to implement something like the following:
  565. // db_delete('styles_preset_instances')
  566. // ->join('styles', 's')
  567. // ->join('styles_presets', 'p')
  568. // ->condition('s.sid', 'styles_preset_instances.sid')
  569. // ->condition('styles_preset_instances.pid', 'p.pid')
  570. // ->condition('s.field_type', 'p.field_type')
  571. // ->condition('styles_preset_instances.sid', $style['sid'])
  572. // ->condition('p.container_name', $container_name)
  573. // ->execute();
  574. // Write the revised style for an update, unless we're only deleting the old.
  575. if (!$delete_only) {
  576. $record = array(
  577. 'sid' => $style['sid'],
  578. 'pid' => $preset['pid'],
  579. );
  580. drupal_write_record('styles_preset_instances', $record);
  581. }
  582. // Let other modules update as necessary on save.
  583. module_invoke_all('styles_preset_save', $field_type, $container_name, $style_name, $preset_name, $delete_only);
  584. // Clear all caches and flush.
  585. styles_style_flush($style);
  586. return TRUE;
  587. }
  588. function styles_style_delete($field_type, $style_name) {
  589. // Let other modules update as necessary on deletion.
  590. module_invoke_all('styles_delete', $field_type, $style_name);
  591. $sid = db_select('styles', 's')
  592. ->fields('s', array('sid'))
  593. ->condition('name', $style_name)
  594. ->condition('field_type', $field_type)
  595. ->execute()
  596. ->fetchField();
  597. if ($sid) {
  598. db_delete('styles_preset_instances')
  599. ->condition('sid', $sid)
  600. ->execute();
  601. db_delete('styles')
  602. ->condition('sid', $sid)
  603. ->execute();
  604. }
  605. // Clear all caches and flush.
  606. styles_style_flush();
  607. }
  608. function styles_style_save(&$style) {
  609. if (isset($style['sid']) && is_numeric($style['sid'])) {
  610. // Load the existing style to make sure we account for renamed styles.
  611. $old_style = styles_style_load($style['field_type'], NULL, $style['sid']);
  612. styles_style_flush($old_style);
  613. drupal_write_record('styles', $style, 'sid');
  614. if ($old_style['name'] != $style['name']) {
  615. $style['old_name'] = $old_style['name'];
  616. }
  617. }
  618. else if (isset($style['name'])) {
  619. // Load the existing style to make sure we account for renamed styles.
  620. $old_style = styles_style_load($style['field_type'], $style['name']);
  621. styles_style_flush($old_style);
  622. if (isset($old_style['sid'])) {
  623. $style['sid'] = $old_style['sid'];
  624. drupal_write_record('styles', $style, 'sid');
  625. }
  626. else {
  627. drupal_write_record('styles', $style);
  628. $style['is_new'] = TRUE;
  629. }
  630. if (isset($old_style['name'])) {
  631. $style['old_name'] = $old_style['name'];
  632. }
  633. }
  634. else {
  635. drupal_write_record('styles', $style);
  636. $style['is_new'] = TRUE;
  637. }
  638. // Let other modules update as necessary on save.
  639. module_invoke_all('styles_style_save', $style);
  640. // Clear all caches and flush.
  641. styles_style_flush($style);
  642. return $style;
  643. }
  644. /**
  645. * Flush cached defaults for a style.
  646. *
  647. * @param $style
  648. * A style array.
  649. */
  650. function styles_style_flush($style = NULL) {
  651. // Clear style and preset caches.
  652. cache_clear_all('styles_default_styles', 'cache_styles');
  653. cache_clear_all('styles_default_presets', 'cache_styles');
  654. cache_clear_all('styles_default_containers', 'cache_styles');
  655. drupal_static_reset('styles_default_styles');
  656. drupal_static_reset('styles_default_presets');
  657. drupal_static_reset('styles_default_containers');
  658. drupal_static_reset('styles_get_registered_classes');
  659. // Let other modules update as necessary on flush.
  660. module_invoke_all('styles_style_flush', $style);
  661. // Clear field caches so that formatters may be added for this style.
  662. field_info_cache_clear();
  663. drupal_theme_rebuild();
  664. // Clear page caches when flushing.
  665. if (module_exists('block')) {
  666. cache_clear_all('*', 'cache_block', TRUE);
  667. }
  668. cache_clear_all('*', 'cache_page', TRUE);
  669. }
  670. /**
  671. * Implementation of hook_flush_caches().
  672. */
  673. function styles_flush_caches() {
  674. return array('cache_styles');
  675. }