Skip to content

Commit

Permalink
Proper URL serialization [closes #30]
Browse files Browse the repository at this point in the history
  • Loading branch information
rtens committed Feb 24, 2016
1 parent 8985005 commit e76c1b6
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 68 deletions.
17 changes: 1 addition & 16 deletions src/delivery/web/BreadCrumbsTrail.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public function getLastCrumb() {
* @return array|BreadCrumb[]
*/
public function updateCrumbs(Action $action, $actionId) {
$current = new BreadCrumb($action->caption(), $this->makeTarget($actionId, $action));
$current = new BreadCrumb($action->caption(), (string)Url::relative($actionId, $this->readRawParameters($action)));

$newCrumbs = [];
foreach ($this->crumbs as $crumb) {
Expand All @@ -71,21 +71,6 @@ public function reset() {
$this->crumbs = [];
}

private function makeTarget($actionId, Action $action) {
$target = $actionId;

$parameters = $this->readRawParameters($action);
if ($parameters) {
$keyValues = [];
foreach ($parameters as $key => $value) {
$keyValues[] = urlencode($key) . '=' . urlencode($value);
}
$target .= '?' . implode('&', $keyValues);
}

return $target;
}

private function readRawParameters(Action $action) {
$values = [];

Expand Down
185 changes: 185 additions & 0 deletions src/delivery/web/Url.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php
namespace rtens\domin\delivery\web;

class Url {

const HOST_PREFIX = '//';
const PORT_SEPARATOR = ':';
const SCHEME_SEPARATOR = ':';
const QUERY_STRING_SEPARATOR = '?';
const FRAGMENT_SEPARATOR = '#';
const MAX_PARAM_LENGTH = 512;

/** @var null|string */
private $scheme;

/** @var null|string */
private $host;

/** @var null|int */
private $port;

/** @var array */
private $path;

/** @var array */
private $parameters;

/** @var string|null */
private $fragment;

/**
* @param string $scheme
* @param string $host
* @param int $port
* @param array $path
* @param array $parameters
* @param string|null $fragment
*/
function __construct($scheme = 'http', $host = null, $port = 80, array $path = [], $parameters = [], $fragment = null) {
$this->scheme = $scheme;
$this->host = $host;
$this->port = $port;
$this->path = $path;
$this->parameters = $parameters;
$this->fragment = $fragment;
}

/**
* @param array|string $path
* @param array $parameters
* @param null|string $fragment
* @return Url
*/
public static function relative($path, array $parameters = [], $fragment = null) {
return new Url(null, null, null, (array)$path, $parameters, $fragment);
}

/**
* @return Url
*/
private function copy() {
return new Url(
$this->scheme,
$this->host,
$this->port,
$this->path,
$this->parameters,
$this->fragment
);
}

/**
* @return null|string
*/
public function getScheme() {
return $this->scheme;
}
/**
* @return null|string
*/
public function getHost() {
return $this->host;
}
/**
* @return int|null
*/
public function getPort() {
return $this->port;
}
/**
* @return array
*/
public function getParameters() {
return $this->parameters;
}

/**
* @param array $parameters
* @return static
*/
public function withParameters(array $parameters) {
$newUrl = $this->copy();
$newUrl->parameters = $parameters;
return $newUrl;
}
/**
* @param string $key
* @param mixed $value
* @return static
*/
public function withParameter($key, $value) {
$newUrl = $this->copy();
$newUrl->parameters[$key] = $value;
return $newUrl;
}
/**
* @return null|string
*/
public function getFragment() {
return $this->fragment;
}
/**
* @return array
*/
public function getPath() {
return $this->path;
}
/**
* @param array $path
* @return static
*/
public function withPath(array $path) {
$url = $this->copy();
$url->path = $path;
return $url;
}

/**
* @param array $path
* @return Url
*/
public function append(array $path) {
$url = $this->copy();
$url->path = array_merge($url->path, $path);
return $url;
}

public function __toString() {
$queries = array();
foreach ($this->flattenParams($this->parameters) as $key => $value) {
$queries[] = $key . '=' . urlencode($value);
}
$port = $this->port ? self::PORT_SEPARATOR . $this->port : '';
$scheme = $this->scheme ? $this->scheme . self::SCHEME_SEPARATOR : '';
$server = $this->host ? $scheme . self::HOST_PREFIX . $this->host . $port : '';
return
$server
. implode('/', $this->path)
. ($queries ? self::QUERY_STRING_SEPARATOR . implode('&', $queries) : '')
. ($this->fragment ? self::FRAGMENT_SEPARATOR . $this->fragment : '');
}

private function flattenParams($parameters, $i = 0) {
$flat = [];
foreach ($parameters as $key => $value) {
if (is_array($value)) {
foreach ($this->flattenParams($value, $i + 1) as $subKey => $subValue) {
$flatKey = $i ? "{$key}][{$subKey}" : "{$key}[{$subKey}]";
$flat = $this->set($flat, $flatKey, $subValue);
}
} else {
$flat = $this->set($flat, $key, $value);
}
}
return $flat;
}

private function set(array $map, $key, $value) {
$cabBeCasted = !is_object($value) || method_exists($value, '__toString');
if ($cabBeCasted && strlen((string)$value) <= self::MAX_PARAM_LENGTH) {
$map[$key] = $value;
}
return $map;
}
}
15 changes: 2 additions & 13 deletions src/delivery/web/menu/ActionMenuItem.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php namespace rtens\domin\delivery\web\menu;

use rtens\domin\delivery\web\Element;
use rtens\domin\delivery\web\Url;

class ActionMenuItem implements MenuItem {

Expand All @@ -21,22 +22,10 @@ public function __construct($caption, $actionId, $parameters = []) {

public function render() {
return new Element('li', [], [
new Element('a', ['href' => $this->getTarget()], [$this->getCaption()])
new Element('a', ['href' => (string)Url::relative($this->actionId, $this->parameters)], [$this->getCaption()])
]);
}

private function getTarget() {
$target = $this->actionId;
if ($this->parameters) {
$keyValues = [];
foreach ($this->parameters as $key => $value) {
$keyValues[] = urlencode($key) . '=' . urlencode($value);
}
$target .= '?' . implode('&', $keyValues);
}
return $target;
}

private function getCaption() {
return $this->caption;
}
Expand Down
17 changes: 2 additions & 15 deletions src/delivery/web/renderers/dashboard/ActionPanelRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use rtens\domin\delivery\web\Element;
use rtens\domin\delivery\web\renderers\dashboard\types\ActionPanel;
use rtens\domin\delivery\web\renderers\dashboard\types\Panel;
use rtens\domin\delivery\web\Url;
use rtens\domin\delivery\web\WebRenderer;
use rtens\domin\Parameter;

Expand Down Expand Up @@ -51,25 +52,11 @@ public function render($value) {
return (string)(new Panel($heading, $this->getContent($value)))
->setMaxHeight($value->getMaxHeight())
->setRightHeading([new Element('a', [
'href' => $this->makeUrl($value)
'href' => (string)Url::relative($value)
], [new Element('span', ['class' => 'glyphicon glyphicon-circle-arrow-right'])])])
->render($this->renderers);
}

private function makeUrl(ActionPanel $panel) {
$url = $panel->getActionId();

if ($panel->getParameters()) {
$keyValues = [];
foreach ($panel->getParameters() as $key => $value) {
$keyValues[] = urlencode($key) . '=' . urlencode($value);
}
$url .= '?' . implode('&', $keyValues);
}

return $url;
}

/**
* @param mixed $value
* @return array|Element[]
Expand Down
17 changes: 2 additions & 15 deletions src/delivery/web/renderers/link/LinkPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use rtens\domin\delivery\web\Element;
use rtens\domin\delivery\web\ExecutionToken;
use rtens\domin\delivery\web\resources\ExecutionResource;
use rtens\domin\delivery\web\Url;
use rtens\domin\delivery\web\WebCommentParser;

class LinkPrinter {
Expand Down Expand Up @@ -84,7 +85,7 @@ private function createLinks($object, $classes = '') {
$parameters[ExecutionResource::TOKEN_ARG] = $this->token->generate($link->actionId());
}

$url = $this->makeUrl($link->actionId(), $parameters);
$url = (string)Url::relative($link->actionId(), $parameters);

$attributes = ['class' => $classes, 'href' => $url];
if ($link->confirm() !== null) {
Expand All @@ -99,18 +100,4 @@ private function createLinks($object, $classes = '') {
]);
}, $this->links->getLinks($object));
}

private function makeUrl($actionId, array $parameters) {
$url = $actionId;

if ($parameters) {
$keyValues = [];
foreach ($parameters as $key => $value) {
$keyValues[] = urlencode($key) . '=' . urlencode($value);
}
$url .= '?' . implode('&', $keyValues);
}

return $url;
}
}
12 changes: 3 additions & 9 deletions src/execution/RedirectResult.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php
namespace rtens\domin\execution;

use rtens\domin\delivery\web\Url;

class RedirectResult implements ExecutionResult {

/** @var string */
Expand All @@ -22,14 +24,6 @@ public function __construct($target, array $parameters = []) {
* @return string
*/
public function getUrl() {
$url = $this->target;
if ($this->parameters) {
$keyValues = [];
foreach ($this->parameters as $key => $value) {
$keyValues[] = urlencode($key) . '=' . urlencode($value);
}
$url .= '?' . implode('&', $keyValues);
}
return $url;
return (string)Url::relative($this->target, $this->parameters);
}
}

0 comments on commit e76c1b6

Please sign in to comment.