# Configuring the Fat-Free Framework

Configuring the Fat-Free Framework requires creating:

- htaccess – Routes page requests to index.php
- index.php – Gets the instance of Fat-Free and executes it
- config.ini – Configuration information and site data
- routes.ini – Sets the controller for each page
- controllers – Code that generates the response to requests
  - page controllers – language specific controllers for content pages
  - common pages controller – controller for the pages that are common across all languages
  - utility controller – routing utility functions

## htaccess

`htaccess` routes requests for pages to index.php.

    # Enable rewrite engine and route requests to framework

    php_flag short_open_tag Off

    RewriteEngine On

    # Some servers require you to specify the `RewriteBase` directive
    # In such cases, it should be the path (relative to the document root)
    # containing this .htaccess file
    #
    RewriteBase /

    RewriteRule ^lib - [R=404]

    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule .* index.php [L,QSA]
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]

Note: These instructions are placed after redirects for https & www (or no www), and changed and deleted pages.

### What’s happening:

`htaccess` tells an Apache server to:

- check if the request contains the string `tmp/` or ends in `.ini` – if it does, reject the request with a `404 Page not found` response
  - The tmp directory and the ini files are private to Fat-Free
- check if the request is for an existing symbolic link, file, or directory – if it is, Apache will process the request
  - `%{REQUEST_FILENAME}` – is a server variable for the name of the requested file (or link or directory)

If the request is not for an existing link, file, or directory (the conditions), then the request is passed to index.php.

`php_flag short_open_tag off` – needs to be set to off. Having it set to on can cause problems with the opening `<?xml` tag for the site map. Some servers default to having `short_open_tag` set to on.

## index.php

`index.php` sets up the framework and processes the request for the desired page.

    <?php
    // Retrieve instance of the framework
    $f3=require('lib/base.php');

    // Load configuration
    $f3->config('app/config.ini');

    // Define routes
    $f3->config('app/routes.ini');

    // Define combined variable for scheme, host, and base
    $schemeHost = $f3->get('SCHEME').'://'.$f3->get('HOST').$f3->get('BASE');
    $f3->set('schemeHost',$schemeHost);

    // Define error response
    $f3->set('ONERROR','UtilitiesController->error');

    $f3->run();

### What’s happening:

`index.php` gets an instance of the framework, loads the configuration and route information, sets the `schemeHost` variable and the function for error handling, and runs the instance of the framework.

- schemeHost – I set a variable for the site address as I’m running the same code on two systems: a localhost version for development and the demo site, and it’s a little easier to call one variable rather than building the site address every time I need it.

## config.ini

`config.ini` tells Fat-Free where to find the files it needs and defines site variables.

    [globals]
    ; Where the framework autoloader will look for app files
    AUTOLOAD=app/
    ; Change the next line to 3 for development
    DEBUG=0
    ; Where the language files are located
    LOCALES=dict/
    ; Where errors are logged
    LOGS=tmp/
    ; Where the framework will look for templates and HTML-support files
    UI=app/ui/;js/;css/
    ; Site owner / company name
    siteOwner="SBF Consulting"
    ; Year site was created (use for copyright text in the footer)
    yearBuilt="2018"
    ; Embed images (versus separate http request)
    imageEmbed=true
    ; Embed minimized JavaScript files (versus loading the original file)
    scriptCSSEmbed=true
    ----- There is more in the file on GitHub -----

### What’s happening:

Values that apply to multiple pages are defined in `config.ini`. Values specific to one page are defined in that page’s controller or HTML file.

`imageEmbed` is used to embed images that are visible when the page loads, such as the hero image on the first page (which is the only image to which currently this applies), as a Base64 image to speed up page loading (eliminates a separate http requests for the image). Embedding the image does make the html code longer, which is more work to scroll through when troubleshooting, which is why I don’t embed the image while developing the site.

`scriptCSSEmbed` controls embedding JavaScript and CSS files in the page for faster loading versus separate files for easier troubleshooting:

- `scriptCSSEmbed` controls whether a minified JavaScript will be embedded in the page or the unminified JavaScript version (which is easier to troubleshoot) will be loaded separately.
- `scriptCSSEmbed` controls whether a minified CSS file will be embedded in the page or the minified CSS file will be loaded using a link – using a link enables the Sass source map to work.

To add a new page to the site:

- Add the page slug and title to the DropdownMenu list
- Add the page to the routes.ini file
- Add the page to the PageController file
- Create the page HTML content file
- Repeat for each language

To add an additional language:

- Add the language to the menu list
- Define the menus for the new language
- Create the routes
- Create the controllers
- Create the content pages
- Create a dict file

## routes.ini

Routes direct a page request to the function that will provide the page based on the address.

    [routes]
    ;GET name address = class->function to render the page
    GET /=UtilitiesController->getLanguage
    GET /sitemap.xml=CommonPageController->getSitemap

    GET @en_home: /en/home=enPageController->RenderHome
    GET @en_details1: /en/bootstrap=enPageController->renderDetails1
    GET @en_details2: /en/fatfree=enPageController->renderDetails2
    GET @en_details3: /en/ffconfig=enPageController->renderDetails3
    GET @en_details4: /en/templates=enPageController->renderDetails4
    GET @en_details5: /en/details=enPageController->renderDetails5
    GET @en_contactx: /en/contact=CommonPageController->contactNew
    POST @en_contactx: /en/contact=CommonPageController->contactPost
    GET @en_termsx: /en/terms=CommonPageController->renderTerms

### What’s happening:

Each line defines: method (GET or POST), route name (used by the template engine for links to that page from other pages); URL address; and the controller function that will create the page.

#### Requests for index files

If a user includes an index file as part of a page address, they’ll be rerouted to the root directory, rather than receiving a Page not found error:

    GET /en/index.htm=UtilitiesController->indexOverride
    GET /en/index.html=UtilitiesController->indexOverride
    GET /en/index.php=UtilitiesController->indexOverride

## Controller.php & PageController.php

`Controller.php` defines the overall controller class. That class is extended with the PageController classes (e.g. `enPageController`).

In addition to the function called by the route definition, Fat-Free also calls a `beforeroute` and an `afterroute` function. The same before and after functions are used for all languages.

### beforeroute – Controller.php

    // HTTP route pre-processor
    function beforeroute($f3) {
        $f3->set('googleNoIndex',false); // Set to true when needed
        $f3->set('isHomePage',false); // Set to true for home pages
        $f3->set('isDetailPage',false); // Set to true for detail pages
        $f3->set('pageCSS',false); // Add file name if needed
        $f3->set('highlighterJavaScript',false); // Set to true for code sections
        $f3->set('pageJavaScript',false); // Add file name if needed
    }

### What’s happening:

Set flags for things that are not required for most pages and change the flag in that page’s controller function when needed:

- `googleNoIndex`: normally false – the only pages not indexed are the Contact and Terms of Use pages and the error pages (404 and 500).
- `isHomePage`: normally false – flag for the home page (it has different functionality).
- `isDetailPage`: normally false – flag for the detail pages (just need for the navigation template).
- `pageCSS`: normally false – if CSS is required for just one or two pages, the CSS can be loaded by setting the value of pageCSS to the CSS file name. The code only supports one file, so if two CSS files are needed, the files should be combined into one file.
- `highlighterJavaScript`: normally false – flag for loading highlight.js to highlight code syntax.
- `pageJavaScript`: normally false – if a special JavaScript function is required for just one pages, the JavaScript can be loaded by setting the value of pageJavaScript to the template file name. I use this for loading the JavaScript for an image slider and for the special effects on the `404 page not found` page and the `500 server error` page. The code only supports one file, so if two JavaScript files are needed, the files should be combined into one file.

### Route Function – PageController.php

    function loadCommonSettings($f3) {
        $f3->set('LANGUAGE','en');
        $f3->set('langSubdirectory','en');
    }

    function RenderHome($f3) {
        $this->loadCommonSettings($f3);
        $f3->set('pageTitle','Learning Frameworks');
        $f3->set('pageDescription','A frontend / backend setup for a simple,
            multi-language website using Bootstrap 4 with the Fat-Free PHP
            framework, but no database.');
        $f3->set('isHomePage',true);
        $f3->set('loadID',
            function($array,$count) {
                reset($array);
                for ($x = 0; $x < $count; $x++) {
                    next($array);
                }
                return key($array);
            }
        );
        // Set the content source
        $f3->set('pageContent',$f3->get('ALIAS').'.html');
    }

### What’s happening:

Set page specific items in the route function (data that’s not contained in the content page):

- `loadCommonSettings` – a local function to set values that are common to all pages for that language:
  - `LANGUAGE` – set the Fat-Free system variable to the language code for the current language. Fat-Free uses this value for selecting the language dictionary.
  - langSubdirectory – This is the language subdirectory.
- `pageTitle` – for the title tag and for social media
- `pageDescription` – for the description meta tag and for social media
- `loadID` – A custom function for pulling the slug value from the config.ini menus for the single page menu (only for the home page)
  - The slug values could have been manually included in the template, but I wanted experience with using a custom function.
- `pageContent` – set the file for the page content – the file name is based on the route’s alias (which is the same text string as the name of the content file)

### afterroute – Controller.php

    // HTTP route post-processor
    function afterroute($f3) {
        // Sorted the languages for the language menu
        $lang_array = $f3->get('languages');
        uasort($lang_array, function ($a,$b){
            return ($a[2] < $b[2]) ? -1 : 1;
        });

        // If a regular route, use the alias, otherwise
        // point the language menu to the home page (e.g. for error pages)
        if ($f3->exists('ALIAS',$alias_base)) {
            $alias_base = substr($alias_base,2); // the part after the lang prefix
        } else {
            $alias_base = '_home';
        }

        $language_links_array = [];
        foreach($lang_array as $key=>$details) {
            array_push($language_links_array,
                [$key.$alias_base,$key,$details[0],$details[2]]
            );
        }
        $f3->set('languageLinks',$language_links_array);
        $pageLanguage = explode(',',$f3->get('LANGUAGE'));
        $f3->set('langCode',$pageLanguage[0]); // Use langCode for the html lang tag
        $lang_prefix = $f3->get('langSubdirectory'); // for local use in this function
        $f3->set('mainMenu', $f3->get($lang_prefix.'HomeMenu'));
        $f3->set('dropdownMenu', $f3->get($lang_prefix.'DropdownMenu'));

        // Render HTML layout
        echo \Template::instance()->render('layout.html','text/html');

### What’s happening:

Set page specific items in the after function:

- Setup an array of the corresponding language pages for the preflang links and the language switcher:
  - `lang_array` – get the array of languages from config.ini – the default language is first and then the other languages (the order doesn’t matter)
  - `uasort` – PHP sort function – sort the array in Unicode order based on the language name (uasort preserves the key values)
  - `alias_base` – Get the base portion of the alias (e.g. en_details1 => _details1) – combine it with the other language prefixes to generate the route names to the other language versions of the same page
  - `language_links_array` – Create a new array to be passed to the template engine
  - loop through the lang_array, pushing an array for each language to the language_links_array – each array contains the route name for the language versions, the language prefix (used for the language flag), and the language name.
  - `languageLinks` – pass the just created array to Fat-Free to be used for the language menu
- `langCode` – set the value for the lang attribute in the html tag.
- Set the `mainMenu` – combine the langCode with “HomeMenu” to generate the language specific menu (this does require that each menu have the same naming structure).
- Set the `dropdownMenu` – combine the langCode with “DropdownMenu” to generate the language specific menu (this does require that each menu have the same naming structure).
- Echo the results from the template engine to generate the page content.

## CommonPageController.php

The PageControllers display the general site content. `CommonPageController.php` extends `Controller.php` to display the pages that are common across all languages or that are used for site management:

- Contact
- Terms of Use | Privacy Policy
- Sitemap
- 404 Page not found
- Other errors (e.g. 500 Internal server error)

## UtilitiesController.php

The `UtilitiesController.php` handles requests that will be redirected:

- getLanguage – requests for the root directory are redirected to the appropriate language subdirectory.
- indexOverride – requests for index files (e.g. index.html) are redirected to the root directory, and then the user will be redirected again to the appropriate language subdirectory.