PageRenderTime 10ms CodeModel.GetById 99ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 2ms

/e107_handlers/admin_ui.php

https://github.com/CasperGemini/e107
PHP | 5872 lines | 3529 code | 715 blank | 1628 comment | 486 complexity | 34ed6a3c5068ad414d571024b6ab9174 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/*
   3 * e107 website system
   4 *
   5 * Copyright (C) 2008-2012 e107 Inc (e107.org)
   6 * Released under the terms and conditions of the
   7 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
   8 *
   9 * Administration User Interface logic
  10 *
  11 * $URL$
  12 * $Id$
  13 */
  14
  15 /**
  16 * @package e107
  17 * @subpackage e107_handlers
  18 * @version $Id$
  19 *
  20 * Administration User Interface logic
  21 */
  22
  23
  24/**
  25 * @todo core request handler (non-admin), core response
  26 */
  27if (!defined('e107_INIT')){ exit; }  
  28 
  29 
  30class e_admin_request
  31{
  32	/**
  33	 * Current GET request array
  34	 * @var array
  35	 */
  36	protected $_request_qry;
  37
  38	/**
  39	 * Current POST array
  40	 * @var array
  41	 */
  42	protected $_posted_qry;
  43
  44	/**
  45	 * Current Mode
  46	 * @var string
  47	 */
  48	protected $_mode = '';
  49
  50	/**
  51	 * Default Mode
  52	 * @var string
  53	 */
  54	protected $_default_mode = 'main';
  55
  56	/**
  57	 * Key name for mode search
  58	 * @var string
  59	 */
  60	protected $_mode_key = 'mode';
  61
  62	/**
  63	 * Current action
  64	 * @var string
  65	 */
  66	protected $_action = '';
  67
  68	/**
  69	 * Default Action
  70	 * @var string
  71	 */
  72	protected $_default_action = 'index';
  73
  74	/**
  75	 * Key name for action search
  76	 * @var string
  77	 */
  78	protected $_action_key = 'action';
  79
  80	/**
  81	 * Current ID
  82	 * @var integer
  83	 */
  84	protected $_id = 0;
  85
  86	/**
  87	 * Key name for ID search
  88	 * @var string
  89	 */
  90	protected $_id_key = 'id';
  91
  92	/**
  93	 * Constructor
  94	 *
  95	 * @param string|array $qry [optional]
  96	 * @return none
  97	 */
  98	public function __construct($request_string = null, $parse = true)
  99	{
 100		if(null === $request_string)
 101		{
 102			$request_string = str_replace('&amp;', '&', e_QUERY);
 103		}
 104		if($parse)
 105		{
 106			$this->parseRequest($request_string);
 107		}
 108	}
 109
 110	/**
 111	 * Parse request data
 112	 * @param string|array $request_data
 113	 * @return e_admin_request
 114	 */
 115	protected function parseRequest($request_data)
 116	{
 117		if(is_string($request_data))
 118		{
 119			parse_str($request_data, $request_data);
 120		}
 121		$this->_request_qry = (array) $request_data;
 122
 123		// Set current mode
 124		if(isset($this->_request_qry[$this->_mode_key]))
 125		{
 126			$this->_mode = preg_replace('/[^\w]/', '', $this->_request_qry[$this->_mode_key]);
 127		}
 128
 129		// Set current action
 130		if(isset($this->_request_qry[$this->_action_key]))
 131		{
 132			$this->_action = preg_replace('/[^\w]/', '', $this->_request_qry[$this->_action_key]);
 133		}
 134
 135		// Set current id
 136		if(isset($this->_request_qry[$this->_id_key]))
 137		{
 138			$this->_id = preg_replace('/[^\w-:.]/', '', $this->_request_qry[$this->_id_key]);
 139		}
 140
 141		$this->_posted_qry =& $_POST; //raw?
 142
 143		return $this;
 144	}
 145
 146	/**
 147	 * Retrieve variable from GET scope
 148	 * If $key is null, all GET data will be returned
 149	 *
 150	 * @param string $key [optional]
 151	 * @param mixed $default [optional]
 152	 * @return mixed
 153	 */
 154	public function getQuery($key = null, $default = null)
 155	{
 156		if(null === $key)
 157		{
 158			return $this->_request_qry;
 159		}
 160		return (isset($this->_request_qry[$key]) ? $this->_request_qry[$key] : $default);
 161	}
 162
 163	/**
 164	 * Set/Unset GET variable
 165	 * If $key is array, $value is not used.
 166	 * If $value is null, (string) $key is unset
 167	 *
 168	 * @param string|array $key
 169	 * @param mixed $value [optional]
 170	 * @return e_admin_request
 171	 */
 172	public function setQuery($key, $value = null)
 173	{
 174		if(is_array($key))
 175		{
 176			foreach ($key as $k=>$v)
 177			{
 178				$this->setQuery($k, $v);
 179			}
 180			return $this;
 181		}
 182
 183		if(null === $value)
 184		{
 185			unset($this->_request_qry[$key]);
 186			unset($_GET[$key]);
 187			return $this;
 188		}
 189
 190		$this->_request_qry[$key] = $value;
 191		$_GET[$key] = $value;
 192		return $this;
 193	}
 194
 195	/**
 196	 * Retrieve variable from POST scope
 197	 * If $key is null, all POST data will be returned
 198	 *
 199	 * @param string $key [optional]
 200	 * @param mixed $default [optional]
 201	 * @return mixed
 202	 */
 203	public function getPosted($key = null, $default = null)
 204	{
 205		if(null === $key)
 206		{
 207			return $this->_posted_qry;
 208		}
 209		return (isset($this->_posted_qry[$key]) ? $this->_posted_qry[$key] : $default);
 210	}
 211
 212	/**
 213	 * Set/Unset POST variable
 214	 * If $key is array, $value is not used.
 215	 * If $value is null, (string) $key is unset
 216	 *
 217	 * @param object $key
 218	 * @param object $value [optional]
 219	 * @return e_admin_request
 220	 */
 221	public function setPosted($key, $value = null)
 222	{
 223		if(is_array($key))
 224		{
 225			if(empty($key))
 226			{
 227				$this->_posted_qry = array(); //POST reset
 228				return $this;
 229			}
 230			foreach ($key as $k=>$v)
 231			{
 232				$this->setPosted($k, $v);
 233			}
 234			return $this;
 235		}
 236
 237		if(null === $value)
 238		{
 239			unset($this->_posted_qry[$key]);
 240			return $this;
 241		}
 242
 243		$tp = e107::getParser();
 244		$this->_posted_qry[$tp->post_toForm($key)] = $tp->post_toForm($value);
 245		return $this;
 246	}
 247
 248	/**
 249	 * Get current mode
 250	 * @return string
 251	 */
 252	public function getMode()
 253	{
 254		if(!$this->_mode) return $this->getDefaultMode();
 255		return $this->_mode;
 256	}
 257
 258	/**
 259	 * Get default mode
 260	 * @return string
 261	 */
 262	public function getDefaultMode()
 263	{
 264		return $this->_default_mode;
 265	}
 266
 267	/**
 268	 * Get current mode name
 269	 *
 270	 * @return string
 271	 */
 272	public function getModeName()
 273	{
 274		return strtolower(str_replace('-', '_', $this->getMode()));
 275	}
 276
 277	/**
 278	 * Reset current mode
 279	 * @param string $mode
 280	 * @return e_admin_request
 281	 */
 282	public function setMode($mode)
 283	{
 284		$this->_mode = preg_replace('/[^\w]/', '', $mode);
 285		$this->setQuery($this->_mode_key, $this->_mode);
 286		return $this;
 287	}
 288
 289	/**
 290	 * Set default mode
 291	 * @param string $mode
 292	 * @return e_admin_request
 293	 */
 294	public function setDefaultMode($mode)
 295	{
 296		if($mode) $this->_default_mode = $mode;
 297		return $this;
 298	}
 299
 300	/**
 301	 * Set mode key name
 302	 * @param string $key
 303	 * @return e_admin_request
 304	 */
 305	public function setModeKey($key)
 306	{
 307		$this->_mode_key = $key;
 308		return $this;
 309	}
 310
 311	/**
 312	 * Get current action
 313	 * @return TBD
 314	 */
 315	public function getAction()
 316	{
 317		if(!$this->_action) return $this->getDefaultAction();
 318		return $this->_action;
 319	}
 320
 321	/**
 322	 * Get default action
 323	 * @return string
 324	 */
 325	public function getDefaultAction()
 326	{
 327		return $this->_default_action;
 328	}
 329
 330	/**
 331	 * Get current action name
 332	 * @return string camelized action
 333	 */
 334	public function getActionName()
 335	{
 336		return $this->camelize($this->getAction());
 337	}
 338
 339	/**
 340	 * Reset current action
 341	 *
 342	 * @param string $action
 343	 * @return e_admin_request
 344	 */
 345	public function setAction($action)
 346	{
 347		$this->_action = preg_replace('/[^\w]/', '', $action);
 348		$this->setQuery($this->_action_key, $this->_action);
 349		return $this;
 350	}
 351
 352	/**
 353	 * Set default action
 354	 *
 355	 * @param string $action
 356	 * @return e_admin_request
 357	 */
 358	public function setDefaultAction($action)
 359	{
 360		if($action) $this->_default_action = $action;
 361		return $this;
 362	}
 363
 364	/**
 365	 * Set action key name
 366	 * @param string $key
 367	 * @return e_admin_request
 368	 */
 369	public function setActionKey($key)
 370	{
 371		$this->_action_key = $key;
 372		return $this;
 373	}
 374
 375	/**
 376	 * Get current ID
 377	 * @return integer
 378	 */
 379	public function getId()
 380	{
 381		return $this->_id;
 382	}
 383
 384	/**
 385	 * Reset current ID
 386	 * @param string $id
 387	 * @return e_admin_request
 388	 */
 389	public function setId($id)
 390	{
 391		$id = intval($id);
 392		$this->_id = $id;
 393		$this->setQuery($this->_id_key, $id);
 394		return $this;
 395	}
 396
 397	/**
 398	 * Set id key name
 399	 * @param string $key
 400	 * @return e_admin_request
 401	 */
 402	public function setIdKey($key)
 403	{
 404		$this->_id_key = $key;
 405		return $this;
 406	}
 407
 408	/**
 409	 * Build query string from current request array
 410	 * NOTE: changing url separator to &amp; ($encode==true) (thus URL XHTML compliance) works in PHP 5.1.2+ environment
 411	 *
 412	 * @param string|array $merge_with [optional] override request values
 413	 * @param boolean $encode if true &amp; separator will be used, all values will be http encoded, default true
 414	 * @param string|array $exclude_from_query numeric array/comma separated list of vars to be excluded from current query, true - don't use current query at all
 415	 * @param boolean $keepSpecial don't exclude special vars as 'mode' and 'action'
 416	 * @return string url encoded query string
 417	 */
 418	public function buildQueryString($merge_with = array(), $encode = true, $exclude_from_query = '', $keepSpecial = true)
 419	{
 420		$ret = $this->getQuery();
 421
 422		//special case - exclude all current
 423		if(true === $exclude_from_query)
 424		{
 425			$exclude_from_query = array_keys($ret);
 426		}
 427		// to array
 428		if(is_string($exclude_from_query))
 429		{
 430			$exclude_from_query = array_map('trim', explode(',', $exclude_from_query));
 431		}
 432		if($exclude_from_query)
 433		{
 434			foreach ($exclude_from_query as $var)
 435			{
 436				if($keepSpecial && $var != $this->_action_key && $var != $this->_mode_key) unset($ret[$var]);
 437			}
 438		}
 439
 440		if(is_string($merge_with))
 441		{
 442			parse_str($merge_with, $merge_with);
 443		}
 444		$ret = array_merge($ret, (array) $merge_with);
 445		$separator = '&';
 446		if($encode)
 447		{
 448			$separator = '&amp;';
 449			//$ret = array_map('rawurlencode', $ret);
 450		}
 451
 452		$ret = http_build_query($ret, 'numeric_', $separator);
 453		if(!$encode)
 454		{
 455			return rawurldecode($ret);
 456		}
 457		return $ret;
 458	}
 459
 460	/**
 461	 * Convert string to CamelCase
 462	 *
 463	 * @param string $str
 464	 * @return string
 465	 */
 466	public function camelize($str)
 467	{
 468		return implode('', array_map('ucfirst', explode('-', str_replace('_', '-', $str))));
 469	}
 470}
 471
 472/**
 473 * TODO - front response parent, should do all the header.php work
 474 */
 475class e_admin_response
 476{
 477	/**
 478	 * Body segments
 479	 *
 480	 * @var array
 481	 */
 482	protected $_body = array();
 483
 484	/**
 485	 * Title segments
 486	 *
 487	 * @var unknown_type
 488	 */
 489	protected $_title = array();
 490
 491	/**
 492	 * e107 meta title
 493	 *
 494	 * @var array
 495	 */
 496	protected $_e_PAGETITLE = array();
 497
 498	/**
 499	 * e107 meta description
 500	 *
 501	 * @var array
 502	 */
 503	protected $_META_DESCRIPTION = array();
 504
 505	/**
 506	 * e107 meta keywords
 507	 *
 508	 * @var array
 509	 */
 510	protected $_META_KEYWORDS = array();
 511
 512	/**
 513	 * Render mods
 514	 *
 515	 * @var array
 516	 */
 517	protected $_render_mod = array();
 518
 519	/**
 520	 * Meta title segment description
 521	 *
 522	 * @var string
 523	 */
 524	protected $_meta_title_separator = ' - ';
 525
 526	/**
 527	 * Title segment separator
 528	 *
 529	 * @var string
 530	 */
 531	protected $_title_separator = ' &raquo; ';
 532
 533	/**
 534	 * Constructor
 535	 *
 536	 */
 537	public function __construct()
 538	{
 539		$this->_render_mod['default'] = 'admin_page';
 540	}
 541
 542	/**
 543	 * Set body segments for a namespace
 544	 *
 545	 * @param string $content
 546	 * @param string $namespace segment namesapce
 547	 * @return e_admin_response
 548	 */
 549	function setBody($content, $namespace = 'default')
 550	{
 551		$this->_body[$namespace] = $content;
 552		return $this;
 553	}
 554
 555	/**
 556	 * Append body segment to a namespace
 557	 *
 558	 * @param string $content
 559	 * @param string $namespace segment namesapce
 560	 * @return e_admin_response
 561	 */
 562	function appendBody($content, $namespace = 'default')
 563	{
 564		if(!isset($this->_body[$namespace]))
 565		{
 566			$this->_body[$namespace] = array();
 567		}
 568		$this->_body[$namespace][] = $content;
 569		return $this;
 570	}
 571
 572	/**
 573	 * Prepend body segment to a namespace
 574	 *
 575	 * @param string $content
 576	 * @param string $namespace segment namespace
 577	 * @return e_admin_response
 578	 */
 579	function prependBody($content, $namespace = 'default')
 580	{
 581		if(!isset($this->_body[$namespace]))
 582		{
 583			$this->_body[$namespace] = array();
 584		}
 585		$this->_body[$namespace] = array_merge(array($content), $this->_body[$namespace]);
 586		return $this;
 587	}
 588
 589	/**
 590	 * Get body segments from a namespace
 591	 *
 592	 * @param string $namespace segment namesapce
 593	 * @param boolean $reset reset segment namespace
 594	 * @param string|boolean $glue if false return array, else return string
 595	 * @return string|array
 596	 */
 597	function getBody($namespace = 'default', $reset = false, $glue = '')
 598	{
 599		$content = vartrue($this->_body[$namespace], array());
 600		if($reset)
 601		{
 602			$this->_body[$namespace] = array();
 603		}
 604		if(is_bool($glue))
 605		{
 606			return ($glue ? $content : implode('', $content));
 607		}
 608		return implode($glue, $content);
 609	}
 610
 611	/**
 612	 * Set title segments for a namespace
 613	 *
 614	 * @param string $title
 615	 * @param string $namespace
 616	 * @return e_admin_response
 617	 */
 618	function setTitle($title, $namespace = 'default')
 619	{
 620		$this->_title[$namespace] = array($title);
 621		return $this;
 622	}
 623
 624	/**
 625	 * Append title segment to a namespace
 626	 *
 627	 * @param string $title
 628	 * @param string $namespace segment namesapce
 629	 * @return e_admin_response
 630	 */
 631	function appendTitle($title, $namespace = 'default')
 632	{
 633		if(empty($title))
 634		{
 635			return $this;
 636		}
 637		if(!isset($this->_title[$namespace]))
 638		{
 639			$this->_title[$namespace] = array();
 640		}
 641		$this->_title[$namespace][] = $title;
 642		return $this;
 643	}
 644
 645	/**
 646	 * Prepend title segment to a namespace
 647	 *
 648	 * @param string $title
 649	 * @param string $namespace segment namespace
 650	 * @return e_admin_response
 651	 */
 652	function prependTitle($title, $namespace = 'default')
 653	{
 654		if(empty($title))
 655		{
 656			return $this;
 657		}
 658		if(!isset($this->_title[$namespace]))
 659		{
 660			$this->_title[$namespace] = array();
 661		}
 662		$this->_title[$namespace] = array_merge(array($title), $this->_title[$namespace]);
 663		return $this;
 664	}
 665
 666	/**
 667	 * Get title segments from namespace
 668	 *
 669	 * @param string $namespace
 670	 * @param boolean $reset
 671	 * @param boolean|string $glue
 672	 * @return unknown
 673	 */
 674	function getTitle($namespace = 'default', $reset = false, $glue = '  ')
 675	{
 676		$content = array();
 677		if(isset($this->_title[$namespace]) && is_array($this->_title[$namespace]))
 678		{
 679			$content = $this->_title[$namespace];
 680		}
 681		if($reset)
 682		{
 683			unset($this->_title[$namespace]);
 684		}
 685		if(is_bool($glue) || empty($glue))
 686		{
 687			return ($glue ? $content : implode($this->_title_separator, $content));
 688		}
 689
 690		$glue = deftrue('SEP',' - '); // Defined by admin theme. // admin-ui used only by bootstrap. 
 691
 692		return implode($glue, $content);
 693		// return $head. implode($glue, $content).$foot;
 694	}
 695
 696	/**
 697	 * Set render mode for a namespace
 698	 *
 699	 * @param string $render_mod
 700	 * @param string $namespace
 701	 * @return e_admin_response
 702	 */
 703	function setRenderMod($render_mod, $namespace = 'default')
 704	{
 705		$this->_render_mod[$namespace] = $render_mod;
 706		return $this;
 707	}
 708
 709	/**
 710	 * Set render mode for namespace
 711	 *
 712	 * @param string $namespace
 713	 * @return string
 714	 */
 715	function getRenderMod($namespace = 'default')
 716	{
 717		return varset($this->_render_mod[$namespace], null);
 718	}
 719
 720	/**
 721	 * Add meta title, description and keywords segments
 722	 *
 723	 * @param string $meta property name
 724	 * @param string $content meta content
 725	 * @return e_admin_response
 726	 */
 727	function addMetaData($meta, $content)
 728	{
 729		$tp = e107::getParser();
 730		$meta = '_' . $meta;
 731		if(isset($this->{$meta}) && !empty($content))
 732		{
 733			$this->{$meta}[] = strip_tags($content);
 734		}
 735		return $this;
 736	}
 737
 738	/**
 739	 * Add meta title segment
 740	 *
 741	 * @param string $title
 742	 * @return e_admin_response
 743	 */
 744	function addMetaTitle($title)
 745	{
 746		$this->addMetaData('e_PAGETITLE', $title);
 747		return $this;
 748	}
 749
 750	/**
 751	 * Add meta description segment
 752	 *
 753	 * @param string $description
 754	 * @return e_admin_response
 755	 */
 756	function addMetaDescription($description)
 757	{
 758		$this->addMetaData('META_DESCRIPTION', $description);
 759		return $this;
 760	}
 761
 762	/**
 763	 * Add meta keywords segment
 764	 *
 765	 * @param string $keyword
 766	 * @return e_admin_response
 767	 */
 768	function addMetaKeywords($keyword)
 769	{
 770		$this->addMetaData('META_KEYWORDS', $keyword);
 771		return $this;
 772	}
 773
 774	/**
 775	 * Send e107 meta-data
 776	 *
 777	 * @return e_admin_response
 778	 */
 779	function sendMeta()
 780	{
 781		//HEADERF already included or meta content already sent
 782		if(e_AJAX_REQUEST || defined('HEADER_INIT') || defined('e_PAGETITLE'))
 783			return $this;
 784
 785		if(!defined('e_PAGETITLE') && !empty($this->_e_PAGETITLE))
 786		{
 787			define('e_PAGETITLE', implode($this->_meta_title_separator, $this->_e_PAGETITLE));
 788		}
 789
 790		if(!defined('META_DESCRIPTION') && !empty($this->_META_DESCRIPTION))
 791		{
 792			define('META_DESCRIPTION', implode(' ', $this->_META_DESCRIPTION));
 793		}
 794		if(!defined('META_KEYWORDS') && !empty($this->_META_KEYWORDS))
 795		{
 796			define('META_KEYWORDS', implode(', ', $this->_META_KEYWORDS));
 797		}
 798		return $this;
 799	}
 800
 801	/**
 802	 * Add content segment to the header namespace
 803	 *
 804	 * @param string $content
 805	 * @return e_admin_response
 806	 */
 807	function addHeaderContent($content)
 808	{
 809		$this->appendBody($content, 'header_content');
 810		return $this;
 811	}
 812
 813	/**
 814	 * Get page header namespace content segments
 815	 *
 816	 * @param boolean $reset
 817	 * @param boolean $glue
 818	 * @return string
 819	 */
 820	function getHeaderContent($reset = true, $glue = "\n\n")
 821	{
 822		return $this->getBody('header_content', $reset, $glue);
 823	}
 824
 825	/**
 826	 * Switch to iframe mod
 827	 * FIXME - implement e_IFRAME to frontend - header_default.php
 828	 *
 829	 * @return e_admin_response
 830	 */
 831	function setIframeMod()
 832	{
 833		global $HEADER, $FOOTER, $CUSTOMHEADER, $CUSTOMFOOTER;
 834		$HEADER = $FOOTER = '';
 835		$CUSTOMHEADER = $CUSTOMFOOTER = array();
 836		//TODO generic $_GET to activate for any page of admin. 
 837		// New
 838		if(!defined('e_IFRAME'))
 839		{
 840			define('e_IFRAME', true);
 841		}
 842		return $this;
 843	}
 844
 845	/**
 846	 * Send Response Output
 847	 *
 848	 * @param string $name segment
 849	 * @param array $options valid keys are: messages|render|meta|return|raw|ajax
 850	 * @return mixed
 851	 */
 852	function send($name = 'default', $options = array())
 853	{
 854		if(is_string($options))
 855		{
 856			parse_str($options, $options);
 857		}
 858
 859		// Merge with all available default options
 860		$options = array_merge(array(
 861			'messages' => true,
 862			'render' => true,
 863			'meta' => false,
 864			'return' => false,
 865			'raw' => false,
 866			'ajax' => false
 867		), $options);
 868
 869		$content = $this->getBody($name, true);
 870		$title = $this->getTitle($name, true);
 871		$return = $options['return'];
 872
 873		if($options['ajax'] || e_AJAX_REQUEST)
 874		{
 875			$type = $options['ajax'] && is_string($options['ajax']) ? $options['ajax'] : '';
 876			$this->getJsHelper()->sendResponse($type);
 877		}
 878
 879		if($options['messages'])
 880		{
 881			$content = e107::getMessage()->render().$content;
 882		}
 883
 884		if($options['meta'])
 885		{
 886			$this->sendMeta();
 887		}
 888
 889		// raw output expected - force return array
 890		if($options['raw'])
 891		{
 892			return array($title, $content, $this->getRenderMod($name));
 893		}
 894
 895		//render disabled by the controller
 896		if(!$this->getRenderMod($name))
 897		{
 898			$options['render'] = false;
 899		}
 900
 901		if($options['render'])
 902		{
 903			return e107::getRender()->tablerender($title, $content, $this->getRenderMod($name), $return);
 904		}
 905
 906		if($return)
 907		{
 908			return $content;
 909		}
 910
 911		print($content);
 912		return '';
 913	}
 914
 915	/**
 916	 * Get JS Helper instance
 917	 *
 918	 * @return e_jshelper
 919	 */
 920	public function getJsHelper()
 921	{
 922		return e107::getSingleton('e_jshelper', true, 'admin_response');
 923	}
 924}
 925
 926/**
 927 * TODO - request related code should be moved to core
 928 * request handler
 929 */
 930class e_admin_dispatcher
 931{
 932	/**
 933	 * @var e_admin_request
 934	 */
 935	protected $_request = null;
 936
 937	/**
 938	 * @var e_admin_response
 939	 */
 940	protected $_response = null;
 941
 942	/**
 943	 * @var e_admin_controller
 944	 */
 945	protected $_current_controller = null;
 946
 947	/**
 948	 * Required (set by child class).
 949	 * Controller map array in format
 950	 * 'MODE' => array('controller' =>'CONTROLLER_CLASS_NAME'[, 'path' => 'CONTROLLER SCRIPT PATH', 'ui' => extend of 'comments_admin_form_ui', 'uipath' => 'path/to/ui/']);
 951	 *
 952	 * @var array
 953	 */
 954	protected $modes = array();
 955	
 956	/**
 957	 * Optional - access restrictions per action 
 958	 * Access array in format (similar to adminMenu)
 959	 * 'MODE/ACTION' => e_UC_* (userclass constant, or custom userclass ID if dynamically set) 
 960	 *
 961	 * @var array
 962	 */
 963	protected $access = array();
 964	
 965	/**
 966	 * Optional - generic entry point access restriction (via getperms()) 
 967	 * Value of this for plugins would be always 'P'.
 968	 * More detailed access control is granted with $access and $modes[MODE]['perm'] or  $modes[MODE]['userclass'] settings
 969	 *
 970	 * @var string
 971	 */
 972	protected $perm;
 973
 974	/**
 975	 * @var string
 976	 */
 977	protected $defaultMode = '';
 978
 979	/**
 980	 * @var string
 981	 */
 982	protected $defaultAction = '';
 983
 984	/**
 985	 * Optional - map 'mode/action' pair to 'modeAlias/actionAlias'
 986	 * @var string
 987	 */
 988	protected $adminMenuAliases = array();
 989
 990	/**
 991	 * Optional (set by child class).
 992	 * Required for admin menu render
 993	 * Format: 'mode/action' => array('caption' => 'Link title'[, 'perm' => '0', 'url' => '{e_PLUGIN}plugname/admin_config.php'], ...);
 994	 * Note that 'perm' and 'userclass' restrictions are inherited from the $modes, $access and $perm, so you don't have to set that vars if 
 995	 * you don't need any additional 'visual' control.
 996	 * All valid key-value pair (see e107::getNav()->admin function) are accepted.
 997	 * @var array
 998	 */
 999	protected $adminMenu = array();
1000	
1001
1002	/**
1003	 * Optional (set by child class).
1004	 * Page titles for pages not in adminMenu (e.g. main/edit)
1005	 * Format array(mod/action => Page Title)
1006	 * @var string
1007	 */
1008	protected $pageTitles = array(
1009		'main/edit' => LAN_MANAGE,
1010	);
1011
1012	/**
1013	 * Optional (set by child class).
1014	 * @var string
1015	 */
1016	protected $menuTitle = 'Menu';
1017
1018	/**
1019	 * @var string
1020	 */
1021	protected $pluginTitle = '';
1022
1023	/**
1024	 * Constructor
1025	 *
1026	 * @param string|array|e_admin_request $request [optional]
1027	 * @param e_admin_response $response
1028	 */
1029	public function __construct($auto_observe = true, $request = null, $response = null)
1030	{
1031		// we let know some admin routines we are in UI mod - related with some legacy checks and fixes
1032		if(!defined('e_ADMIN_UI'))
1033		{
1034			define('e_ADMIN_UI', true);
1035		}
1036		require_once(e_ADMIN.'boot.php');
1037		
1038		if(null === $request || !is_object($request))
1039		{
1040			$request = new e_admin_request($request);
1041		}
1042
1043		if(null === $response)
1044		{
1045			$response = new e_admin_response();
1046		}
1047
1048		$this->setRequest($request)->setResponse($response)->init();
1049
1050		if(!$this->defaultMode || !$this->defaultAction)
1051		{
1052			$this->setDefaults();
1053		}
1054
1055		$request->setDefaultMode($this->defaultMode)->setDefaultAction($this->defaultAction);
1056
1057		// register itself
1058		e107::setRegistry('admin/ui/dispatcher', $this);
1059		
1060		// permissions and restrictions
1061		$this->checkAccess();
1062
1063		if($auto_observe)
1064		{
1065			$this->runObservers(true);
1066		}
1067	}
1068
1069	/**
1070	 * User defined constructor - called before _initController() method
1071	 * @return e_admin_dispatcher
1072	 */
1073	public function init()
1074	{
1075	}
1076	
1077	public function checkAccess()
1078	{
1079		$request = $this->getRequest();
1080		$currentMode = $request->getMode();
1081
1082		// access based on mode setting - general controller access
1083		if(!$this->checkModeAccess($currentMode))
1084		{
1085			$request->setAction('e403');
1086			e107::getMessage()->addError('You don\'t have permissions to view this page.')
1087				->addDebug('Mode access restriction triggered.');
1088			return false;
1089		}
1090		
1091		// access based on $access settings - access per action
1092		$currentAction = $request->getAction();
1093		$route = $currentMode.'/'.$currentAction;
1094		if(!$this->checkRouteAccess($route))
1095		{
1096			$request->setAction('e403');
1097			e107::getMessage()->addError('You don\'t have permissions to view this page.')
1098				->addDebug('Route access restriction triggered.');
1099			return false;
1100		}
1101		
1102		return true;
1103	}
1104	
1105	public function checkModeAccess($mode)
1106	{
1107		// mode userclass (former check_class())
1108		if(isset($this->modes[$mode]['userclass']) && !e107::getUser()->checkClass($this->modes[$mode]['userclass'], false))
1109		{
1110			return false;
1111		}
1112		// mode admin permission (former getperms())
1113		if(isset($this->modes[$mode]['perm']) && !e107::getUser()->checkAdminPerms($this->modes[$mode]['perm']))
1114		{
1115			return false;
1116		}
1117		// generic dispatcher admin permission  (former getperms())
1118		if(null !== $this->perm && !e107::getUser()->checkAdminPerms($this->perm))
1119		{
1120			return false;
1121		}
1122		return true;
1123	}
1124	
1125	public function checkRouteAccess($route)
1126	{
1127		if(isset($this->access[$route]) && !e107::getUser()->checkClass($this->access[$route], false))
1128		{
1129			return false;
1130		}
1131		return true;
1132	}
1133
1134	/**
1135	 * Retrieve missing default action/mode
1136	 * @return e_admin_dispatcher
1137	 */
1138	public function setDefaults()
1139	{
1140		// try Admin menu first
1141		if($this->adminMenu)
1142		{
1143			reset($this->adminMenu);
1144			list($mode, $action) = explode('/', key($this->adminMenu), 3);
1145		}
1146		else
1147		{
1148			reset($this->modes);
1149			$mode = key($this->modes);
1150			$action = $this->modes[$mode]['index'];
1151		}
1152
1153		if(!$this->defaultMode) $this->defaultMode = $mode;
1154		if(!$this->defaultAction) $this->defaultAction = $action;
1155
1156		return $this;
1157	}
1158
1159	/**
1160	 * Get admin menu array
1161	 * @return array
1162	 */
1163	public function getMenuData()
1164	{
1165		return $this->adminMenu;
1166	}
1167	
1168	/**
1169	 * Get admin menu array
1170	 * @return array
1171	 */
1172	public function getPageTitles()
1173	{
1174		return $this->pageTitles;
1175	}
1176
1177	/**
1178	 * Get admin menu array
1179	 * @return array
1180	 */
1181	public function getMenuAliases()
1182	{
1183		return $this->adminMenuAliases;
1184	}
1185
1186	/**
1187	 * Get request object
1188	 * @return e_admin_request
1189	 */
1190	public function getRequest()
1191	{
1192		return $this->_request;
1193	}
1194
1195	/**
1196	 * Set request object
1197	 * @param e_admin_request $request
1198	 * @return e_admin_dispatcher
1199	 */
1200	public function setRequest($request)
1201	{
1202		$this->_request = $request;
1203		return $this;
1204	}
1205
1206	/**
1207	 * Get response object
1208	 * @return e_admin_response
1209	 */
1210	public function getResponse()
1211	{
1212		return $this->_response;
1213	}
1214
1215	/**
1216	 * Set response object
1217	 * @param e_admin_response $response
1218	 * @return e_admin_dispatcher
1219	 */
1220	public function setResponse($response)
1221	{
1222		$this->_response = $response;
1223		return $this;
1224	}
1225
1226	/**
1227	 * Dispatch & render all
1228	 *
1229	 * @param boolean $run_header see runObservers()
1230	 * @param boolean $return see runPage()
1231	 * @return string|array current admin page body
1232	 */
1233	public function run($run_header = true, $return = 'render')
1234	{
1235		return $this->runObservers()->runPage($return);
1236	}
1237
1238	/**
1239	 * Run observers/headers only, should be called before header.php call
1240	 *
1241	 * @return e_admin_dispatcher
1242	 */
1243	public function runObservers($run_header = true)
1244	{
1245		//search for $actionName.'Observer' method. Additional $actionName.$triggerName.'Trigger' methods will be called as well
1246		$this->getController()->dispatchObserver();
1247
1248		//search for $actionName.'Header' method, js manager should be used inside for sending JS to the page,
1249		// meta information should be created there as well
1250		if($run_header)
1251		{
1252			$this->getController()->dispatchHeader();
1253
1254		}
1255		return $this;
1256	}
1257
1258	/**
1259	 * Run page action.
1260	 * If return type is array, it should contain allowed response options (see e_admin_response::send())
1261	 * Available return type string values:
1262	 * - render_return: return rendered content ( see e107::getRender()->tablerender()), add system messages, send meta information
1263	 * - render: outputs rendered content ( see e107::getRender()->tablerender()), add system messages
1264	 * - response: return response object
1265	 * - raw: return array(title, content, render mode)
1266	 * - ajax: force ajax output (and exit)
1267	 *
1268	 * @param string|array $return_type expected string values: render|render_out|response|raw|ajax[_text|_json|_xml]
1269	 * @return mixed
1270	 */
1271	public function runPage($return_type = 'render')
1272	{
1273		$response = $this->getController()->dispatchPage();
1274		if(is_array($return_type))
1275		{
1276			return $response->send('default', $return_type);
1277		}
1278		switch($return_type)
1279		{
1280			case 'render_return':
1281				$options = array(
1282					'messages' => true,
1283					'render' => true,
1284					'meta' => true,
1285					'return' => true,
1286					'raw' => false
1287				);
1288			break;
1289
1290			case 'raw':
1291				$options = array(
1292					'messages' => false,
1293					'render' => false,
1294					'meta' => false,
1295					'return' => true,
1296					'raw' => true
1297				);
1298			break;
1299
1300			case 'ajax':
1301			case 'ajax_text':
1302			case 'ajax_xml';
1303			case 'ajax_json';
1304				$options = array(
1305					'messages' => false,
1306					'render' => false,
1307					'meta' => false,
1308					'return' => false,
1309					'raw' => false,
1310					'ajax' => str_replace(array('ajax_', 'ajax'), array('', 'text'), $return_type)
1311				);
1312			break;
1313
1314			case 'response':
1315				return $response;
1316			break;
1317
1318			case 'render':
1319			default:
1320				$options = array(
1321					'messages' => true,
1322					'render' => true,
1323					'meta' => false,
1324					'return' => false,
1325					'raw' => false
1326				);
1327			break;
1328		}
1329		return $response->send('default', $options);
1330	}
1331
1332	/**
1333	 * Proxy method
1334	 *
1335	 * @return string
1336	 */
1337	public function getHeader()
1338	{
1339		return $this->getController()->getHeader();
1340	}
1341
1342	/**
1343	 * Get current controller object
1344	 * @return e_admin_controller
1345	 */
1346	public function getController()
1347	{
1348		if(null === $this->_current_controller)
1349		{
1350			$this->_initController();
1351		}
1352		return $this->_current_controller;
1353	}
1354
1355	/**
1356	 * Try to init Controller from request using current controller map
1357	 *
1358	 * @return e_admin_dispatcher
1359	 */
1360	protected function _initController()
1361	{
1362		$request = $this->getRequest();
1363		$response = $this->getResponse();
1364		if(isset($this->modes[$request->getModeName()]) && isset($this->modes[$request->getModeName()]['controller']))
1365		{
1366			$class_name = $this->modes[$request->getModeName()]['controller'];
1367			$class_path = vartrue($this->modes[$request->getModeName()]['path']);
1368
1369			if($class_path)
1370			{
1371				require_once(e107::getParser()->replaceConstants($class_path));
1372			}
1373			if($class_name && class_exists($class_name))//NOTE: autoload in the play
1374			{
1375				$this->_current_controller = new  $class_name($request, $response);
1376				//give access to current request object, user defined init
1377				$this->_current_controller->setRequest($this->getRequest())->init();
1378			}
1379			// Known controller (found in e_admin_dispatcher::$modes), class not found exception
1380			else
1381			{
1382				// TODO - admin log
1383				// get default controller
1384				$this->_current_controller = $this->getDefaultController();
1385				// add messages
1386				e107::getMessage()->add('Can\'t find class <strong>&quot;'.($class_name ? $class_name : 'n/a').'&quot;</strong> for controller <strong>&quot;'.ucfirst($request->getModeName()).'&quot;</strong>', E_MESSAGE_ERROR)
1387					->add('Requested: '.e_SELF.'?'.$request->buildQueryString(), E_MESSAGE_DEBUG);
1388				//
1389				$request->setMode($this->getDefaultControllerName())->setAction('e404');
1390				$this->_current_controller->setRequest($request)->init();
1391			}
1392
1393			if(vartrue($this->modes[$request->getModeName()]['ui']))
1394			{
1395				$class_name = $this->modes[$request->getModeName()]['ui'];
1396				$class_path = vartrue($this->modes[$request->getModeName()]['uipath']);
1397				if($class_path)
1398				{
1399					require_once(e107::getParser()->replaceConstants($class_path));
1400				}
1401				if(class_exists($class_name))//NOTE: autoload in the play
1402				{
1403					$this->_current_controller->setParam('ui', new $class_name($this->_current_controller));
1404				}
1405			}
1406			$this->_current_controller->setParam('modes', $this->modes);
1407
1408		}
1409		// Not known controller (not found in e_admin_dispatcher::$modes) exception
1410		else
1411		{
1412			// TODO - admin log
1413			$this->_current_controller = $this->getDefaultController();
1414			// add messages
1415			e107::getMessage()->add('Can\'t find class for controller <strong>&quot;'.ucfirst($request->getModeName()).'&quot;</strong>', E_MESSAGE_ERROR)
1416				->add('Requested: '.e_SELF.'?'.$request->buildQueryString(), E_MESSAGE_DEBUG);
1417			// go to not found page
1418			$request->setMode($this->getDefaultControllerName())->setAction('e404');
1419			$this->_current_controller->setRequest($request)->init();
1420		}
1421
1422		return $this;
1423	}
1424
1425	/**
1426	 * Default controller object - needed if controller not found
1427	 * @return e_admin_controller
1428	 */
1429	public function getDefaultController()
1430	{
1431		$class_name = $this->getDefaultControllerName();
1432		return new $class_name($this->getRequest(), $this->getResponse());
1433	}
1434
1435	/**
1436	 *  Default controller name - needed if controller not found
1437	 * @return string name of controller
1438	 */
1439	public function getDefaultControllerName()
1440	{
1441		return 'e_admin_controller';
1442	}
1443
1444	/**
1445	 * Generic Admin Menu Generator
1446	 * @return string
1447	 */
1448	function renderMenu()
1449	{
1450		
1451		$tp = e107::getParser();
1452		$var = array();
1453		$selected = false;
1454		foreach($this->adminMenu as $key => $val)
1455		{
1456			$tmp = explode('/', trim($key, '/'), 3);
1457
1458			// sync with mode/route access
1459			if(!$this->checkModeAccess($tmp[0]) || !$this->checkRouteAccess($tmp[0].'/'.$tmp[1]))
1460			{
1461				continue;
1462			}
1463
1464			// custom 'selected' check
1465			if(isset($val['selected']) && $val['selected']) $selected = $val['selected'] === true ? $key : $val['selected'];
1466
1467			foreach ($val as $k=>$v)
1468			{
1469				switch($k)
1470				{
1471					case 'caption':
1472						$k2 = 'text';
1473						$v = defset($v, $v);
1474					break;
1475
1476					case 'url':
1477						$k2 = 'link';
1478						$v = $tp->replaceConstants($v, 'abs').'?mode='.$tmp[0].'&amp;action='.$tmp[1];
1479					break;
1480
1481					case 'uri':
1482						$k2 = 'link';
1483						$v = $tp->replaceConstants($v, 'abs');
1484					break;
1485
1486					default:
1487						$k2 = $k;
1488						
1489					break;
1490				}
1491
1492				
1493
1494				// Access check done above
1495				// if($val['perm']!= null) // check perms
1496				// {
1497					// if(getperms($val['perm']))
1498					// {
1499						// $var[$key][$k2] = $v;
1500					// }
1501				// }
1502				// else
1503				{
1504					$var[$key][$k2] = $v;
1505				
1506				}
1507
1508			}
1509		
1510			
1511			
1512			// TODO slide down menu options?
1513			if(!vartrue($var[$key]['link']))
1514			{
1515				$var[$key]['link'] = e_SELF.'?mode='.$tmp[0].'&amp;action='.$tmp[1]; // FIXME - URL based on $modes, remove url key
1516			}
1517
1518				
1519			if(varset($val['tab']))
1520			{
1521				$var[$key]['link'] .= "&amp;tab=".$val['tab'];	
1522			}
1523
1524			/*$var[$key]['text'] = $val['caption'];
1525			$var[$key]['link'] = (vartrue($val['url']) ? $tp->replaceConstants($val['url'], 'abs') : e_SELF).'?mode='.$tmp[0].'&action='.$tmp[1];
1526			$var[$key]['perm'] = $val['perm'];	*/
1527		}
1528		
1529		if(empty($var)) return '';
1530		
1531		$request = $this->getRequest();
1532		if(!$selected) $selected = $request->getMode().'/'.$request->getAction();
1533		$selected = vartrue($this->adminMenuAliases[$selected], $selected);
1534		return e107::getNav()->admin($this->menuTitle, $selected, $var);
1535	}
1536
1537
1538	/**
1539	 * Render Help Text in <ul> format. XXX TODO
1540	 */
1541	function renderHelp()
1542	{
1543		
1544		
1545		
1546	}
1547
1548	
1549	/** 
1550	 * Check for table issues and warn the user. XXX TODO 
1551	 * ie. user is using French interface but no french tables found for the current DB tables. 
1552	 */
1553	function renderWarnings()
1554	{
1555		
1556		
1557		
1558		
1559	}
1560	
1561
1562}
1563
1564class e_admin_controller
1565{
1566	/**
1567	 * @var e_admin_request
1568	 */
1569	protected $_request;
1570
1571	/**
1572	 * @var e_admin_response
1573	 */
1574	protected $_response;
1575
1576	/**
1577	 * @var array User defined parameters
1578	 */
1579	protected $_params = array();
1580
1581	/**
1582	 * @var string default action name
1583	 */
1584	protected $_default_action = 'index';
1585	
1586	/**
1587	 * List (numerical array) of only allowed for this controller actions
1588	 * Useful to grant access for certain pre-defined actions only
1589	 * XXX - we may move this in dispatcher (or even having it also there), still searching the most 'friendly' way
1590	 * @var array
1591	 */
1592	protected $allow = array();
1593	
1594	/**
1595	 * List (numerical array) of only disallowed for this controller actions
1596	 * Useful to restrict access for certain pre-defined actions only
1597	 * XXX - we may move this in dispatcher (or even having it also there), still searching the most 'friendly' way
1598	 * @var array
1599	 */
1600	protected $disallow = array();
1601
1602	/**
1603	 * Constructor
1604	 * @param e_admin_request $request [optional]
1605	 */
1606	public function __construct($request, $response, $params = array())
1607	{
1608		$this->_params = array_merge(array('enable_triggers' => false), $params);
1609		$this->setRequest($request)
1610			->setResponse($response)
1611			->setParams($params);
1612			
1613		$this->checkAccess();
1614	}
1615
1616	/**
1617	 * Check against allowed/disallowed actions
1618	 * FIXME check plugin admin access (check_class(P)), confirm e-token is verified
1619	 */
1620	public function checkAccess()
1621	{
1622		$request = $this->getRequest();
1623		$currentAction = $request->getAction();
1624
1625		// access based on mode setting - general controller access
1626		if(!empty($this->disallow) && in_array($currentAction, $this->disallow))
1627		{
1628			$request->setAction('e403');
1629			e107::getMessage()->addError('You don\'t have permissions to view this page.')
1630				->addDebug('Controller action disallowed restriction triggered.');
1631			return false;
1632		}
1633		
1634		// access based on $access settings - access per action
1635		if(!empty($this->allow) && !in_array($currentAction, $this->allow))
1636		{
1637			$request->setAction('e403');
1638			e107::getMessage()->addError('You don\'t have permissions to view this page.')
1639				->addDebug('Controller action not in allowed list restriction triggered.');
1640			return false;
1641		}
1642		return true;
1643	}
1644
1645	/**
1646	 * User defined init
1647	 * Called before dispatch routine
1648	 */
1649	public function init()
1650	{
1651	}
1652
1653	/**
1654	 * Get controller parameter
1655	 * Currently used core parameters:
1656	 * - enable_triggers: don't use it direct, see {@link setTriggersEnabled()}
1657	 * - modes - see dispatcher::$modes
1658	 * - ajax_response - text|xml|json - default is 'text'; this should be set by the action method
1659	 * - TODO - more parameters/add missing to this list
1660	 *
1661	 * @param string $key [optional] if null - get whole array
1662	 * @param mixed $default [optional]
1663	 * @return mixed
1664	 */
1665	public function getParam($key = null, $default = null)
1666	{
1667		if(null === $key)
1668		{
1669			return $this->_params;
1670		}
1671		return (isset($this->_params[$key]) ? $this->_params[$key] : $default);
1672	}
1673
1674	/**
1675	 * Set parameter
1676	 * @param string $key
1677	 * @param mixed $value
1678	 * @return e_admin_controller
1679	 */
1680	public function setParam($key, $value)
1681	{
1682		if(null === $value)
1683		{
1684			unset($this->_params[$key]);
1685			return $this;
1686		}
1687		$this->_params[$key] = $value;
1688		return $this;
1689	}
1690
1691	/**
1692	 * Merge passed parameter array with current parameters
1693	 * @param array $params
1694	 * @return e_admin_controller
1695	 */
1696	public function setParams($params)
1697	{
1698		$this->_params = array_merge($this->_params, $params);
1699		return $this;
1700	}
1701
1702	/**
1703	 * Reset parameter array
1704	 * @param array $params
1705	 * @return e_admin_controller
1706	 */
1707	public function resetParams($params)
1708	{
1709		$this->_params = $params;
1710		return $this;
1711	}
1712
1713	/**
1714	 * Get current request object
1715	 * @return e_admin_request
1716	 */
1717	public function getRequest()
1718	{
1719		return $this->_request;
1720	}
1721
1722	/**
1723	 * Set current request object
1724	 * @param e_admin_request $request
1725	 * @return e_admin_controller
1726	 */
1727	public function setRequest($request)
1728	{
1729		$this->_request = $request;
1730		return $this;
1731	}
1732
1733	/**
1734	 * Get current response object
1735	 * @return e_admin_response
1736	 */
1737	public function getResponse()
1738	{
1739		return $this->_response;
1740	}
1741
1742	/**
1743	 * Set current response object
1744	 * @param e_admin_response $response
1745	 * @return e_admin_controller
1746	 */
1747	public function setResponse($response)
1748	{
1749		$this->_response = $response;
1750		return $this;
1751	}
1752	
1753	/**
1754	 * Get current dispatcher object
1755	 * @return e_admin_dispatcher
1756	 */
1757	public function getDispatcher()
1758	{
1759		return e107::getRegistry('admin/ui/dispatcher');
1760	}
1761
1762	/**
1763	 * Request proxy method
1764	 * @param string $key [optional]
1765	 * @param mixed $default [optional]
1766	 * @return mixed
1767	 */
1768	public function getQuery($key = null, $default = null)
1769	{
1770		return $this->getRequest()->getQuery($key, $default);
1771	}
1772
1773	/**
1774	 * Request proxy method
1775	 * @param string|array $key
1776	 * @param mixed $value [optional]
1777	 * @return e_admin_controller
1778	 */
1779	public function setQuery($key, $value = null)
1780	{
1781		$this->getRequest()->setQuery($key, $value);
1782		return $this;
1783	}
1784
1785	/**
1786	 * Request proxy method
1787	 * @param string $key [optional]
1788	 * @param mixed $default [optional]
1789	 * @return mixed
1790	 */
1791	public function getPosted($key = null, $default = null)
1792	{
1793		return $this->getRequest()->getPosted($key, $default);
1794	}
1795
1796	/**
1797	 * Request proxy method
1798	 * @param string $key
1799	 * @param mixed $value [optional]
1800	 * @return e_admin_controller
1801	 */
1802	public function setPosted($key, $value = null)
1803	{
1804		$this->getRequest()->setPosted($key, $value);
1805		return $this;
1806	}
1807
1808	/**
1809	 * Add page title, response proxy method
1810	 *
1811	 * @param string $title if boolean true - current menu caption will be used
1812	 * @param boolean $meta add to meta as well
1813	 * @return e_admin_controller
1814	 */
1815	public function addTitle($title = true, $meta = true)
1816	{
1817		if(true === $title)
1818		{
1819			$_dispatcher = $this->getDispatcher();
1820			$data = $_dispatcher->getPageTitles();
1821			$search = $this->getMode().'/'.$this->getAction();
1822			if(isset($data[$search])) $res['caption'] = $data[$search];
1823			else 
1824			{
1825				$data = $_dispatcher->getMenuData();
1826				if(isset($data[$search])) $res = $data[$search];
1827				else return $this;
1828			}
1829			$title = $res['caption'];
1830		}
1831	//	print_a($title);
1832		$this->getResponse()->appendTitle($title);
1833		if($meta) $this->addMetaTitle($title);
1834		return $this;
1835	}
1836
1837	/**
1838	 * Add page meta title, response proxy method.
1839	 * Should be called before header.php
1840	 *
1841	 * @param string $title
1842	 * @return e_admin_controller
1843	 */
1844	public function addMetaTitle($title)
1845	{
1846		$this->getResponse()->addMetaTitle($title);
1847		return $this;
1848	}
1849
1850	/**
1851	 * Add header content, response proxy method
1852	 * Should be called before header.php
1853	 *
1854	 * @param string $content
1855	 * @return e_admin_controller
1856	 */
1857	public function addHeader($content)
1858	{
1859		$this->getResponse()->addHeaderContent(vartrue($content));
1860		return $this;
1861	}
1862
1863	/**
1864	 * Get header content, response proxy method
1865	 *
1866	 * @return string
1867	 */
1868	public function getHeader()
1869	{
1870		return $this->getResponse()->getHeaderContent();
1871	}
1872
1873	/**
1874	 * Get current mode, response proxy method
1875	 * @return string
1876	 */
1877	public function getMode()
1878	{
1879		return $this->getRequest()->getMode();
1880	}
1881
1882	/**
1883	 * Get current actin, response proxy method
1884	 * @return string
1885	 */
1886	public function getAction()
1887	{
1888		return $this->getRequest()->getAction();
1889	}
1890
1891	/**
1892	 * Get current ID, response proxy method
1893	 * @return string
1894	 */
1895	public function getId()
1896	{
1897		return $this->getRequest()->getId();
1898	}
1899
1900	/**
1901	 * Get response owned JS Helper instance, response proxy method
1902	 *
1903	 * @return e_jshelper
1904	 */
1905	public function getJsHelper()
1906	{
1907		return $this->getResponse()->getJsHelper();
1908	}
1909
1910	protected function _preDispatch($action = '')
1911	{
1912		if(!$action) $action = $this->getRequest()->getActionName();
1913		$method = $this->toMethodName($action, 'page');
1914		if(!method_exists($this, $method))
1915		{
1916			$this->getRequest()->setAction($this->getDefaultAction());
1917		}
1918
1919		// switch to 404 if needed
1920		$method = $this->toMethodName($this->getRequest()->getActionName(), 'page');
1921		if(!method_exists($this, $method))
1922		{
1923			$this->getRequest()->setAction('e404');
1924			$message = e107::getParser()->lanVars(LAN_UI_404_METHOD_ERROR, $method, true);
1925			e107::getMessage()->add($message, E_MESSAGE_ERROR);
1926		}
1927	}
1928
1929	/**
1930	 * Dispatch observer, check for triggers
1931	 *
1932	 * @param string $action [optional]
1933	 * @return e_admin_controller
1934	 */
1935	public function dispatchObserver($action = null)
1936	{
1937		$request = $this->getRequest();
1938		if(null === $request)
1939		{
1940			$request = new e_admin_request();
1941			$this->setRequest($request);
1942		}
1943
1944		$this->_preDispatch($action);
1945		if(null === $action)
1946		{
1947			$action = $request->getActionName();
1948		}
1949
1950		// check for observer
1951		$actionObserverName = $this->toMethodName($action, 'observer', e_AJAX_REQUEST);
1952		if(method_exists($this, $actionObserverName))
1953		{
1954			$this->$actionObserverName();
1955		}
1956
1957		// check for triggers, not available in Ajax mode
1958		if(!e_AJAX_REQUEST && $this->triggersEnabled())
1959		{
1960			$posted = $request->getPosted();
1961			foreach ($posted as $key => $value)
1962			{
1963				if(strpos($key, 'etrigger_') === 0)
1964				{
1965					$actionTriggerName = $this->toMethodName($action.$request->camelize(substr($key, 9)), 'trigger', false);
1966					if(method_exists($this, $actionTriggerName))
1967					{
1968						$this->$actionTriggerName($value);
1969					}
1970					//Check if triggers are still enabled
1971					if(!$this->triggersEnabled())
1972					{
1973						break;
1974					}
1975				}
1976			}
1977		}
1978
1979		return $this;
1980	}
1981
1982	/**
1983	 * Dispatch header, not allowed in Ajax mode
1984	 * @param string $action [optional]
1985	 * @return e_admin_controller
1986	 */
1987	public function dispatchHeader($action = null)
1988	{
1989		// not available in Ajax mode
1990		if(e_AJAX_REQUEST)
1991		{
1992			return $this;
1993		}
1994
1995		$request = $this->getRequest();
1996		if(null === $request)
1997		{
1998			$request = new e_admin_request();
1999			$this->setRequest($request);
2000		}
2001
2002		$this->_preDispatch($action);
2003		if(null === $action)
2004		{
2005			$action = $request->getActionName();
2006		}
2007
2008		// check for observer
2009		$actionHeaderName = $this->toMethodName($action, 'header', false);
2010		if(method_exists($this, $actionHeaderName))
2011		{
2012			$this->$actionHeaderName();
2013		}
2014
2015		//send meta data
2016		$this->getResponse()->sendMeta();
2017		return $this;
2018	}
2019
2020	/**
2021	 * Dispatch controller action
2022	 *
2023	 * @param string $action [optional]
2024	 * @return e_admin_response
2025	 */
2026	public function dispatchPage($action = null)
2027	{
2028		$request = $this->getRequest();
2029		if(null === $request)
2030		{
2031			$request = new e_admin_request();
2032			$this->setRequest($request);
2033		}
2034		$response = $this->getResponse();
2035		$this->_preDispatch($action);
2036
2037		if(null === $action)
2038		{
2039			$action = $request->getActionName();
2040		}
2041
2042		// check for observer
2043		$actionName = $this->toMethodName($action, 'page');
2044		$ret = '';
2045		if(!method_exists($this, $actionName)) // pre dispatch already switched to default action/not found page if needed
2046		{
2047			e107::getMessage()->add('Action '.$actionName.' no found!', E_MESSAGE_ERROR);
2048			return $response;
2049		}
2050		ob_start(); //catch any output
2051		$ret = $this->{$actionName}();
2052
2053
2054		//Ajax XML/JSON communication
2055		if(e_AJAX_REQUEST && is_array($ret))
2056		{
2057			$response_type = $this->getParam('ajax_response', 'xml');
2058			ob_clean();
2059			$js_helper = $response->getJsHelper();
2060			foreach ($ret as $act => $data)
2061			{
2062				$js_helper->addResponse($data, $act);
2063			}
2064			$js_helper->sendResponse($response_type);
2065		}
2066
2067		$ret .= ob_get_clean();
2068
2069		// Ajax text response
2070		if(e_AJAX_REQUEST)
2071		{
2072			$response_type = 'text';
2073			$response->getJsHelper()->addResponse($ret)->sendResponse($response_type);
2074		}
2075		else
2076		{
2077			$response->appendBody($ret);
2078		}
2079
2080		return $response;
2081	}
2082
2083	public function E404Observer()
2084	{
2085		$this->getResponse()->setTitle(LAN_UI_404_TITLE_ERROR);
2086	}
2087
2088	public function E404Page()
2089	{
2090		return '<div class="center">'.LAN_UI_404_BODY_ERROR.'</div>'; // TODO - lan
2091	}
2092
2093
2094	public function E404AjaxPage()
2095	{
2096		exit;
2097	}
2098	
2099
2100	public function E403Observer()
2101	{
2102		$this->getResponse()->setTitle(LAN_UI_403_TITLE_ERROR);
2103	}
2104
2105	public function E403Page()
2106	{
2107		return '<div class="center">'.LAN_UI_403_BODY_ERROR.'</div>'; // TODO - lan
2108	}
2109
2110
2111	public function E403AjaxPage()
2112	{
2113		exit;
2114	}
2115
2116	/**
2117	 * Generic redirect handler, it handles almost everything we would need.
2118	 * Additionally, it moves currently registered system messages to SESSION message stack
2119	 * In almost every case {@link redirectAction()} and {@link redirectMode()} are better solution
2120	 *
2121	 * @param string $action defaults to current action
2122	 * @param string $mode defaults to current mode
2123	 * @param string|array $exclude_query comma delimited variable names to be excluded from current query OR TRUE to exclude everything
2124	 * @param string|array $merge_query query string (&amp; delimiter) or associative array to be merged with current query
2125	 * @param string $path default to e_SELF
2126	 * @return void
2127	 */
2128	public function redirect($action = null, $mode = null, $exclude_query = '', $merge_query = array(), $path = null)
2129	{
2130		$request = $this->getRequest();
2131
2132		if($mode) $request->setMode($mode);
2133		if($action) $request->setAction($action);
2134		if(!$path) $path = e_SELF;
2135		
2136		//prevent cache
2137		header('Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
2138	//	header('Pragma: no-cache');
2139
2140		$url = $path.'?'.$request->buildQueryString($merge_query, false, $exclude_query);
2141		// Transfer all messages to session
2142		e107::getMessage()->moveToSession();
2143		// write session data
2144		session_write_close();
2145
2146		// do redirect
2147		header('Location: '.$url);
2148		exit;
2149	}
2150
2151	/**
2152	 * Convenient redirect() proxy method, make life easier when redirecting between actions
2153	 * in same mode.
2154	 *
2155	 * @param string $action [optional]
2156	 * @param string|array $exclude_query [optional]
2157	 * @param string|array $merge_query [optional]
2158	 * @return none
2159	 */
2160	public function redirectAction($action = null, $exclude_query = '', $merge_query = array())
2161	{
2162		$this->redirect($action, null, $exclude_query, $merge_query);
2163	}
2164
2165	/**
2166	 * Convenient redirect to another mode (doesn't use current Query state)
2167	 * If path is empty, it'll be auto-detected from modes (dispatcher) array
2168	 *
2169	 * @param string $mode
2170	 * @param string $action
2171	 * @param string|array $query [optional]
2172	 * @param string $path
2173	 * @return void
2174	 */
2175	public function redirectMode($mode, $action, $query = array(), $path = null)
2176	{
2177		if(!$path && $this->getParam('modes'))
2178		{
2179			$modes = $this->getParam('modes');
2180			if(vartue($modes[$mode]) && vartrue($modes[$mode]['url']))
2181			{
2182				$path = e107::getParser()->replaceConstants($modes[$mode]['url'], 'abs');
2183			}
2184		}
2185		$this->redirect($action, $mode, true, $query, $path);
2186	}
2187
2188	/**
2189	 * Convert action name to method name
2190	 *
2191	 * @param string $action_name formatted (e.g. request method getActionName()) action name
2192	 * @param string $type page|observer|header|trigger
2193	 * @param boolean $ajax force with true/false, if null will be auto-resolved
2194	 * @return string
2195	 */
2196	public function toMethodName($action_name, $type= 'page', $ajax = null)
2197	{
2198		if(null === $ajax) $ajax = e_AJAX_REQUEST; //auto-resolving
2199		return $action_name.($ajax ? 'Ajax' : '').ucfirst(strtolower($type));
2200	}
2201
2202	/**
2203	 * Check if there is a trigger available in the posted data
2204	 * @param array $exclude
2205	 * @return boolean
2206	 */
2207	public function hasTrigger($exclude = array())
2208	{
2209		$posted = array_keys($this->getPosted());
2210		foreach ($posted as $key)
2211		{
2212			if(!in_array($key, $exclude) && strpos($key, 'etrigger_') === 0)
2213			{
2214				return true;
2215			}
2216		}
2217		return false;
2218	}
2219
2220	/**
2221	 * Get default action
2222	 * @return string action
2223	 */
2224	public function getDefaultAction()
2225	{
2226		return $this->_default_action;
2227	}
2228
2229	/**
2230	 * Set default action
2231	 * @param string $action_name
2232	 * @return e_admin_controller
2233	 */
2234	public function setDefaultAction($action_name)
2235	{
2236		$this->_default_action = $action_name;
2237		return $this;
2238	}
2239
2240	/**
2241	 * @return boolean
2242	 */
2243	public function triggersEnabled()
2244	{
2245		return $this->getParam('enable_triggers');
2246	}
2247
2248	/**
2249	 * @param boolean $flag
2250	 * @return e_admin_controller
2251	 */
2252	public function setTriggersEnabled($flag)
2253	{
2254		$this->setParam('enable_triggers', $flag);
2255		return $this;
2256	}
2257}
2258
2259//FIXME - move everything from e_admin_ui except model auto-create related code
2260class e_admin_controller_ui extends e_admin_controller
2261{
2262	/**
2263	 * @var array UI field data
2264	 */
2265	protected $fields = array();
2266
2267	/**
2268	 * @var array default fields activated on List view
2269	 */
2270	protected $fieldpref = array();
2271
2272	/**
2273	 * @var array Plugin Preference description array
2274	 */
2275	protected $prefs = array();
2276
2277	/**
2278	 * Data required for _modifyListQry() to automate
2279	 * db query building
2280	 * @var array
2281	 */
2282	protected $tableJoin = array(); 
2283
2284	/**
2285	 * Array of table names and their a…

Large files files are truncated, but you can click here to view the full file