View.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. <?php
  2. /**
  3. *
  4. * Cube Framework $Id$ wjGj3bGJdRKfONM6h2P+182eI09uPFKTK7vg7mxxK9w=
  5. *
  6. * @link http://codecu.be/framework
  7. * @copyright Copyright (c) 2017 CodeCube SRL
  8. * @license http://codecu.be/framework/license Commercial License
  9. *
  10. * @version 1.10 [rev.1.10.01]
  11. */
  12. /**
  13. * view object
  14. */
  15. namespace Cube;
  16. use Cube\View\Helper\HelperInterface,
  17. Cube\Loader\Autoloader;
  18. class View
  19. {
  20. const DIR_SEPARATOR = '/';
  21. const URI_DELIMITER = '/';
  22. const FILES_EXTENSION = '.phtml';
  23. const VIEWS_FOLDER = 'view';
  24. /**
  25. *
  26. * the location of the layout file to be used
  27. *
  28. * @var string
  29. */
  30. protected $_layout;
  31. /**
  32. *
  33. * location where to check for layout files
  34. *
  35. * @var string
  36. */
  37. protected $_layoutsPath;
  38. /**
  39. *
  40. * location where to check for view files
  41. *
  42. * @var string
  43. */
  44. protected $_viewsPath;
  45. /**
  46. *
  47. * custom file name to be used
  48. * if not set, the default name generated for an action will be used
  49. *
  50. * @var string
  51. */
  52. protected $_viewFileName;
  53. /**
  54. *
  55. * the relative base url of the application
  56. *
  57. * @var string
  58. */
  59. public $baseUrl;
  60. /**
  61. *
  62. * the variable that will display the views in the layout file
  63. *
  64. * @var array
  65. */
  66. protected $_content = array();
  67. /**
  68. *
  69. * array of variables that will be forwarded to the layout and view files
  70. *
  71. * @var array
  72. */
  73. protected $_variables;
  74. /**
  75. *
  76. * array of global variables
  77. *
  78. * @var array
  79. */
  80. protected $_globals;
  81. /**
  82. *
  83. * instances of view helper objects
  84. *
  85. * @var array
  86. */
  87. protected $_helpers = array();
  88. /**
  89. *
  90. * @param array $variables
  91. */
  92. public function __construct($variables = array())
  93. {
  94. $this->setVariables($variables);
  95. $this->setBaseUrl();
  96. }
  97. /**
  98. *
  99. * get the contents of the layout variable
  100. *
  101. * @return string
  102. */
  103. public function getLayout()
  104. {
  105. return $this->_layout;
  106. }
  107. /**
  108. *
  109. * set the location of the layout file to be used
  110. *
  111. * @param string $layout
  112. *
  113. * @return $this
  114. */
  115. public function setLayout($layout)
  116. {
  117. if (isset($layout)) {
  118. $this->_layout = $layout;
  119. }
  120. return $this;
  121. }
  122. /**
  123. *
  124. * clear the layout variable
  125. *
  126. * @return $this
  127. */
  128. public function setNoLayout()
  129. {
  130. $this->_layout = null;
  131. return $this;
  132. }
  133. /**
  134. *
  135. * return the path of the view files
  136. *
  137. * @return string
  138. */
  139. public function getViewsPath()
  140. {
  141. return $this->_viewsPath;
  142. }
  143. /**
  144. *
  145. * set the view files path
  146. *
  147. * @param string $viewsPath
  148. *
  149. * @return $this
  150. */
  151. public function setViewsPath($viewsPath)
  152. {
  153. if (isset($viewsPath)) {
  154. $this->_viewsPath = $viewsPath;
  155. }
  156. return $this;
  157. }
  158. /**
  159. *
  160. * set custom view file name to be used when rendering
  161. *
  162. * @param string $viewFileName
  163. *
  164. * @return $this
  165. */
  166. public function setViewFileName($viewFileName)
  167. {
  168. $this->_viewFileName = $viewFileName;
  169. return $this;
  170. }
  171. /**
  172. *
  173. * get custom view file name
  174. *
  175. * @return string
  176. */
  177. public function getViewFileName()
  178. {
  179. return $this->_viewFileName;
  180. }
  181. /**
  182. *
  183. * return the path of the layout files
  184. *
  185. * @return string
  186. */
  187. public function getLayoutsPath()
  188. {
  189. return $this->_layoutsPath;
  190. }
  191. /**
  192. *
  193. * set the layout files path
  194. *
  195. * @param string $layoutsPath
  196. *
  197. * @return $this
  198. */
  199. public function setLayoutsPath($layoutsPath)
  200. {
  201. if (isset($layoutsPath)) {
  202. $this->_layoutsPath = $layoutsPath;
  203. }
  204. return $this;
  205. }
  206. /**
  207. *
  208. * set base url
  209. *
  210. * @return $this
  211. */
  212. public function setBaseUrl()
  213. {
  214. $this->baseUrl = rtrim(
  215. dirname($_SERVER['SCRIPT_NAME']), '/\\');
  216. return $this;
  217. }
  218. /**
  219. *
  220. * get layout content
  221. *
  222. * @return string
  223. */
  224. public function getContent()
  225. {
  226. return implode('', $this->_content);
  227. }
  228. /**
  229. *
  230. * add content to the layout content array
  231. *
  232. * @param array|string $content
  233. *
  234. * @return $this
  235. */
  236. public function setContent($content)
  237. {
  238. $this->_content[] = $content;
  239. return $this;
  240. }
  241. /**
  242. *
  243. * clear content array
  244. *
  245. * @return $this
  246. */
  247. public function clearContent()
  248. {
  249. $this->_content = array();
  250. return $this;
  251. }
  252. /**
  253. *
  254. * get view variables array
  255. *
  256. * @return array
  257. */
  258. public function getVariables()
  259. {
  260. return $this->_variables;
  261. }
  262. /**
  263. *
  264. * set multiple view variables
  265. *
  266. * @param array $variables
  267. *
  268. * @return $this
  269. */
  270. public function setVariables(array $variables)
  271. {
  272. foreach ($variables as $key => $value) {
  273. $this->setVariable($key, $value);
  274. }
  275. return $this;
  276. }
  277. /**
  278. *
  279. * clear view object variables
  280. *
  281. * @return $this
  282. */
  283. public function clearVariables()
  284. {
  285. $this->_variables = array();
  286. return $this;
  287. }
  288. /**
  289. *
  290. * get view globals array
  291. *
  292. * @return array
  293. */
  294. public function getGlobals()
  295. {
  296. return $this->_globals;
  297. }
  298. /**
  299. *
  300. * set multiple view variables
  301. *
  302. * @param array $globals
  303. *
  304. * @return $this
  305. */
  306. public function setGlobals(array $globals)
  307. {
  308. foreach ($globals as $key => $value) {
  309. $this->setGlobal($key, $value);
  310. }
  311. return $this;
  312. }
  313. /**
  314. *
  315. * clear view object globals
  316. *
  317. * @return $this
  318. */
  319. public function clearGlobals()
  320. {
  321. $this->_globals = array();
  322. return $this;
  323. }
  324. /**
  325. *
  326. * get all instantiated view helpers
  327. *
  328. * @return array
  329. */
  330. public function getHelpers()
  331. {
  332. return $this->_helpers;
  333. }
  334. /**
  335. *
  336. * return a view helper
  337. *
  338. * @param string $name
  339. *
  340. * @throws \DomainException
  341. * @return \Cube\View\Helper\HelperInterface
  342. */
  343. public function getHelper($name)
  344. {
  345. if (array_key_exists($name, $this->_helpers)) {
  346. return $this->_helpers[$name];
  347. }
  348. else {
  349. $className = '\\' . __NAMESPACE__ . '\\View\\Helper\\' . ucfirst($name);
  350. if (class_exists($className)) {
  351. $reflect = new \ReflectionClass($className);
  352. $instance = $reflect->newInstanceArgs();
  353. $helper = $instance->setView($this);
  354. $this->setHelper($name, $helper);
  355. return $helper;
  356. }
  357. else {
  358. throw new \DomainException(sprintf("A helper with the name '%s' does not exist.", ucfirst($name)));
  359. }
  360. }
  361. }
  362. /**
  363. *
  364. * set a new view helper
  365. *
  366. * @param string $name
  367. * @param \Cube\View\Helper\HelperInterface $helper
  368. *
  369. * @return $this
  370. * @throws \InvalidArgumentException
  371. */
  372. public function setHelper($name, $helper)
  373. {
  374. if (!array_key_exists($name, $this->_helpers)) {
  375. if ($helper instanceof HelperInterface) {
  376. $this->_helpers[$name] = $helper;
  377. }
  378. else {
  379. throw new \InvalidArgumentException(
  380. sprintf("The view helper with the name '%s' must be an instance of \Cube\View\Helper\HelperInterface.",
  381. $name));
  382. }
  383. }
  384. return $this;
  385. }
  386. /**
  387. *
  388. * check if a view helper has been set
  389. *
  390. * @param string $name the name of the registered helper
  391. *
  392. * @return bool
  393. */
  394. public function isHelper($name)
  395. {
  396. if (array_key_exists($name, $this->_helpers)) {
  397. return true;
  398. }
  399. return false;
  400. }
  401. /**
  402. *
  403. * set single view variable
  404. *
  405. * @param string $key
  406. * @param mixed $value
  407. *
  408. * @return $this
  409. */
  410. public function setVariable($key, $value)
  411. {
  412. $this->_variables[$key] = $value;
  413. return $this;
  414. }
  415. /**
  416. *
  417. * set single view global
  418. *
  419. * @param string $key
  420. * @param mixed $value
  421. *
  422. * @return $this
  423. */
  424. public function setGlobal($key, $value)
  425. {
  426. $this->_globals[$key] = $value;
  427. return $this;
  428. }
  429. /**
  430. *
  431. * processes a single view file and saves the output in the views variable in array format
  432. * or it returns the output to a view helper
  433. *
  434. * (additions)
  435. * > if the active theme contains the view file, then that file will be processed
  436. * instead of the default module view file
  437. * > if the view file isn't found in the theme or the active module,
  438. * check all modules from the application before returning a file now found error
  439. *
  440. * 1.4 - each check will first check in the mods folder
  441. * 1.8 - allows the loading of view files from mods/themes/<active-theme> in order to completely separate stock
  442. * files from modified files
  443. *
  444. * PROCESSING ORDER:
  445. * - absolute name
  446. * - mods themes folder
  447. * - themes folder
  448. * - mods modules views folder
  449. * - modules views folder
  450. *
  451. * @param string $file
  452. * @param bool $partial if partial, the output is not saved in the output array
  453. *
  454. * @return string
  455. */
  456. public function process($file, $partial = false)
  457. {
  458. $location = null;
  459. $baseFile = ltrim($file, self::DIR_SEPARATOR);
  460. $modsPath = Autoloader::getInstance()->getModsPath();
  461. $locations = array(
  462. $file, // <- absolute path to file (wont work for mods etc), nor for themes
  463. $modsPath . self::DIR_SEPARATOR . $this->_layoutsPath . self::DIR_SEPARATOR . $baseFile, // <- mods folder / theme specific file (needs relative path)
  464. $this->_layoutsPath . self::DIR_SEPARATOR . $baseFile, // <- theme specific file (needs relative path)
  465. );
  466. $moduleManager = ModuleManager::getInstance();
  467. $modulePaths = $moduleManager->getPaths();
  468. $activeModule = $moduleManager->getActiveModule();
  469. if ($activeModule) {
  470. $modulePaths = array($activeModule => $modulePaths[$activeModule]) + $modulePaths;
  471. }
  472. foreach ($modulePaths as $path) {
  473. if ($path) {
  474. $fileLocation = str_replace(DIRECTORY_SEPARATOR . ModuleManager::MODULE_FILES, '', $path)
  475. . DIRECTORY_SEPARATOR . self::VIEWS_FOLDER
  476. . DIRECTORY_SEPARATOR . $baseFile;
  477. array_push($locations, $modsPath . self::DIR_SEPARATOR . $fileLocation);
  478. array_push($locations, $fileLocation);
  479. }
  480. }
  481. foreach ($locations as $loc) {
  482. if (file_exists($loc)) {
  483. $location = $loc;
  484. break;
  485. }
  486. }
  487. try {
  488. if ($location !== null) {
  489. @extract($this->_variables);
  490. ob_start();
  491. include $location;
  492. $output = ob_get_clean();
  493. if ($partial === false) {
  494. $this->setContent($output);
  495. }
  496. else {
  497. return $output;
  498. }
  499. }
  500. else {
  501. throw new Exception(
  502. sprintf("The view file '%s' could not be found.", $file));
  503. }
  504. } catch (Exception $e) {
  505. $this->setContent($e->display());
  506. }
  507. return '';
  508. }
  509. /**
  510. *
  511. * renders the layout and returns the output buffer
  512. *
  513. * @param null $layout
  514. *
  515. * @internal param string $name the name of the layout to process
  516. * @return string|null
  517. */
  518. public function render($layout = null)
  519. {
  520. if ($layout === null) {
  521. $layout = ltrim($this->_layout, self::DIR_SEPARATOR);
  522. }
  523. $modsPath = Autoloader::getInstance()->getModsPath();
  524. ob_start();
  525. if (@is_file($layout)) {
  526. $layout = $this->_layout;
  527. }
  528. else if (@is_file($modsPath . self::DIR_SEPARATOR . $this->_layoutsPath . self::DIR_SEPARATOR . $layout)) {
  529. $layout = $modsPath . self::DIR_SEPARATOR . $this->_layoutsPath . self::DIR_SEPARATOR . $layout;
  530. }
  531. else if (@is_file($this->_layoutsPath . self::DIR_SEPARATOR . $layout)) {
  532. $layout = $this->_layoutsPath . self::DIR_SEPARATOR . $layout;
  533. }
  534. else {
  535. $layout = null;
  536. }
  537. if ($layout !== null) {
  538. require $layout;
  539. return ob_get_clean();
  540. }
  541. else {
  542. echo $this->getContent();
  543. }
  544. }
  545. /**
  546. *
  547. * get magic method, enables <code> echo $view->name </code>
  548. *
  549. * @param string $name
  550. *
  551. * @return mixed|null
  552. */
  553. public function get($name)
  554. {
  555. $method = 'get' . ucfirst($name);
  556. if (method_exists($this, $method)) {
  557. return $this->$method();
  558. }
  559. else if (isset($this->_globals[$name])) {
  560. return $this->_globals[$name];
  561. }
  562. else if (isset($this->_variables[$name])) {
  563. return $this->_variables[$name];
  564. }
  565. return null;
  566. }
  567. /**
  568. *
  569. * set page attributes (magic method): enables <code>$view->name = $value</code>
  570. *
  571. * @param string $name
  572. * @param mixed $value
  573. *
  574. * @return $this
  575. */
  576. public function set($name, $value)
  577. {
  578. $method = 'set' . ucfirst($name);
  579. if (method_exists($this, $method)) {
  580. $this->$method($value);
  581. }
  582. else {
  583. $this->_variables[$name] = $value;
  584. }
  585. return $this;
  586. }
  587. /**
  588. *
  589. * get magic method, proxy to $this->get($name)
  590. *
  591. * @param string $name
  592. *
  593. * @return string|null
  594. */
  595. public function __get($name)
  596. {
  597. return $this->get($name);
  598. }
  599. /**
  600. *
  601. * set magic method, proxy for $this->set($name, $value) method
  602. *
  603. * @param string $name
  604. * @param string $value
  605. */
  606. public function __set($name, $value)
  607. {
  608. $this->set($name, $value);
  609. }
  610. /**
  611. *
  612. * call magic method, used for calling view helpers
  613. * custom helpers need to be registered with the view in the bootstrap
  614. * create a proxy for the translate view helper, called <code>$this->_($message)</code>
  615. *
  616. * @param string $name the name of the view helper
  617. * @param array $arguments the arguments accepted by the helper in array format
  618. *
  619. * @return \Cube\View\Helper\HelperInterface return the view helper method with the same name as the view helper
  620. */
  621. public function __call($name, $arguments)
  622. {
  623. if (strcmp($name, '_') === 0) {
  624. $name = 'translate';
  625. }
  626. $helper = $this->getHelper($name);
  627. return call_user_func_array(
  628. array($helper, $name), $arguments);
  629. }
  630. }