メインコンテンツまでスキップ
Version: Fegg 5.x(開発版)

URL

URL and Controller class​

Fegg maps URL segments to a controller class, a method and its arguments:

https://example.com/class/method/param1/param2/
  1. Controller class (site/controller/Class.php, first letter in upper case)
  2. Method of the controller class
  3. Arguments for the method

When the method segment is empty, index() is called. When no segment names a controller, the Index controller of that directory is used.

Sub directories of site/controller/ are part of the URL and of the namespace:

URLFileCalled
/site/controller/Index.phpSite\Controller\Index::index()
/news/site/controller/News.phpSite\Controller\News::index()
/news/detail/12/site/controller/News.phpSite\Controller\News::detail('12')
/cms/news/edit/3/site/controller/Cms/News.phpSite\Controller\Cms\News::edit('3')
/cms/media/core/controller/Cms/Media.php (no site class)Fegg\Controller\Cms\Media::index()
  • The site (Site\Controller\...) is searched first, then the core (Fegg\Controller\...). A site class with the same name replaces the core's CMS screen (see Controller).
  • Segments are walked from the left; the first one that names a controller file wins over a directory with the same name.
  • Controller and directory names must be valid PHP class names (letters, digits, _). For URLs like /about-us/, use a route.
  • Abstract classes (the base Controller classes) are never called from a URL.
  • Only the controller's own public methods are actions: methods of the base classes, methods named like a method of Fegg\Application (mail, in, redirect ...), static methods and names starting with _ are 404 (see Controller).
  • If no controller or no method matches, the NotFound controller renders the 404 page.

Arguments are always strings.

Example​

URL
https://example.com/post/edit/1/
htdocs/_fegg/site/controller/Post.php
<?php
namespace Site\Controller;

defined('FEGG_CORE_DIR') || exit;

class Post extends Controller
{
public function edit($id)
{
echo $id; // Result: 1
}
}

Trailing slash​

URLs without an extension are normalised to end with /. A GET or HEAD request to /news/detail/1 is redirected (301) to /news/detail/1/, keeping the query string. Other methods (POST, ...) are handled in place without a redirect. URLs with an extension (/news/post_1.html) are not changed.

Write links in templates with the trailing slash to avoid the extra redirect.

Routing​

To use URLs that do not follow the class/method structure, add routes to htdocs/_fegg/site/config/route.php:

$route['from'] = 'to';

The key is the URL (without the leading /) and the value is the class/method/arguments path it is mapped to.

  • Routes without wildcards are checked first. Then the routes are tried in the order they are written, and the first match wins. Put specific routes above general ones.
  • A route without an extension matches the URL with or without a trailing slash ('contact/' matches /contact and /contact/).
  • When no route matches, the URL itself is used as the path.

Wildcards​

WildcardMatches
:numDigits only ([0-9]+)
:anyOne segment: any characters except /

Refer to the matched values with $1, $2, ... in the value.

Example​

htdocs/_fegg/site/config/route.php
<?php
defined('FEGG_CORE_DIR') || exit;

// Handle index.html (in the skeleton by default)
$route[':any/index.html'] = '$1/index';
// https://example.com/news/index.html -> Site\Controller\News::index()

$route['news/post_:num.html'] = 'news/detail/$1';
// https://example.com/news/post_1.html -> Site\Controller\News::detail('1')

$route['item/:any/'] = 'product/item_lookup/$1';
// https://example.com/item/foobar/ -> Site\Controller\Product::item_lookup('foobar')

$route['contact/'] = 'contact/index';
$route['contact/confirm.html'] = 'contact/confirm';
// https://example.com/contact/confirm.html -> Site\Controller\Contact::confirm()

Static pages​

Pages that have no data of their own do not need a controller. Route them to the skeleton's Site\Controller\Page, which renders the template named in the route:

htdocs/_fegg/site/config/route.php
$route['about/'] = 'page/render/about'; // site/template/about.tpl
$route['guide/:any.html'] = 'page/render/guide/$1'; // site/template/guide/*.tpl

Page::render() joins its arguments into the template path. If the template does not exist, it redirects to the top page.

Route-only controllers​

Page implements the marker interface Fegg\Http\RouteOnly. A controller that implements it is only called through a route in route.php. The default /class/method/arguments mapping skips it, so /page/render/about/ typed in the browser is a 404. This way a visitor cannot choose which template Page renders; only the routes you write can.

Use RouteOnly for your own controllers whose arguments must not come straight from the URL:

htdocs/_fegg/site/controller/Landing.php
<?php
namespace Site\Controller;

defined('FEGG_CORE_DIR') || exit;

use Fegg\Http\RouteOnly;

class Landing extends Controller implements RouteOnly
{
public function show($campaign)
{
$this->page['campaign'] = $campaign;
$this->displayPage('landing/' . $campaign);
}
}
htdocs/_fegg/site/config/route.php
$route['campaign/spring/'] = 'landing/show/spring';