Permalink
Browse files

Improved decoupling and testability

  • Loading branch information...
AliasIO committed Apr 6, 2014
1 parent d3ec2ab commit 5a122020af9e90fdf089e7f48fa2269fd2ff4046
View
112 README.md
@@ -16,6 +16,7 @@ Buzzword compliance
✔ Namespaced
✔ Unit tested
✔ Pluggable
+✔ Testable
✔ [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)
✔ PHP5
✔ MVC
@@ -38,17 +39,16 @@ Getting started: controllers and views
Let's create a page. Each page consists of a controller and at least one view.
-Controllers house the
-[business logic](http://en.wikipedia.org/wiki/Business_logic) of the page while
-views should be limited to simple UI logic (loops and switches).
+The controller does most of the work; views should be limited to simple
+presentation logic (loops and switches).
**Controller `Swiftlet/Controllers/Foo.php`**
```php
<?php
namespace Swiftlet\Controllers;
-class Foo extends \Swiftlet\Controller
+class Foo extends \Swiftlet\AbstractController
{
protected $title = 'Foo'; // Optional but usually desired
@@ -74,15 +74,15 @@ Important: class names are written in
</p>
```
-Variables can be passed from controller to view using the views `set` and
-`get` methods. Values are automatically made safe for use in HTML, use
-`$this->htmlDecode()` on values that should be treated as code.
+The controller can set variables directly on the view. Values are automatically
+made safe for use in HTML, use `$this->get('variable', false)` on values that
+should be treated as code.
You can now view the page by navigating to `http://<swiftlet>/foo` in your web
browser!
-If you're running Apache and see "404 Not Found" you will need to enable
-rewrites. Alternatively you can navigate to `http://<swiftlet>?q=foo`.
+If you get a "404 Not Found" you will need to enable rewrites in the web server
+configuration. Alternatively you can navigate to `http://<swiftlet>?q=foo`.
*Swiftlet can be invoked from the command line (e.g. to run cron jobs). Simply
run `php public/index.php -q foo`.*
@@ -91,16 +91,15 @@ run `php public/index.php -q foo`.*
Routing
-------
-Notice how we can access the page at `/foo` by simply creating a controller
-named `Foo`. The application (Swiftlet) maps URLs to controllers, actions and
-arguments.
+Notice how you can access the page at `/foo` by simply creating a controller
+named `Foo`. The application maps URLs to controllers, actions and arguments.
Consider this URL: `/foo/bar/baz/qux`
In this case `foo` is the name of the controller and view, `bar` the name of
-the action and `baz` and `qux` are arguments. If the controller or action is
-missing from the URL they will default to `index` (`/` will call `index()` on
-`Swiftlet\Controller\Index`).
+the action and `baz` and `qux` are additional arguments. If the controller or
+action is missing from the URL they will default to `index` (`/` will call
+`index()` on `Swiftlet\Controller\Index`).
Underscores in the controller name are translated to directory separators, so
`/foo_bar` will point to `Swiftlet/Controllers/Foo/Bar.php`.
@@ -117,11 +116,10 @@ Actions are methods of the controller. A common example might be `edit` or
`/blog/edit/1`
-This will call the function `edit()` on `Blog` with `1` as the argument (the
+This will call the function `edit()` on `Blog` with `1` as an argument (the
id of the blog post to edit).
-The action name and arguments can be accessed through
-`$this->app->getAction()` and `$this->app->getArgs()` respectively.
+Arguments can be accessed through `$this->app->getArgs()`.
To use a different view for a specific action you may change the value of
`$this->view->name`. The view name is a filename relative to the `views`
@@ -139,7 +137,7 @@ Let's throw a model into the mix and update the controller.
<?php
namespace Swiftlet\Models;
-class Foo extends \Swiftlet\Model
+class Foo extends \Swiftlet\AbstractModel
{
public function getHelloWorld()
{
@@ -161,9 +159,9 @@ class Foo extends \Swiftlet\Controller
public function index()
{
// Get an instance of the Example class (Swiftlet/Models/Example.php)
- $exampleModel = $this->app->getModel('example');
+ $example = new \Swiftlet\Models\Example;
- $this->view->helloWorld = $exampleModel->getHelloWorld();
+ $this->view->helloWorld = $example->getHelloWorld();
}
}
```
@@ -173,7 +171,7 @@ object such as a user.
```php
<?php
-$user = $this->app->getModel('user');
+$user = new \Swiftlet\Models\User;
$user->setEmail('example@example.com');
@@ -183,19 +181,14 @@ $user->save();
Loading and saving data should almost always happen in a model. You can create
as many models as you like; they aren't tied to specific controllers or views.
-A model can be instantiated using `$this->app->getModel($modelName)`. To allow
-re-use, use `$this->app->getSingleton($modelName)` instead as this will only
-create a single instance when called multiple times (useful for database
-connections and session management).
-
Plugins and hooks
-----------------
Plugins implement [hooks](http://en.wikipedia.org/wiki/Hooking). Hooks are entry
points for code that extends the application. Swiftlet has a few core hooks and
additiontal ones can be registered pretty much anywhere using
-`$this->app->registerHook($hookName)`.
+`$this->app->registerHook($hookName, $controller, $view)`.
**Plugin `Swiftlet/Plugins/Foo.php`**
@@ -208,9 +201,7 @@ class Foo extends \Swiftlet\Plugin
public function actionAfter()
{
// Overwrite our previously set "helloWorld" variable
- if ( $this->app->getControllerName() === 'Index' ) {
- $this->view->helloWorld = 'Hi world!';
- }
+ $this->view->helloWorld = 'Hi world!';
}
}
```
@@ -235,18 +226,15 @@ Libraries
---------
Reusable components such as code to send an email or generate a thumbnail image
-should go in a separate library class. A library can be instantiated using
-`$this->app->getLibrary($libraryName)`.
+should go in a separate library class.
```php
<?php
-$email = $this->app->getLibrary('email');
+$email = new \Swiftlet\Libraries\Email
$email->send($to, $subject, $message);
```
---------------------------------------------------------------------------------
-
Configuration
-------------
@@ -265,48 +253,27 @@ $value = $this->app->getConfig('variable');
Values can be set in `config/main.php` or a custom file.
---------------------------------------------------------------------------------
-
-
-Abstract Public methods
------------------------
+Public methods
+--------------
**Application `Swiftlet\App`**
-* `run()`
+* `App run()`
Run the application
-* `serve()`
-Render the view
-
* `mixed getConfig(string $variable)`
Get a configuration value
-* `setConfig(string $variable, mixed $value)`
+* `App setConfig(string $variable, mixed $value)`
Set a configuration value
-* `string getAction()`
-Name of the action
-
* `array getArgs([ integer $index ])`
List of arguments passed in the URL, or a specific argument if `$index` is specified
-* `object getModel(string $modelName)`
-Create a new model instance
-
-* `object getSingleton(string $modelName)`
-Create or return an existing model instance
-
-* `object getLibrary(string $libraryName)`
-Create a new library instance
-
-* `string getControllerName()`
-Name of the controller
-
* `string getRootPath()`
Absolute client-side path to the website root
-* `registerHook(string $hookName, array $params)`
+* `App registerHook(string $hookName, array $params)`
Register a hook
@@ -315,7 +282,7 @@ Register a hook
* `mixed get(string $variable [, bool $htmlEncode = true ])`
Get a view variable, encoded for safe use in HTML by default
-* `set(string $variable [, mixed $value ])`
+* `View set(string $variable [, mixed $value ])`
Set a view variable
* `__set(string $variable [, mixed $value ])`
@@ -328,23 +295,8 @@ being HTML encoded.
* `__get(string $variable)`
Magic method to get a view variable
-* `htmlEncode(mixed $value)`
+* `mixed htmlEncode(mixed $value)`
Recursively make a value safe for HTML
-* `htmlDecode(mixed $value)`
+* `mixed htmlDecode(mixed $value)`
Recursively decode a previously encoded value to be rendered as HTML
-
-
-**Controller `Swiftlet\Controller`**
-
-* `index()`
-Default action
-
-
-User contributed packages
--------------------------
-
-Community created plugins, controllers and models are available at
-[github.com/ElbertF/Swiftlet-Packages](https://github.com/ElbertF/Swiftlet-Packages).
-Feel free to submit your own.
-
@@ -2,11 +2,13 @@
namespace Swiftlet;
+require 'Swiftlet/Exception.php';
+
/**
* Common class
* @abstract
*/
-abstract class Common implements Interfaces\Common
+abstract class AbstractCommon implements Interfaces\Common
{
/**
* TODO
@@ -0,0 +1,79 @@
+<?php
+
+namespace Swiftlet;
+
+/**
+ * Controller class
+ * @abstract
+ */
+abstract class AbstractController extends AbstractCommon implements Interfaces\Controller
+{
+ /**
+ * Application instance
+ * @var Interfaces\App
+ */
+ protected $app;
+
+ /**
+ * View instance
+ * @var Interfaces\View
+ */
+ protected $view;
+
+ /**
+ * Page title
+ * @var string
+ */
+ protected $title;
+
+ /**
+ * Set application instance
+ * @param Interfaces\App $app
+ * @return Interfaces\Controller
+ */
+ public function setApp(Interfaces\App $app)
+ {
+ $this->app = $app;
+
+ return $this;
+ }
+
+ /**
+ * Set view instance
+ * @param Interfaces\App $app
+ * @return Interfaces\Controller
+ */
+ public function setView(Interfaces\View $view)
+ {
+ $this->view = $view;
+
+ $reflection = new \ReflectionClass($this);
+
+ $this->view->name = strtolower($reflection->getShortName());
+
+ $this->view->pageTitle = $this->title;
+
+ return $this;
+ }
+
+ /**
+ * Set page title
+ * @param string $app
+ * @return Interfaces\Controller
+ */
+ public function setTitle($title)
+ {
+ $this->title = $title;
+
+ $this->view->pageTitle = $title;
+
+ return $this;
+ }
+
+ /**
+ * Default action
+ */
+ public function index()
+ {
+ }
+}
@@ -0,0 +1,28 @@
+<?php
+
+namespace Swiftlet;
+
+/**
+ * Library class
+ * @abstract
+ */
+abstract class AbstractLibrary extends AbstractCommon implements Interfaces\Library
+{
+ /**
+ * Application instance
+ * @var Interfaces\App
+ */
+ protected $app;
+
+ /**
+ * Set application instance
+ * @param Interfaces\App $app
+ * @return Interfaces\Library
+ */
+ public function setApp(Interfaces\App $app)
+ {
+ $this->app = $app;
+
+ return $this;
+ }
+}
Oops, something went wrong.

0 comments on commit 5a12202

Please sign in to comment.