AbstractProject.php

AbstractProject

Namespace

Drupal\ooe\Project

File

lib/Drupal/ooe/Project/AbstractProject.php
View source
  1. <?php
  2. /**
  3. * @file
  4. * AbstractProject
  5. */
  6. namespace Drupal\ooe\Project;
  7. use Drupal\ooe\Module\DefaultModuleHelper;
  8. use Drupal\ooe\Factory\IFactory;
  9. use Drupal\ooe\Layout\IRegion;
  10. use Drupal\ooe\Theme\BartikRegions;
  11. use Drupal\ooe\Block\BlockCacheKind;
  12. use Drupal\ooe\Block\BlockStatusKind;
  13. use Drupal\ooe\Menu\IMenuItem;
  14. use Drupal\ooe\Block\IBlock;
  15. /**
  16. * A useful starting point for creating a "project" within a module.
  17. *
  18. * UML:
  19. * @link http://drupal7demo.webel.com.au/node/1565 AbstractProject @endlink
  20. *
  21. * @author darrenkelly
  22. */
  23. abstract class AbstractProject extends DefaultModuleHelper implements IProject {
  24. /**
  25. * A Drupal access arguments array.
  26. *
  27. * @var array
  28. */
  29. private $accessArguments;
  30. /**
  31. * By default there is no access restriction ! Inject via constructor (only).
  32. *
  33. * @todo Sensible default access (currently no restriction)
  34. *
  35. * Subclasses may reimplement this to provide more specific access arguments.
  36. *
  37. * @return array
  38. * An empty Drupal access arguments array.
  39. */
  40. protected function accessArguments() {
  41. if (empty($this->accessArguments)) {
  42. $this->accessArguments = array();
  43. // @todo: default no access restriction.
  44. // @todo consider via myAccessArguments().
  45. }
  46. return $this->accessArguments;
  47. }
  48. /**
  49. * A theme region for the default block.
  50. *
  51. * @var \Drupal\ooe\Layout\IRegion
  52. */
  53. private $blockRegion;
  54. /**
  55. * If not injected on construction, defaults to the Bartik theme 1st sidebar.
  56. *
  57. * @todo Ensure safe default
  58. *
  59. * @return \Drupal\ooe\Layout\IRegion
  60. * The constructor-injected, else lazily created and configured,
  61. * theme region.
  62. */
  63. protected function blockRegion() {
  64. if (empty($this->blockRegion)) {
  65. // Create:
  66. $this->blockRegion = $this->factory()->newRegion(BartikRegions::SIDEBAR_FIRST);
  67. // @todo sensible default region
  68. // Configure:
  69. // $this->blockRegion->set?
  70. }
  71. return $this->blockRegion;
  72. }
  73. /**
  74. * Constructor.
  75. *
  76. * @param string $module
  77. * The machine name of the module
  78. *
  79. * @param \Drupal\ooe\Factory\IFactory $factory
  80. * Optional factory; if none given or null
  81. * a @link DefaultFactory @endlink will be used.
  82. *
  83. * @param array $accessArguments
  84. * Optional Drupal access arguments array.
  85. *
  86. * @param \Drupal\ooe\Layout\IRegion $blockRegion
  87. * Optional theme layout region for the default block.
  88. */
  89. public function __construct(
  90. $module, IFactory $factory = NULL, array $accessArguments = NULL, IRegion $blockRegion = NULL) {
  91. parent::__construct($module, $factory);
  92. if (!empty($accessArguments)) {
  93. $this->accessArguments = $accessArguments;
  94. }
  95. if (!empty($blockRegion)) {
  96. $this->blockRegion = $blockRegion;
  97. }
  98. }
  99. /**
  100. * By default does nothing; reimplement to add additional menu items.
  101. *
  102. * Note the main menu item is always already added.
  103. */
  104. protected function myFillMenuItemSet() {
  105. }
  106. /**
  107. * A set of menu items.
  108. *
  109. * @var \Drupal\ooe\Menu\IMenuItemSet
  110. */
  111. private $menuItemSet;
  112. /**
  113. * Lazily creates and configures a set/group of menu items.
  114. *
  115. * It always already includes the primary menu item !
  116. *
  117. * Additional menu items will be automatically added via
  118. * @link AbstractProject::myFillmenItemSet @endlink().
  119. *
  120. * @return \Drupal\ooe\Menu\IMenuItemSet
  121. * A lazily created and configured set of menu items.
  122. */
  123. final protected function menuItemSet() {
  124. if (empty($this->menuItemSet)) {
  125. // Create:
  126. $this->menuItemSet = $this->factory()->newMenuItemSet();
  127. // Configure:
  128. $this->menuItemSet->addMenuItem($this->getMenuItem());
  129. // Always at least !
  130. $this->myFillMenuItemSet();
  131. }
  132. return $this->menuItemSet;
  133. }
  134. /**
  135. * Adds a menu item to the menu item set of this.
  136. *
  137. * @param \Drupal\ooe\Menu\IMenuItem $menuItem
  138. * A menu item to add to the menu item set/group.
  139. *
  140. * @return \Drupal\ooe\Module\IProject
  141. * This.
  142. */
  143. final protected function addMenuItem(IMenuItem $menuItem) {
  144. $this->menuItemSet()->addMenuItem($menuItem);
  145. return $this;
  146. }
  147. /**
  148. * The set of menu items handled by this.
  149. *
  150. * @return \Drupal\ooe\Menu\IMenuItem[]
  151. * The array of menu items handled by this.
  152. */
  153. public function getMenuItems() {
  154. return $this->menuItemSet()->getMenuItems();
  155. }
  156. /**
  157. * The (default) block of this project.
  158. *
  159. * Need not be used, need not be made visible.
  160. *
  161. * @var \Drupal\ooe\Block\IBlock
  162. */
  163. private $block;
  164. /**
  165. * Lazily creates a demo block.
  166. *
  167. * The ultimate block implementation chosen
  168. * will depend on @link AbstractProject::myBlock @endlink.
  169. *
  170. * This strategy also enables one to separate configurations
  171. * common to all projects from those specific to a specific project.
  172. *
  173. * @return \Drupal\ooe\Block\IBlock
  174. * A demo block.
  175. */
  176. public function getBlock() {
  177. if (empty($this->block)) {
  178. $this->block = $this->myBlock();
  179. }
  180. return $this->block;
  181. }
  182. /**
  183. * A helper method to assist in implementing @link AbstractBlock::myBlock().
  184. *
  185. * There is no obligation to use it, however it provides
  186. * a sensible default configuration, including enabling the block
  187. * and assigning it to the default block region managed by this.
  188. *
  189. * Please note that $deltaSuffix is NOT the entire block delta identifier,
  190. * it is only the suffix that will be appended to the module machine name
  191. * following by an underscore '_'.
  192. *
  193. * @param string $deltaSuffix
  194. * Will always be appended to 'MYMODULE_' as the block delta identifier.
  195. * @param string $info
  196. * Translated ! Will optionally be prepended with the module display name.
  197. *
  198. * @return \Drupal\ooe\Block\IBlock
  199. * A new configured block with useful defaults.
  200. */
  201. protected function newBlock(
  202. $deltaSuffix, $info
  203. ) {
  204. $fullInfo = $this->doPrefixBlockInfo ?
  205. t('!module-display-name: !info',
  206. array(
  207. '!module-display-name' => $this->getModuleDisplayName(),
  208. '!info' => $info,
  209. )) : $info;
  210. return $this->block = $this->factory()->newBlock(
  211. $this->getModule() . "_$deltaSuffix", // POLICY!
  212. $fullInfo
  213. )
  214. ->setCache(BlockCacheKind::CACHE_PER_ROLE)
  215. ->setStatus(BlockStatusKind::ENABLED)
  216. ->setRegion($this->blockRegion());
  217. // Never null !
  218. }
  219. /**
  220. * If TRUE the block info will be automatically prefixed
  221. * with the module display name followed by ': '
  222. *
  223. * @var bool
  224. */
  225. private $doPrefixBlockInfo = TRUE;
  226. /**
  227. * Sets whether the block info will be automatically prefixed.
  228. *
  229. * Sets whether the block info will be automatically prefixed
  230. * with the module display name followed by ': ",
  231. *
  232. * @param bool $doPrefixBlockInfo
  233. * If TRUE the block info will be automatically prefixed
  234. * with the module display name followed by ': '.
  235. *
  236. * @return IProject
  237. * This.
  238. */
  239. public function setDoPrefixBlockInfo($doPrefixBlockInfo) {
  240. $this->doPrefixBlockInfo = $doPrefixBlockInfo;
  241. return $this;
  242. }
  243. /**
  244. * Whether the menu titles will be automatically prefixed.
  245. *
  246. * Whether the menu titles will be automatically prefixed
  247. * with the module display name followed by ': ".
  248. *
  249. * @return bool
  250. * Whether the menu titles will be automatically
  251. * prefixed with the module display name followed by ': ".
  252. */
  253. public function isDoPrefixMenuTitles() {
  254. return $this->doPrefixMenuTitles;
  255. }
  256. /**
  257. * Whether the block info will be automatically prefixed.
  258. *
  259. * Whether the block info will be automatically prefixed
  260. * with the module display name followed by ': ".
  261. *
  262. * @return bool
  263. * Whether the block info will be automatically prefixed
  264. * with the module display name followed by ': ".
  265. */
  266. public function isDoPrefixBlockInfo() {
  267. return $this->doPrefixBlockInfo;
  268. }
  269. /**
  270. * Whether the menu paths will be automatically prefixed.
  271. *
  272. * Whether the menu paths will be automatically prefixed
  273. * with the module machine name followed by ': ".
  274. *
  275. * @return bool
  276. * Whether the menu paths will be automatically prefixed
  277. * with the module machine name followed by ': ".
  278. */
  279. public function isDoPrefixMenuPaths() {
  280. return $this->doPrefixMenuPaths;
  281. }
  282. /**
  283. * Implement to return a new configured block.
  284. *
  285. * This is deliberately chosen to be abstract
  286. * to force implementations of @link IProject @endlink
  287. * to choose and configure a specific implementation.
  288. *
  289. * The term 'hook' is massively overloaded in software engineering.
  290. * This is a "hook" in a sense slightly different from the Drupal
  291. * hook mechanism. This stratagy, although it might seem like overkill
  292. * for the simplest project, is extremely powerful and is used often
  293. * in the OOE system. It enables a clean separation of configuration
  294. * specific to all projects from those specific to a given project.
  295. *
  296. * @return \Drupal\ooe\Block\IBlock
  297. * A block specific to a project.
  298. */
  299. abstract protected function myBlock();
  300. /**
  301. * A (default) block view for a project.
  302. *
  303. * It is not assumed
  304. * that a block (and block view) is needed or even visible for a
  305. * given project within a module, so in many cases a
  306. * @link StubBlockView @endlink
  307. * is sufficient.
  308. *
  309. * Remember, there is no obligation to use an @link IProject @endlink
  310. * at all, it is merely a useful starting point that covers many cases.
  311. *
  312. * @var \Drupal\ooe\Block\IBlockView
  313. */
  314. private $blockView;
  315. /**
  316. * A (default) block view for a project.
  317. *
  318. * It is not assumed
  319. * that a block is needed or even visible for a given project,
  320. * so in many cases a @link StubBlockView @endlink is sufficient.
  321. *
  322. * The block view chosen will ultimately depend on
  323. * @link AbstractProject::myBlockView @endlink(IBlock)
  324. * and it will always be bound to the
  325. * @link AbstractProject::$block @endlink.
  326. *
  327. * @return \Drupal\ooe\Block\IBlockView
  328. * A lazily created and configured block view.
  329. */
  330. public function getBlockView() {
  331. if (empty($this->blockView)) {
  332. $this->blockView = $this->myBlockView($this->getBlock());
  333. }
  334. return $this->blockView;
  335. }
  336. /**
  337. * Implement to return a (usually new) configured block view.
  338. *
  339. * @param \Drupal\ooe\Block\IBlock $block
  340. * The primary block for which this must create a new block view.
  341. *
  342. * @return \Drupal\ooe\Block\IBlockView
  343. * A configured block view.
  344. */
  345. abstract protected function myBlockView(IBlock $block);
  346. /**
  347. * The primary menu item of this.
  348. *
  349. * @var \Drupal\ooe\Menu\IMenuItem
  350. */
  351. private $menuItem;
  352. /**
  353. * May be overridden to return a more specialised primary menu item.
  354. *
  355. * @return \Drupal\ooe\Menu\IMenuItem
  356. * A lazily created and configured menu item.
  357. */
  358. public function getMenuItem() {
  359. if (empty($this->menuItem)) {
  360. $this->menuItem = $this->myMenuItem();
  361. //dpm($this->menuItem->getPath());//DEBUG
  362. //dpm($this->accessArguments(),$this->accessArguments());//DEBUG
  363. $this->menuItem->setAccessArguments($this->accessArguments());
  364. //$this->menuItem->forceAccessCallbackTRUE();
  365. // Concern: setting the access arguments here
  366. // overrides any set in the myMenuItem().
  367. // Consider myAccessArguments().
  368. }
  369. return $this->menuItem;
  370. }
  371. /**
  372. * If TRUE menu paths will be automatically prefixed
  373. * with the module machine name followed by '/'
  374. *
  375. * @var bool
  376. */
  377. private $doPrefixMenuPaths = FALSE;
  378. /**
  379. * Sets whether the menu paths will be automatically prefixed.
  380. *
  381. * Sets whether the menu paths will be automatically
  382. * prefixed with the module machine name followed by ': ",
  383. *
  384. * @param bool $doPrefixMenuPaths
  385. * If TRUE menu paths will be automatically prefixed
  386. * with the module machine name followed by '/'.
  387. *
  388. * @return IProject
  389. * This.
  390. */
  391. public function setDoPrefixMenuPaths($doPrefixMenuPaths) {
  392. $this->doPrefixMenuPaths = $doPrefixMenuPaths;
  393. return $this;
  394. }
  395. /**
  396. * If TRUE menu title will be automatically prefixed
  397. * with the module display name followed by ': ".
  398. *
  399. * @var bool
  400. */
  401. private $doPrefixMenuTitles = TRUE;
  402. /**
  403. * Sets whether the menu titles will be automatically prefixed.
  404. *
  405. * Sets whether the menu titles will be automatically prefixed
  406. * with the module display name followed by ': ",
  407. *
  408. * @param bool $doPrefixMenuTitles
  409. * If TRUE menu titles will be automatically prefixed
  410. * with the module display name followed by ': ".
  411. *
  412. * @return IProject
  413. * This.
  414. */
  415. public function setDoPrefixMenuTitles($doPrefixMenuTitles) {
  416. $this->doPrefixMenuTitles = $doPrefixMenuTitles;
  417. return $this;
  418. }
  419. /**
  420. * Creates a new basic menu item with an explicit .module file callback.
  421. *
  422. * Applies any access arguments.
  423. *
  424. * It is here to help one implement myMenuItem(); it has sensible defaults
  425. * that one can further configure using the return IMenuItem.
  426. *
  427. * The top-level callback must be a function in the .module file !
  428. *
  429. * This method is only here to show you the "old" Drupal7 way
  430. * and to support some of the simpler demo projects here such as
  431. * @end CurrentPosts @endlink.
  432. *
  433. * (You SHOULD when working with OOE always prefer where possible extending
  434. * an @link AbstractControlledProject @endlink which offers
  435. * an @link IPageMenuItem @endlink with an @link IPageController @endlink !.)
  436. *
  437. * You are free to use any valid menu $path, however
  438. * it is a good idea to include the module machine name in the
  439. * given $path or to switch on the option
  440. * @link AbstractProject::$doPrefixMenuPaths @endlink
  441. * to automatically prefix it with the module machine name and '/'.
  442. *
  443. * Please note however that parameter $pageCallbackSuffix is always appended
  444. * to the module machine name in lower case prefixed AND followed by '_'
  445. * so that "uncontrolled" module file callback function conventions are met.
  446. *
  447. * When using .module level callbacks (which with OOE you need no longer do)
  448. * please always prefix your module callback functions with '_MYMODULE_' !
  449. * The initial underscore helps to distinguish
  450. * custom callbacks from Drupal hooks and handlers.
  451. *
  452. * Example: to create a callback to .module file
  453. * _ooe_page_callback() where 'ooe' is the module:
  454. *
  455. * $pageCallbackSuffix='page_callback'
  456. *
  457. * @param string $title
  458. * The title of the menu item (optionally automatically
  459. * prepended with the module display name and ': ').
  460. * @param string $path
  461. * The menu path (optionally automatically prepended
  462. * with the module machine name followed by '/'.
  463. * @param string $pageCallbackSuffix
  464. * Always only the "tail" of a .module callback function
  465. * as in 'mycallback' in '_MYMODULE_mycallback()'.
  466. *
  467. * @return \Drupal\ooe\Menu\IMenuItem
  468. * A new configured menu item.
  469. */
  470. protected function newMenuItem($title, $path, $pageCallbackSuffix) {
  471. $fullTitle = $this->doPrefixMenuTitles ?
  472. $this->getModuleDisplayName() . ": $title" : $title;
  473. $fullPath = $this->doPrefixMenuPaths ?
  474. $this->getModule() . "/$path" : $path;
  475. return $this->factory()->newMenuItem(
  476. $fullTitle, $fullPath
  477. )->setPageCallback('_' . $this->getModule() . '_' . $pageCallbackSuffix)
  478. ->setAccessArguments($this->accessArguments());
  479. //->setTypeNormal(true);// Redundant, default.
  480. }
  481. /**
  482. * Concrete subclasses must implement this to return a new menu item.
  483. *
  484. * Concrete subclasses must implement this to return a new,
  485. * configured, basic (uncontrolled)
  486. * @IMenuItem or any other subclass kind of menu item
  487. * such as a controlled @IPageMenuItem.
  488. *
  489. * @return \Drupal\ooe\Menu\IMenuItem
  490. * Creates and configures a new menu item.
  491. */
  492. abstract protected function myMenuItem();
  493. }

Classes

Namesort descending Description
AbstractProject A useful starting point for creating a "project" within a module.