Standalone MVC Apps Tutorial
In this tutorial we will build a "standalone" MVC App using the cMVC Framework to view and manage the presidents database created in the Content Types Tutorial. We will be able to preview changes to a staging environment to test and review changes, and later publish to a production environment to release tested updates for public consumption.
App Package
First, create a new "Standalone MVC App" Package to organize and manage application files.
- Launch the Content Manager (CMS) App.
- Click Add Content () in the Collection Bar and select "Folder" in the drop-down.
- Enter the Title "Packages".
- Click Approve.
- Click Add Content () in the Contents field and select "Package" in the drop-down.
- Enter the Title "Standalone MVC App".
- Under the Packages tab, enter the Namespace "com_presidentsdemo_www".
- Click Approve.
- Click back to the Contents tab.
Version Settings
Next, enable version control, so we can restore previous versions of our files if needed.
- Click Add Content () in the Contents field and select "Version Settings" in the drop-down.
- Enter Title: Version Control
- For Folders, check "Standalone MVC App" under "Packages".
- For Content Types, check "Content".
- For Max. Versions in History, select "8" or your preferred Maximum Number of Versions to keep.
- Click Approve and Back.
File Settings
Next, configure how various files should be written to the file system.
webCOMAND Hostnames
For this tutorial, you can host the staging and live versions of this app at the corresponding hostnames that came with your account:
live.<account>.webcomand.com
staging.<account>.webcomand.com
Custom Hostnames
As an alternative, you can use hostnames based on domains you control with the following steps.
- Add CNAME records that point to <account>.webcomand.com for the desired live and staging hostnames. If you're not sure how to do that, see your DNS provider for instructions.
- For each hostname configured:
- Click Add Content () in the Contents field and select "Web Route" in the drop-down.
- For Hostname, enter the configured hostname.
- Click Approve and expand logged events to see if the SSL certificate was updated properly.
- Click Back
If you set up custom hostnames, use those instead of live.<account>.webcomand.com
and staging.<account>.webcomand.com
in the subsequent steps below.
File System Folder
With the live and staging hostnames set up, we can configure webCOMAND to write Files (content in the webCOMAND repository of the File Content Type, or a Content Type that extends the File Content Type) in our new package to folders in the server's file system that will contain the application files and web server Document Root (htdocs) to serve files for the hostnames.
- Click Add Content () in the Contents field and select "File Settings" in the drop-down.
- Enter Title: App Files
- For Folders, check "Standalone MVC App" under "Packages".
- For Content Types, check "File".
- Enter Approve Path:
/publications/live.<account>.webcomand.com
- Enter Save Path:
/publications/staging.<account>.webcomand.com
- Leave the Store Path blank, because we don't need to update files as we type.
In some cases it is nice to have another environment for testing during development, before saving to staging. In those cases, this field can be used to write/update files in your development environment, and as a bonus, no need to save before testing.
- Click Approve and Back.
For more information, see the File Settings Content Type.
Router
A key component in the MVC framework is the router. The router receives all web requests to the application and routes them to a controller based on the requested URL. The COMAND MVC router makes this easy with defaults suitable for most applications. Since the router brokers all web requests, we define the router in index.php directly under the package folder. When an index.php file is directly under the package folder, it will be executed for all requests that do not correspond to a file in the public subfolder.
- Click Add Content () in the Contents field and select "PHP File" in the drop-down.
- Enter the Filename "htdocs/router.php".
- Enter the Text:
<?php namespace com_presidentsdemo_www; // enable the COMAND auto-loader require_once('/var/www/webcomand/comand.php'); // use standard routing with a few tweaks: \io_comand_mvc\router::route([ // define the base namespace for cMVC files to auto-load 'namespace' => __NAMESPACE__, // where to find files in the namespace (relative to this router) 'namespace_path' => '../cmvc/', // process just the URL path segments after the package name 'request' => $_COMAND['REQUEST_URI'], // set default controller for when no controller is specified 'default' => 'presidents', ]);
- Click Approve.
Web Server Configuration
In order for the router to receive all appropriate web requests, we need to configure the web server to execute the router PHP file for requests to a specific URL and its sub-paths.
Apache (.htaccess)
Apache web server can be configured with an .htaccess file like the following, which uses Rewrite Rules to direct all requests to a specific path to the router. The router (index.php) must live within the Document Root, but the MVC application files it references may be located anywhere the web server has access to, so it is a best practice to locate those files outside of the Document Root.
- Click the New Menu () in the Contents field and select "Apache Config File" in the drop-down.
- Enter the Filename "htdocs/.htaccess".
- Enter the Text:
# Direct all requests that are not for a real file or # folder in Document Root to the cMVC Router. # To support symbolic links, uncomment the next line. # RewriteCond %{REQUEST_FILENAME} !-l RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule .* router.php [QSA,L]
- Click Approve.
Models
This app will work with the Presidents database, which can be created by following the Content Types Tutorial, or the steps below.
- Click "Standalone MVC App" in the folder tree on the left.
- Click the Import button () in the Contents field.
- Click URL and enter:
https://www.webcomand.com/packages/com_presidentsdemo_www/install/presidents.json
A model is automatically available when a new content type is created, so there is no need to create one to query, access and edit the Presidents content like we will from our views and controllers below. More advanced models can be defined to extend and override the automatic model, which is covered in the COMAND Content Type Classes Topic.
Views
Views are PHP files that describe how to display the app interface, components and content, typically in HTML. Standard PHP tags and short tags are used to define the view logic and insert variables passed to the view from a controller.
Our app will have 3 views:
- presidents - to display a list of presidents
- president - to display a single president in a form for editing
- layout - to wrap the views above in a common web page "wrapper"
presidents (list view)
- Click the New Menu () in the Contents field and select "cMVC View" in the drop-down.
- Enter the Filename "cmvc/views/presidents.php".
- Enter the Text:
<ol> <?php foreach($presidents as $p): ?> <li value="<?= $p->Number ?>"> <a href="edit/<?= $p->OID ?>"><?= $p->Name ?></a> </li> <?php endforeach; ?> </ol>
- Click Approve and then Back.
president (edit view)
- Click the New Menu () in the Contents field and select "cMVC View" in the drop-down.
- Enter the Filename "cmvc/views/president.php".
- Enter the Text:
<form action="update" method="POST" enctype="multipart/form-data"> <input type="hidden" name="oid" value="<?= $oid ?>" /> <label for="number">Number</label> <input type="number" name="number" value="<?= $p->Number ?>" /> <label for="name">Name</label> <input type="text" name="name" value="<?= $p->Name ?>" /> <label for="photo">Photo</label> <img src="<?= $img_url ?>" /> <input type="file" name="photo" /> <input type="submit" name="op" value="Update" /> <input type="submit" name="op" value="Cancel" /> </form>
- Click Approve and then Back.
layout (common wrapper)
- Click the New Menu () in the Contents field and select "cMVC View" in the drop-down.
- Enter the Filename "cmvc/views/layout.php".
- Enter the Text:
<!DOCTYPE html> <html lang="en"> <head> <title>Presidents MVC App</title> <base href="<?= $base_url ?>" /> <link type="text/css" rel="stylesheet" href="../css/web.css" /> </head> <body> <h1>Presidents</h1> <?php if( $msg ): ?> <div class="msg"><?= $msg ?></div> <?php endif; ?> <?= $body ?> </body> </html>
- Click Approve and then Back.
web.css
The layout view references an external CSS file, so we can create that as a simple static file under the Document Root.
- Click the New Menu () in the Contents field and select "CSS File" in the drop-down.
- Enter the Filename "htdocs/css/web.css".
- Enter the Text:
.msg {border: 1px solid #888; padding: 4px; background-color: #eee;} label, input, img {display: block; margin: 4px 0;} input {margin-bottom: 16px; padding: 4px;} input[type="submit"] {display: inline;}
- Click Approve and then Back.
Controllers
Controllers are PHP files that respond to web requests. A controller's public methods with names that begins with "web__" will be called automatically based on the URL of the web request. We will add a single controller with 3 "web__" methods:
- web__index() - Called for requests that don't target a specific method. Ours will list all presidents.
- web__edit() - Display a specific president in a form to edit that president's field values.
- web__update() - Update a president's field values based on the edit form submission.
presidents (controller)
- Click the New Menu () in the Contents field and select "cMVC Controller" in the drop-down.
- Enter the Filename "cmvc/controllers/presidents.php".
- Enter the Text:
<?php namespace com_presidentsdemo_www\controllers; class presidents extends \io_comand_mvc\controller { public function web__index($msg = '') { $p = $this->repo()->get("FROM President ORDER BY Number"); $body = $this->view('presidents', ['presidents'=>$p], FALSE); $this->view('layout', [ 'base_url'=>$this->base_url, 'body'=>$body, 'msg'=>$msg]); } public function web__edit($oid) { $p = $this->repo()->get_first($oid); $foid = $p->Type->get_field('Photo')->OID; $img_url = "/com_webcomand/img/$oid/$foid/96x96/4"; $body = $this->view('president', [ 'oid'=>$oid, 'p'=>$p, 'img_url'=>$img_url], FALSE); $this->view('layout', [ 'base_url'=>$this->base_url, 'body'=>$body]); } public function web__update() { if($this->request->post('op') == 'Cancel') { $this->web__index(); } $oid = $this->request->post('oid'); $p = $this->repo()->get_first($oid); if(!$p || $p->Type->Identifier != 'President') { $this->web__index('Invalid President OID'); } $p->Name = $this->request->post('name'); $p->Number = $this->request->post('number'); $photo = $this->request->file('photo'); if($photo) { $p->Photo = $photo; } try { $p->approve(); } catch(Exception $e) { $this->web__index('Update error: ' . $e->getMessage()); } $this->web__index('Updated President ' . $p->Name); } }
- Click Approve and then Back.
Conclusion
The Presidents app uses the cMVC framework and File Settings to make it easier to build, stage, test, debug and release large scale web applications from webCOMAND.