Webylon 3.2 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • 1c
    • exchange
      • catalog
  • auth
  • Booking
  • building
    • company
  • cart
    • shipping
    • steppedcheckout
  • Catalog
    • monument
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • Announcement_Controller
  • AnnouncementHolder_Controller
  • BookingAdminPage_Controller
  • BookingPage_Controller
  • Cart_Controller
  • CartPage_Controller
  • Catalog_Controller
  • CheckoutPage_Controller
  • ChequePayment_Handler
  • ContactsPage_Controller
  • ContentController
  • ContentNegotiator
  • Controller
  • DataObjectManager_Controller
  • DatePickerField_Controller
  • Director
  • DocPage_Controller
  • DocumentsPage_Controller
  • Event_Controller
  • EventHolder_Controller
  • FavoritePage_Controller
  • FileDataObjectManager_Controller
  • FindCyrillic_Controller
  • HomePage_Controller
  • Import1C_Controller
  • ImportCatalog1C_Controller
  • LastDoc_Controller
  • LiveCalendarWidget_Controller
  • MapObject_Controller
  • MapObjectGroup_Controller
  • MapPage_Controller
  • MediawebPage_Controller
  • ModelAsController
  • Monument_Controller
  • MonumentCatalog_Controller
  • MonumentForm_Controller
  • MultiUploadControls
  • NewsArchive_Controller
  • NewsEntry_Controller
  • NewsHolder_Controller
  • Orders1CExchange_Controller
  • Page_Controller
  • Payment_Handler
  • PhotoAlbumManager_Controller
  • Product_Controller
  • ProductSearchPage_Controller
  • ProfilePage_Controller
  • PublHolder_Controller
  • Publication_Controller
  • RatingExtension_Controller
  • RegistrationPage_Controller
  • RemoveOrphanedPagesTask
  • RequestHandler
  • Room_Controller
  • RoomCatalog_Controller
  • RootURLController
  • SapphireInfo
  • Search_Controller
  • Session
  • SimpleOrderPage_Controller
  • SiteMap_Controller
  • Socle_Controller
  • SocleSize_Controller
  • SpecialCatalog_Controller
  • SS_HTTPRequest
  • SS_HTTPResponse
  • StartCatalog_Controller
  • SubsitesSelectorPage_Controller
  • VideoBankPage_Controller

Interfaces

  • NestedController

Exceptions

  • SS_HTTPResponse_Exception
  1 <?php
  2 /**
  3  * Base controller class.
  4  * Controllers are the cornerstone of all site functionality in Sapphire.  The {@link Director}
  5  * selects a controller to pass control to, and then calls {@link run()}.  This method will execute
  6  * the appropriate action - either by calling the action method, or displaying the action's template.
  7  *
  8  * See {@link getTemplate()} for information on how the template is chosen.
  9  * @package sapphire
 10  * @subpackage control
 11  */
 12 class Controller extends RequestHandler {
 13 
 14     /**
 15      * @var array $urlParams An array of arguments extracted from the URL 
 16      */
 17     protected $urlParams;
 18     
 19     /**
 20      * @var array $requestParams Contains all GET and POST parameters
 21      * passed to the current {@link SS_HTTPRequest}.
 22      * @uses SS_HTTPRequest->requestVars()
 23      */
 24     protected $requestParams;
 25     
 26     /**
 27      * @var string $action The URL part matched on the current controller as
 28      * determined by the "$Action" part of the {@link $url_handlers} definition.
 29      * Should correlate to a public method on this controller.
 30      * Used in {@link render()} and {@link getViewer()} to determine
 31      * action-specific templates.
 32      */
 33     protected $action;
 34     
 35     /**
 36      * The {@link Session} object for this controller
 37      */
 38     protected $session;
 39 
 40     /**
 41      * Stack of current controllers.
 42      * Controller::$controller_stack[0] is the current controller.
 43      */
 44     protected static $controller_stack = array();
 45     
 46     protected $basicAuthEnabled = true;
 47 
 48     /**
 49      * @var SS_HTTPResponse $response The response object that the controller returns.
 50      * Set in {@link handleRequest()}.
 51      */
 52     protected $response;
 53     
 54     /**
 55      * @var SS_HTTPRequest $request The request object that the controller was called with.
 56      * Set in {@link handleRequest()}. Useful to generate the {}
 57      */
 58     protected $request;
 59     
 60     /**
 61      * Default URL handlers - (Action)/(ID)/(OtherID)
 62      */
 63     static $url_handlers = array(
 64         '$Action//$ID/$OtherID' => 'handleAction',
 65     );
 66     
 67     static $allowed_actions = array(
 68         'handleAction',
 69         'handleIndex',
 70     );
 71     
 72     /**
 73      * Initialisation function that is run before any action on the controller is called.
 74      * 
 75      * @uses BasicAuth::requireLogin()
 76      */
 77     function init() {
 78         if($this->basicAuthEnabled) BasicAuth::protect_site_if_necessary();
 79 
 80         // Directly access the session variable just in case the Group or Member tables don't yet exist
 81         if(Session::get('loggedInAs') && Security::database_is_ready()) {
 82             $member = Member::currentUser();
 83             if($member) {
 84                 Cookie::set("PastMember", true, 90, null, null, false, true);
 85                 DB::query("UPDATE \"Member\" SET \"LastVisited\" = " . DB::getConn()->now() . " WHERE \"ID\" = $member->ID", null);
 86             }
 87         }
 88         
 89         // This is used to test that subordinate controllers are actually calling parent::init() - a common bug
 90         $this->baseInitCalled = true;
 91     }
 92     
 93     /**
 94      * Executes this controller, and return an {@link SS_HTTPResponse} object with the result.
 95      * 
 96      * This method first does a few set-up activities:
 97      *  - Push this controller ont to the controller stack - 
 98      *    see {@link Controller::curr()} for information about this.
 99      *  - Call {@link init()}
100      *  - Defer to {@link RequestHandler->handleRequest()} to determine which action
101      *    should be executed
102      * 
103      * Note: $requestParams['executeForm'] support was removed, 
104      * make the following change in your URLs: 
105      * "/?executeForm=FooBar" -> "/FooBar" 
106      * Also make sure "FooBar" is in the $allowed_actions of your controller class.
107      * 
108      * Note: You should rarely need to overload run() - 
109      * this kind of change is only really appropriate for things like nested
110      * controllers - {@link ModelAsController} and {@link RootURLController} 
111      * are two examples here.  If you want to make more
112      * orthodox functionality, it's better to overload {@link init()} or {@link index()}.
113      * 
114      * Important: If you are going to overload handleRequest, 
115      * make sure that you start the method with $this->pushCurrent()
116      * and end the method with $this->popCurrent().  
117      * Failure to do this will create weird session errors.
118      * 
119      * @param $request The {@link SS_HTTPRequest} object that is responsible 
120      *  for distributing request parsing.
121      * @return SS_HTTPResponse The response that this controller produces, 
122      *  including HTTP headers such as redirection info
123      */
124     function handleRequest(SS_HTTPRequest $request) {
125         if(!$request) user_error("Controller::handleRequest() not passed a request!", E_USER_ERROR);
126         
127         $this->pushCurrent();
128         $this->urlParams = $request->allParams();
129         $this->request = $request;
130         $this->response = new SS_HTTPResponse();
131         
132         $this->extend('onBeforeInit');
133 
134         // Init
135         $this->baseInitCalled = false;  
136         $this->init();
137         if(!$this->baseInitCalled) user_error("init() method on class '$this->class' doesn't call Controller::init().  Make sure that you have parent::init() included.", E_USER_WARNING);
138 
139         $this->extend('onAfterInit');
140         
141         // If we had a redirection or something, halt processing.
142         if($this->response->isFinished()) {
143             $this->popCurrent();
144             return $this->response;
145         }
146 
147         $body = parent::handleRequest($request);
148         if($body instanceof SS_HTTPResponse) {
149             if(isset($_REQUEST['debug_request'])) Debug::message("Request handler returned SS_HTTPResponse object to $this->class controller; returning it without modification.");
150             $this->response = $body;
151             
152         } else {
153             if(is_object($body)) {
154                 if(isset($_REQUEST['debug_request'])) Debug::message("Request handler $body->class object to $this->class controller;, rendering with template returned by $body->class::getViewer()");
155                $body = $body->getViewer($request->latestParam('Action'))->process($body);
156             }
157             
158             $this->response->setBody($body);
159         }
160 
161 
162         ContentNegotiator::process($this->response);
163         HTTP::add_cache_headers($this->response);
164 
165         $this->popCurrent();
166         return $this->response;
167     }
168 
169     /**
170      * Controller's default action handler.  It will call the method named in $Action, if that method exists.
171      * If $Action isn't given, it will use "index" as a default.
172      */
173     public function handleAction($request) {
174         // urlParams, requestParams, and action are set for backward compatability 
175         foreach($request->latestParams() as $k => $v) {
176             if($v || !isset($this->urlParams[$k])) $this->urlParams[$k] = $v;
177         }
178 
179         $this->action = str_replace("-","_",$request->param('Action'));
180         $this->requestParams = $request->requestVars();
181         if(!$this->action) $this->action = 'index';
182         
183         if(!$this->hasAction($this->action)) {
184             $this->httpError(404, "The action '$this->action' does not exist in class $this->class");
185         }
186         
187         // run & init are manually disabled, because they create infinite loops and other dodgy situations 
188         if(!$this->checkAccessAction($this->action) || in_array(strtolower($this->action), array('run', 'init'))) {
189             return $this->httpError(403, "Action '$this->action' isn't allowed on class $this->class");
190         }
191         
192         if($this->hasMethod($this->action)) {
193             $result = $this->{$this->action}($request);
194             
195             // If the action returns an array, customise with it before rendering the template.
196             if(is_array($result)) {
197                 return $this->getViewer($this->action)->process($this->customise($result));
198             } else {
199                 return $result;
200             }
201         } else {
202             return $this->getViewer($this->action)->process($this);
203         }
204     }
205 
206     function setURLParams($urlParams) {
207         $this->urlParams = $urlParams;
208     }
209     
210     /**
211      * @return array The parameters extracted from the URL by the {@link Director}.
212      */
213     function getURLParams() {
214         return $this->urlParams;
215     }
216     
217     /**
218      * Returns the SS_HTTPResponse object that this controller is building up.
219      * Can be used to set the status code and headers
220      */
221     function getResponse() {
222         return $this->response;
223     }
224     
225     /**
226      * Get the request with which this controller was called (if any).
227      * Usually set in {@link handleRequest()}.
228      *
229      * @return SS_HTTPRequest
230      */
231     function getRequest() {
232         return $this->request;
233     }
234 
235     protected $baseInitCalled = false;
236 
237     /**
238      * Return the object that is going to own a form that's being processed, and handle its execution.
239      * Note that the result needn't be an actual controller object.
240      */
241     function getFormOwner() {
242         // Get the appropraite ocntroller: sometimes we want to get a form from another controller
243         if(isset($this->requestParams['formController'])) {
244             $formController = Director::getControllerForURL($this->requestParams['formController']);
245 
246             while(is_a($formController, 'NestedController')) {
247                 $formController = $formController->getNestedController();
248             }
249             return $formController;
250 
251         } else {
252             return $this;
253         }
254     }
255 
256     /**
257      * This is the default action handler used if a method doesn't exist.
258      * It will process the controller object with the template returned by {@link getViewer()}
259      */
260     function defaultAction($action) {
261         return $this->getViewer($action)->process($this);
262     }
263 
264     /**
265      * Returns the action that is being executed on this controller.
266      */
267     function getAction() {
268         return $this->action;
269     }
270 
271     /**
272      * Return an SSViewer object to process the data
273      * @return SSViewer The viewer identified being the default handler for this Controller/Action combination
274      */
275     function getViewer($action) {
276         // Hard-coded templates
277         if($this->templates[$action]) {
278             $templates = $this->templates[$action];
279         }   else if($this->templates['index']) {
280             $templates = $this->templates['index'];
281         }   else if($this->template) {
282             $templates = $this->template;
283         } else {
284             // Add action-specific templates for inheritance chain
285             $parentClass = $this->class;
286             if($action && $action != 'index') {
287                 $parentClass = $this->class;
288                 while($parentClass != "Controller") {
289                     $template = strtok($parentClass,'_') . '_' . $action;
290                     if ($this->isAjax()) {
291                         $templates[] = $template . '_ajax';
292                     }
293                     $templates[] = $template;
294                     $parentClass = get_parent_class($parentClass);
295                 }
296             }
297             // Add controller templates for inheritance chain
298             $parentClass = $this->class;
299             while($parentClass != "Controller") {
300                 $template = strtok($parentClass,'_');
301                 if ($this->isAjax()) {
302                     $templates[] = $template . '_ajax';
303                 }
304                 $templates[] = $template;
305                 $parentClass = get_parent_class($parentClass);
306             }
307 
308             // remove duplicates
309             $templates = array_unique($templates);
310         }
311         return new SSViewer($templates);
312     }
313     
314     public function hasAction($action) {
315         return parent::hasAction($action) || $this->hasActionTemplate($action);
316     }
317     
318     /**
319      * Returns TRUE if this controller has a template that is specifically designed to handle a specific action.
320      *
321      * @param string $action
322      * @return bool
323      */
324     public function hasActionTemplate($action) {
325         if(isset($this->templates[$action])) return true;
326         
327         $parentClass = $this->class;
328         $templates   = array();
329         
330         while($parentClass != 'Controller') {
331             $templates[] = strtok($parentClass, '_') . '_' . $action;
332             $parentClass = get_parent_class($parentClass);
333         }
334         
335         return SSViewer::hasTemplate($templates);
336     }
337     
338     /**
339      * Render the current controller with the templates determined
340      * by {@link getViewer()}.
341      * 
342      * @param array $params Key-value array for custom template variables (Optional)
343      * @return string Parsed template content 
344      */
345     function render($params = null) {
346         $template = $this->getViewer($this->getAction());
347     
348         // if the object is already customised (e.g. through Controller->run()), use it
349         $obj = ($this->customisedObj) ? $this->customisedObj : $this;
350     
351         if($params) $obj = $this->customise($params);
352         
353         return $template->process($obj);
354     }
355   
356     /**
357      * Call this to disable site-wide basic authentication for a specific contoller.
358      * This must be called before Controller::init().  That is, you must call it in your controller's
359      * init method before it calls parent::init().
360      */
361     function disableBasicAuth() {
362         $this->basicAuthEnabled = false;
363     }
364 
365     /**
366      * Returns the current controller
367      * @returns Controller
368      */
369     public static function curr() {
370         if(Controller::$controller_stack) {
371             return Controller::$controller_stack[0];
372         } else {
373             user_error("No current controller available", E_USER_WARNING);
374         }
375     }
376     
377     /**
378      * Tests whether we have a currently active controller or not
379      * @return boolean True if there is at least 1 controller in the stack.
380      */
381     public static function has_curr() {
382         return Controller::$controller_stack ? true : false;
383     }
384 
385     /**
386      * Returns true if the member is allowed to do the given action.
387      * @param perm The permission to be checked, such as 'View'.
388      * @param member The member whose permissions need checking.  Defaults to the currently logged
389      * in user.
390      * @return boolean
391      */
392     function can($perm, $member = null) {
393         if(!$member) $member = Member::currentUser();
394         if($this->hasMethod($methodName = 'can' . $perm)) {
395             return $this->$methodName($member);
396         } else {
397             return true;
398         }
399     }
400 
401     //-----------------------------------------------------------------------------------
402 
403     /**
404      * returns a date object for use within a template
405      * Usage: $Now.Year - Returns 2006
406      * @return Date The current date
407      */
408     function Now() {
409         $d = new Date(null);
410         $d->setValue(date("Y-m-d h:i:s"));
411         return $d;
412     }
413 
414     /**
415      * Returns the currently logged in user
416      */
417     function CurrentMember() {
418         return Member::currentUser();
419     }
420 
421     /**
422      * Returns true if the visitor has been here before
423      * @return boolean
424      */
425     function PastVisitor() {
426         user_error("Controller::PastVisitor() is deprecated", E_USER_NOTICE);
427         return false;
428     }
429 
430     /**
431      * Return true if the visitor has signed up for a login account before
432      * @return boolean
433      */
434     function PastMember() {
435         return Cookie::get("PastMember") ? true : false;
436     }
437 
438     /**
439      * Pushes this controller onto the stack of current controllers.
440      * This means that any redirection, session setting, or other things that rely on Controller::curr() will now write to this
441      * controller object.
442      */
443     function pushCurrent() {
444         array_unshift(self::$controller_stack, $this);
445         // Create a new session object
446         if(!$this->session) {
447             if(isset(self::$controller_stack[1])) {
448                 $this->session = self::$controller_stack[1]->getSession();
449             } else {
450                 $this->session = new Session(Session::get_all());
451             }
452         }
453     }
454 
455     /**
456      * Pop this controller off the top of the stack.
457      */
458     function popCurrent() {
459         if($this === self::$controller_stack[0]) {
460             array_shift(self::$controller_stack);
461         } else {
462             user_error("popCurrent called on $this->class controller, but it wasn't at the top of the stack", E_USER_WARNING);
463         }
464     }
465     
466     /**
467      * Redirct to the given URL.
468      * It is generally recommended to call Director::redirect() rather than calling this function directly.
469      */
470     function redirect($url, $code=302) {
471         if($this->response->getHeader('Location')) {
472             user_error("Already directed to " . $this->response->getHeader('Location') . "; now trying to direct to $url", E_USER_WARNING);
473             return;
474         }
475 
476         // Attach site-root to relative links, if they have a slash in them
477         if($url == "" || $url[0] == '?' || (substr($url,0,4) != "http" && $url[0] != "/" && strpos($url,'/') !== false)){
478             $url = Director::baseURL() . $url;
479         }
480 
481         $this->response->redirect($url, $code);
482     }
483     
484     /**
485      * Redirect back. Uses either the HTTP_REFERER or a manually set request-variable called
486      * _REDIRECT_BACK_URL.
487      * This variable is needed in scenarios where not HTTP-Referer is sent (
488      * e.g when calling a page by location.href in IE).
489      * If none of the two variables is available, it will redirect to the base
490      * URL (see {@link Director::baseURL()}).
491      * @uses redirect()
492      */
493     function redirectBack() {
494         if($this->request->requestVar('_REDIRECT_BACK_URL')) {
495             $url = $this->request->requestVar('_REDIRECT_BACK_URL');
496         } else if($this->request->getHeader('Referer')) {
497             $url = $this->request->getHeader('Referer');
498         } else {
499             $url = Director::baseURL();
500         }
501 
502         // absolute redirection URLs not located on this site may cause phishing
503         if(Director::is_site_url($url)) {
504             return $this->redirect($url);
505         } else {
506             return false;
507         }
508 
509     }
510     
511     /**
512      * Tests whether a redirection has been requested.
513      * @return string If redirect() has been called, it will return the URL redirected to.  Otherwise, it will return null;
514      */
515     function redirectedTo() {
516         return $this->response->getHeader('Location');
517     } 
518     
519     /**
520      * Get the Session object representing this Controller's session
521      * @return Session
522      */
523     function getSession() {
524         return $this->session;
525     }
526     
527     /**
528      * Set the Session object.
529      */
530     function setSession(Session $session) {
531         $this->session = $session;
532     }
533     
534     /**
535      * Returns true if this controller is processing an ajax request
536      * @return boolean True if this controller is processing an ajax request
537      */
538     function isAjax() {
539         return (
540             isset($this->requestParams['ajax']) || isset($_REQUEST['ajax']) ||
541             (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == "XMLHttpRequest")
542         );
543     }
544     
545     /**
546      * Joins two or more link segments together, putting a slash between them if necessary.
547      * Use this for building the results of {@link Link()} methods.
548      * If either of the links have query strings, 
549      * then they will be combined and put at the end of the resulting url.
550      * 
551      * Caution: All parameters are expected to be URI-encoded already.
552      * 
553      * @param String 
554      * @return String
555      */
556     static function join_links() {
557         $args = func_get_args();
558         $result = "";
559         $querystrings = array();
560         foreach($args as $arg) {
561             if(strpos($arg,'?') !== false) {
562                 list($arg, $suffix) = explode('?',$arg,2);
563                 $querystrings[] = $suffix;
564             }
565             if($arg) {
566                 if($result && substr($result,-1) != '/' && $arg[0] != '/') $result .= "/$arg";
567                 else $result .= (substr($result, -1) == '/' && $arg[0] == '/') ? ltrim($arg, '/') : $arg;
568             }
569         }
570         
571         if($querystrings) $result .= '?' . implode('&', $querystrings);
572         
573         return $result;
574     }
575 }
576 
577 ?>
578 
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -
Webylon 3.2 API Docs API documentation generated by ApiGen 2.8.0