/** * Dispatch an URL to the correct handlers. This method does the actual * magic, such as url parsing, matching and command invocation. You can * optionally provide a custom url and tell the dispatcher that some parts * of the url should be skipped when handling this request. * * \param $url * The url to dispatch (optional, defaults to null). Omit this value (or * provide null) to use the current request url. * * \param $skip_path_components * The number of path components to skip when handling this request * (optional, defaults to null). This is useful if you want to skip some * prefix present in all urls, such as ~username. If you don't specify * this parameter the value of <code>$_SERVER['PHP_SELF']</code> will be * used to figure out how many components to skip. */ function dispatch($url = null, $skip_path_components = null) { if (is_null($skip_path_components)) { /* Figure out the current script location. This is most likely * the script living in the document root calling this method. Use * the directory path component of this file to figure out how many * path components should be skipped. */ $dir_url = dirname($_SERVER['PHP_SELF']); if ($dir_url == DIRECTORY_SEPARATOR) { $skip_path_components = 0; } else { $skip_path_components = count(explode('/', str_strip_prefix($dir_url, '/'))); } } /* Initialization */ $get_params = ''; /* Use the current url if no explicit url was given */ if (is_null($url)) { $url = Request::relative_url(); } /* We need to strip off the GET parameters */ $question_mark_pos = strpos($url, '?'); if ($question_mark_pos !== false) { $get_params = substr($url, $question_mark_pos); $url = substr($url, 0, $question_mark_pos); } /* Sanity checks */ assert('is_int($skip_path_components) && $skip_path_components >= 0'); assert('is_string($url)'); /* Force trailing slash for GET requests? */ if (Request::is_get() && $this->_getdefault('force-trailing-slash', true) && $url != '/' && !str_has_suffix($url, '/') && preg_match('/^.*\\/[^.\\/]+$/', $url)) { redirect($url . '/' . $get_params, HTTP_STATUS_MOVED_PERMANENTLY); } /* Store the url so that it can be used later */ $this->_set('url', $url); /* Split the url into smaller pieces */ $url = str_strip_prefix($url, '/'); $url = str_strip_suffix($url, '/'); $components = split('/', $url); /* Skip some components if requested, and store the cut-off part in the * 'base-url' property. */ if (count($components) < $skip_path_components) { $this->_handle_result(HTTP_STATUS_INTERNAL_SERVER_ERROR); } $base_url = sprintf('/%s/', join('/', array_slice($components, 0, $skip_path_components))); $this->_set('base-url', $base_url); $components = array_slice($components, $skip_path_components); /* Special case for top level urls */ if (count($components) == 1 && strlen($components[0]) == 0) { $components = array(); } /* Try all URL maps and see if they match the input url */ $found_map = false; $command_name = null; $parameters = array(); foreach ($this->urlmaps as $urlmap) { list($command_name, $patterns) = $urlmap; /* Check for valid parameters */ $match = $this->_match_inputs_with_patterns($components, $patterns); /* This urlmap didn't match, try next one */ if ($match === false) { continue; /* This urlmap matched! */ } else { $parameters = $match; $found_map = true; break; } } /* No explicit map found, try an implicit map */ if (!$found_map && $this->_getdefault('use-implicit-commands', true)) { $command_name = join('_', $components); $command_name = str_replace('-', '_', $command_name); /* The method must exist */ $command = 'command_' . $command_name; $found_map = method_exists($this, $command); } /* As a last resort try the default handler, if one was set. There's no * need to check the availability of the method; set_default_command() * already did that. */ if (!$found_map && $this->_isset('default-command')) { $command_name = $this->_get('default-command'); $found_map = true; } /* Sanity check: is the method available? */ $command = 'command_' . $command_name; if (!method_exists($this, $command)) { /* FIXME: it's not clear if this is desirable */ /* We found a handler name but the method doesn't exist... */ /* Trying the default handler, but remember which command * we wanted to access. */ if (!$this->_isset('default_command')) { /* We give up. */ $found_map = false; } else { $command = 'command_' . $this->_get('default-command'); } } /* If we still don't have a command, we give up. Too bad... not found */ if (!$found_map) { $this->_handle_result(HTTP_STATUS_NOT_FOUND); return false; } /* Store the command name for use by _handle_result() and possibly * pre_command(). */ $this->_set('command', $command_name); /* If this piece of code is reached, a valid command has been found. Run * the pre-command hook, call the appropriate method and handle the * result. The pre_command() method may return HTTP_STATUS_NOT_FOUND or * HTTP_STATUS_FORBIDDEN as well, so we need to handle the status * carefully. */ $status = $this->pre_command($parameters); /* The pre_command() method is not required to have a return value. If * it doesn't return anything, $status will be null at this point. If * that's the case we assume everything is alright. */ if (is_null($status)) { $status = HTTP_STATUS_OK; } if ($status == HTTP_STATUS_OK) { /* The pre_command() method succeeded. Run the actual command and * keep track of the status. */ $status = $this->{$command}($parameters); } /* Regardless of whether the actual command has been executed, the * result handler is invoked. Note: The post_command() is only invoked * if both the pre_command() and the actual command method return * HTTP_STATUS_OK (there's no danger of calling post_command() if no * real command has been executed). */ $this->_handle_result($status); }
/** * Fill form automatically from query data. If the form uses the GET method * the data comes from <code>$_GET</code>. If the form uses the POST method * the data comes from <code>$_POST</code>. * * The return value (see also fill() for an explanation) can be used to * detect incomplete \c $_GET or \c $_POST values. This may happen when * handling different form flavours with different controls using a single * form, e.g. a simple and advanced search form pointing to the same page in * which an instance of the advanced flavour of the form handles the * submitted data. It may also happen when users are messing with the * submitted data. You may then decide to process() the form only if all * values were provided. Example: * <code>if ($form->autofill() && $form->process()) { ...} else { ...}</code> * * \return * True if this fill could be automatically filled from \c $_GET or \c * $_POST, false if this was not the case. * * \see AnewtForm::fill() */ function autofill() { $form_method = $this->_get('method'); if (Request::is_get() && $form_method == ANEWT_FORM_METHOD_GET) { return $this->fill($_GET); } elseif (Request::is_post() && $form_method == ANEWT_FORM_METHOD_POST) { return $this->fill($_POST); } return false; }