Skip to content

Commit

Permalink
Fixes to routing, mostly.
Browse files Browse the repository at this point in the history
  • Loading branch information
Robin de Graaf committed Mar 12, 2017
1 parent 569f4b6 commit 8d2baf8
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 18 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Parable PHP Framework Changelog

### 0.9.2

__Changes__
- Parameters from a Route are now directly passed into actions. No more getting it from the Route through `getValue()`. See the new `\Controller\Home` example action for how to use it. The first parameter is still the `\Parable\Routing\Route` instance associated with the request.
- Parameters passed to a Route can now be typecast in the url itself. `{param:int}`, `{param:string}`, `{param:float}`. Other types are, at the moment, all string values.
- Methods for routes should now be passed as an array. Passing it as a string is allowed for now, but will be removed the next time the version is bumped to either 0.10.0 or 1.0.0, whichever happens first.
- Many public functions have been turned protected if public access wasn't required or desired.
- `\Parable\Routing\Route` has gained a `getValues()` method.
- `\Init\Example` has been expanded, showing a way to hook into the 404 event, as well as that DI is available as usual.

__Bugfixes__
- HTTP code 200 is now explicitly set on a successful dispatch.
- The full URL is now passed to the `parable_http_404` hook, rather than just the partial.
- A bug in a file that's too embarrassing to mention.

### 0.9.1

__Changes__
Expand Down
8 changes: 5 additions & 3 deletions src/Framework/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class App
protected $database;

/** @var string */
protected $version = '0.9.0';
protected $version = '0.9.2';

public function __construct(
\Parable\Filesystem\Path $path,
Expand Down Expand Up @@ -90,7 +90,8 @@ public function run()
$this->loadRoutes();

/* Get the current url */
$currentUrl = $this->url->getCurrentUrl();
$currentUrl = $this->url->getCurrentUrl();
$currentFullUrl = $this->url->getCurrentUrlFull();

/* Load the config */
if ($this->config->get('database.type')) {
Expand All @@ -107,11 +108,12 @@ public function run()
$route = $this->router->matchCurrentRoute();
$this->hook->trigger('parable_route_match_after', $route);
if ($route) {
$this->response->setHttpCode(200);
$this->hook->trigger('parable_http_200', $route);
$this->dispatcher->dispatch($route);
} else {
$this->response->setHttpCode(404);
$this->hook->trigger('parable_http_404', $currentUrl);
$this->hook->trigger('parable_http_404', $currentFullUrl);
}

$this->hook->trigger('parable_response_send');
Expand Down
10 changes: 8 additions & 2 deletions src/Framework/Dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,19 @@ public function dispatch(\Parable\Routing\Route $route)
$content = null;
$this->response->startOutputBuffer();

/* Build the parameters array */
$parameters = [$route];
foreach ($route->getValues() as $value) {
$parameters[] = $value;
}

/* Call the relevant code */
if ($route->controller && $route->action) {
$controller = \Parable\DI\Container::get($route->controller);
$content = $controller->{$route->action}($route);
$content = $controller->{$route->action}(...$parameters);
} elseif ($route->callable) {
$call = $route->callable;
$content = $call($route);
$content = $call(...$parameters);
}

/* Try to get the relevant view */
Expand Down
4 changes: 2 additions & 2 deletions src/Http/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ public function isPost()
/**
* @return bool
*/
public function isUpdate()
public function isPut()
{
return $this->isMethod('UPDATE');
return $this->isMethod('PUT');
}

/**
Expand Down
71 changes: 66 additions & 5 deletions src/Routing/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function __construct(
) {
$this->request = $request;

$this->methods = explode('|', $data['methods']);
$this->methods = $data['methods'];
$this->url = isset($data['url']) ? $data['url'] : null;
$this->controller = isset($data['controller']) ? $data['controller'] : null;
$this->action = isset($data['action']) ? $data['action'] : null;
Expand All @@ -50,6 +50,16 @@ public function __construct(
if (!$this->controller && !$this->action && !$this->callable) {
throw new \Parable\Routing\Exception('Either a controller/action combination or callable is required.');
}
if (!is_array($this->methods)) {
/*
* @deprecated This will be turned into an Exception in the next minor version (if pre-release) or 1.0.0.
*/
if (strpos($this->methods, "|") !== false) {
$this->methods = explode("|", $this->methods);
} else {
$this->methods = [$this->methods];
}
}

$this->parseUrlParameters();
}
Expand All @@ -60,7 +70,7 @@ public function __construct(
*
* @return $this
*/
public function parseUrlParameters()
protected function parseUrlParameters()
{
$urlParts = explode('/', $this->url);
$this->parameters = [];
Expand All @@ -79,16 +89,57 @@ public function parseUrlParameters()
*
* @return array
*/
public function extractParameterValues($url)
protected function extractParameterValues($url)
{
$urlParts = explode('/', $url);
$this->values = [];
foreach ($this->parameters as $index => $name) {
$this->values[$name] = $urlParts[$index];
$value = $urlParts[$index];

$validValue = $this->checkParameterValueType($name, $value);
if ($validValue === false) {
$this->values = [];
break;
}
$this->values[$name] = $validValue;
}
return $this->values;
}

/**
* @param string $name
* @param mixed $value
*
* @return mixed|bool
*/
protected function checkParameterValueType($name, $value)
{
// If there's no : in the name, then it's not typed.
if (strpos($name, ':') === false) {
return $value;
}
list($key, $type) = explode(":", $name);

if (!in_array($type, ["int", "string", "float"])) {
return false;
}

if ($type === "int") {
if (is_numeric($value) && (int)$value == $value) {
return (int)$value;
}
return false;
} elseif ($type === "float") {
if (is_numeric($value) && (float)$value == $value) {
return (float)$value;
}
return false;
}

// by default return the string value
return $value;
}

/**
* Take $url and replace the 'values' with the parameters they represent. This gives us a 'corrected' url,
* which can be directly matched with the route's url.
Expand All @@ -97,7 +148,7 @@ public function extractParameterValues($url)
*
* @return string
*/
public function injectParameters($url)
protected function injectParameters($url)
{
$urlParts = explode('/', $url);
$parameters = array_flip($this->values);
Expand Down Expand Up @@ -203,6 +254,16 @@ public function getValue($key)
return $this->values[$key];
}

/**
* Get all values
*
* @return array
*/
public function getValues()
{
return $this->values;
}

/**
* @param array $parameters
*
Expand Down
7 changes: 7 additions & 0 deletions structure/app/Config/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ public function getValues()
'initLocations' => [
'app/Init',
],
'database' => [
'type' => 'mysql',
'location' => 'localhost',
'username' => 'username',
'password' => 'password',
'database' => 'database',
],
];
}
}
15 changes: 13 additions & 2 deletions structure/app/Controller/Home.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,21 @@ class Home
{
/**
* Index action
*
* @param \Parable\Routing\Route $route
*/
public function index(\Parable\Routing\Route $route)
{
}

/**
* @param \Parable\Routing\Route $route
* @param int $id
* @param mixed $name
*/
public function test(\Parable\Routing\Route $route, $id, $name)
{
/** @var \Parable\Http\Values\Internal $internal */
$internal = \Parable\DI\Container::get(\Parable\Http\Values\Internal::class);
$internal->set('id', $id);
$internal->set('name', $name);
}
}
15 changes: 12 additions & 3 deletions structure/app/Init/Example.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

class Example
{
public function __construct()
{
public function __construct(
\Parable\Events\Hook $hook,
\Parable\Http\Response $response
) {
/*
* Init scripts function very simply: They need to be in Init namespace, their filename should match their
* classname, and the location of these scripts needs to be set in a Config file, using the root key
Expand All @@ -15,7 +17,7 @@ public function __construct()
* done. Init scripts are the perfect place to hook into events before anything else is done. This allows,
* for example, the following:
*
* $hook->into('parable_dispatch_before', function() use ($response, $view) {
* $hook->into('parable_dispatch_before', function($payload, $trigger) use ($response, $view) {
* $response->prependContent($view->partial('app/View/Layout/header.phtml'));
* });
*
Expand All @@ -27,6 +29,13 @@ public function __construct()
*
* If you don't want or plan to use Init scripts, you can safely remove this directory. It won't complain if
* there's no init scripts available. You can also remove the key from the Config.
*
* Below is a simple way of hooking into the 404 event.
*/

$hook->into('parable_http_404', function($trigger, $url) use ($response) {
$response->setContent("404 - page '{$url}' could not be found");
$response->send();
});
}
}
22 changes: 21 additions & 1 deletion structure/app/Routes/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,32 @@ class App extends \Parable\Framework\Routes\Base
public function get()
{
return [
/*
* Valid method values are GET, POST, PUT, DELETE, PATCH. If the route is requested
* through a method it does not support, a 404 is thrown.
*/
'index' => [
'methods' => 'GET',
'methods' => ['GET'],
'url' => '/',
'controller' => \Controller\Home::class,
'action' => 'index',
],
/*
* If you add parameters to a URL by adding {param} anywhere, it is REQUIRED. Leaving
* the parameter off in the requested URL will cause a 404 to be thrown.
*
* Within a URL, you may specify what type a parameter is required to be.
*
* Valid values: {param:int}, {param:string}, {param:float}
*
* If the value passed is invalid, a 404 is thrown.
*/
'test-parameters' => [
'methods' => ['GET'],
'url' => '/test/{id:int}/{name}',
'controller' => \Controller\Home::class,
'action' => 'test',
],
];
}
}
70 changes: 70 additions & 0 deletions structure/app/View/Home/test.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php /** @var $this \Parable\Framework\View */ ?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<title>Hello from <?=$this->config->get('app.title');?> <?=$this->app->getVersion();?></title>

<!-- Raleway font from google fonts -->
<link href='https://fonts.googleapis.com/css?family=Raleway:100,400' rel='stylesheet' type='text/css'>

<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />

<link rel="icon" type="image/png" href="<?=$this->url->getUrl('images/icon-32.png');?>" />

<style>
* {
font-family: 'Raleway', sans-serif;
font-weight: 400;
}
.container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
width: 100%;
height: 4rem;
line-height: 4rem;

text-align: center;
color: #4533b7;

animation: fade-in 2s forwards;
}
a {
color: #7e5deb;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.container header {
font-weight: 100;
font-size: 4.15rem;
}
.container aside {
font-size: 0.72rem;
margin-top: -0.8rem;
letter-spacing: 4px;
margin-left: 3px;
}
@keyframes fade-in {
from {opacity: 0;}
to {opacity: 1;}
}
</style>
</head>
<body>

test with multiple parameters:

<br /><br />

ID: <?=$this->internal->get('id');?><br />
NAME: <?=$this->internal->get('name');?><br />

</body>
</html>

0 comments on commit 8d2baf8

Please sign in to comment.