Basic Menu generation

This commit is contained in:
Timothy Warren 2015-10-09 14:34:55 -04:00
parent 728850da08
commit a8e3c594e3
22 changed files with 391 additions and 273 deletions

View File

@ -5,47 +5,24 @@
namespace Aviat\AnimeClient; namespace Aviat\AnimeClient;
use \Whoops\Handler\PrettyPageHandler;
use \Whoops\Handler\JsonResponseHandler;
use Aura\Html\HelperLocatorFactory; use Aura\Html\HelperLocatorFactory;
use \Aura\Web\WebFactory; use Aura\Web\WebFactory;
use \Aura\Router\RouterFactory; use Aura\Router\RouterFactory;
use \Aura\Session\SessionFactory; use Aura\Session\SessionFactory;
use Aviat\Ion\Di\Container; use Aviat\Ion\Di\Container;
require _dir(SRC_DIR, '/functions.php');
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Setup DI container // Setup DI container
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
$di = function() { return function(array $config_array = []) {
$container = new Container(); $container = new Container();
// -------------------------------------------------------------------------
// Setup error handling
// -------------------------------------------------------------------------
$whoops = new \Whoops\Run();
// Set up default handler for general errors
$defaultHandler = new PrettyPageHandler();
$whoops->pushHandler($defaultHandler);
// Set up json handler for ajax errors
$jsonHandler = new JsonResponseHandler();
$jsonHandler->onlyForAjaxRequests(TRUE);
$whoops->pushHandler($jsonHandler);
$whoops->register();
$container->set('error-handler', $defaultHandler);
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Injected Objects // Injected Objects
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Create Config Object // Create Config Object
$config = new Config(); $config = new Config($config_array);
$container->set('config', $config); $container->set('config', $config);
// Create Aura Router Object // Create Aura Router Object
@ -79,14 +56,11 @@ $di = function() {
$container->set('url-generator', new UrlGenerator($container)); $container->set('url-generator', new UrlGenerator($container));
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Router // Dispatcher
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
$router = new Router($container); $container->set('dispatcher', new Dispatcher($container));
$container->set('router', $router);
return $container; return $container;
}; };
$di()->get('router')->dispatch();
// End of bootstrap.php // End of bootstrap.php

View File

@ -1,24 +1,7 @@
<?php <?php
return [ return [
'top' => [
'default' => '',
'items' => [
'anime_list' => '{anime_list}',
'manga_list' => '{manga_list}',
'collection' => '{collection}'
]
],
'view_type' => [
'is_parent' => FALSE,
'default' => 'cover_view',
'items' => [
'cover_view' => '{parent}',
'list_view' => '{parent}/list'
]
],
'anime_list' => [ 'anime_list' => [
'default' => '',
'route_prefix' => '/anime', 'route_prefix' => '/anime',
'items' => [ 'items' => [
'watching' => '/watching', 'watching' => '/watching',
@ -27,13 +10,9 @@ return [
'dropped' => '/dropped', 'dropped' => '/dropped',
'completed' => '/completed', 'completed' => '/completed',
'all' => '/all' 'all' => '/all'
],
'children' => [
'view_type'
] ]
], ],
'manga_list' => [ 'manga_list' => [
'default' => '',
'route_prefix' => '/manga', 'route_prefix' => '/manga',
'items' => [ 'items' => [
'reading' => '/reading', 'reading' => '/reading',
@ -42,20 +21,13 @@ return [
'dropped' => '/dropped', 'dropped' => '/dropped',
'completed' => '/completed', 'completed' => '/completed',
'all' => '/all' 'all' => '/all'
],
'children' => [
'view_type'
] ]
], ],
'collection' => [ 'collection' => [
'default' => '',
'route_prefix' => '/collection', 'route_prefix' => '/collection',
'items' => [ 'items' => [
'anime' => '/anime', 'anime' => '/anime',
'manga' => '/manga', 'manga' => '/manga',
],
'children' => [
'view_type'
] ]
] ]
]; ];

View File

@ -8,7 +8,6 @@
<thead> <thead>
<tr> <tr>
<th>Title</th> <th>Title</th>
<th>Alternate Title</th>
<th>Airing Status</th> <th>Airing Status</th>
<th>Score</th> <th>Score</th>
<th>Type</th> <th>Type</th>
@ -25,19 +24,21 @@
<a href="<?= $item['anime']['url'] ?>"> <a href="<?= $item['anime']['url'] ?>">
<?= $item['anime']['title'] ?> <?= $item['anime']['title'] ?>
</a> </a>
<?= ( ! empty($item['anime']['alternate_title'])) ? " <br /> " . $item['anime']['alternate_title'] : "" ?>
</td> </td>
<td class="align_left"><?= $item['anime']['alternate_title'] ?></td>
<td class="align_left"><?= $item['airing']['status'] ?></td> <td class="align_left"><?= $item['airing']['status'] ?></td>
<td><?= $item['user_rating'] ?> / 10 </td> <td><?= $item['user_rating'] ?> / 10 </td>
<td><?= $item['anime']['type'] ?></td> <td><?= $item['anime']['type'] ?></td>
<td>Episodes: <?= $item['episodes']['watched'] ?> / <?= $item['episodes']['total'] ?></td> <td>Episodes: <?= $item['episodes']['watched'] ?> / <?= $item['episodes']['total'] ?></td>
<td><?= $item['anime']['age_rating'] ?></td> <td><?= $item['anime']['age_rating'] ?></td>
<td><?= $item['notes'] ?></td> <td><?= $item['notes'] ?></td>
<td class="flex flex-justify-space-around align-left"> <td class="align-left">
<ul>
<?php sort($item['anime']['genres']) ?> <?php sort($item['anime']['genres']) ?>
<?php foreach($item['anime']['genres'] as $genre): ?> <?php foreach($item['anime']['genres'] as $genre): ?>
<span><?= $genre ?></span> <li><?= $genre ?></li>
<?php endforeach ?> <?php endforeach ?>
</ul>
</td> </td>
</tr> </tr>
<?php endforeach ?> <?php endforeach ?>

View File

@ -24,20 +24,14 @@
<?php endif */ ?> <?php endif */ ?>
</span> </span>
</h1> </h1>
<?php if ( ! empty($nav_routes)): ?>
<nav> <nav>
<ul> <?= $helper->menu($menu_name) ?>
<?php foreach($nav_routes as $title => $nav_path): ?>
<li class="<?= is_selected($nav_path, $route_path) ?>"><a href="<?= $urlGenerator->url($nav_path) ?>"><?= $title ?></a></li>
<?php endforeach ?>
</ul>
<?php if (is_view_page()): ?> <?php if (is_view_page()): ?>
<br /> <br />
<ul> <ul class="align_right">
<li class="<?= is_not_selected('list', last_segment()) ?>"><a href="<?= $urlGenerator->url($route_path) ?>">Cover View</a></li> <li class="<?= is_not_selected('list', $urlGenerator->last_segment()) ?>"><a href="<?= $urlGenerator->url($route_path) ?>">Cover View</a></li>
<li class="<?= is_selected('list', last_segment()) ?>"><a href="<?= $urlGenerator->url("{$route_path}/list") ?>">List View</a></li> <li class="<?= is_selected('list', $urlGenerator->last_segment()) ?>"><a href="<?= $urlGenerator->url("{$route_path}/list") ?>">List View</a></li>
</ul> </ul>
<?php endif ?> <?php endif ?>
</nav> </nav>
<br /> <br />
<?php endif ?>

View File

@ -2,6 +2,10 @@
/** /**
* Here begins everything! * Here begins everything!
*/ */
use Whoops\Handler\PrettyPageHandler;
use Whoops\Handler\JsonResponseHandler;
use Aviat\AnimeClient\Config;
// Work around the silly timezone error // Work around the silly timezone error
$timezone = ini_get('date.timezone'); $timezone = ini_get('date.timezone');
@ -47,6 +51,37 @@ spl_autoload_register(function($class) {
// Dependency setup // Dependency setup
require _dir(ROOT_DIR, '/vendor/autoload.php'); require _dir(ROOT_DIR, '/vendor/autoload.php');
require _dir(APP_DIR, 'bootstrap.php'); require _dir(SRC_DIR, '/functions.php');
// -------------------------------------------------------------------------
// Setup error handling
// -------------------------------------------------------------------------
$whoops = new \Whoops\Run();
// Set up default handler for general errors
$defaultHandler = new PrettyPageHandler();
$whoops->pushHandler($defaultHandler);
// Set up json handler for ajax errors
$jsonHandler = new JsonResponseHandler();
$jsonHandler->onlyForAjaxRequests(TRUE);
$whoops->pushHandler($jsonHandler);
//$whoops->register();
// -----------------------------------------------------------------------------
// Dependency Injection setup
// -----------------------------------------------------------------------------
require _dir(CONF_DIR, 'base_config.php'); // $base_config
require _dir(CONF_DIR, 'config.php'); // $config
$config_array = array_merge($base_config, $config);
$di = require _dir(APP_DIR, 'bootstrap.php');
$container = $di($config_array);
$container->set('error-handler', $defaultHandler);
// -----------------------------------------------------------------------------
// Dispatch to the current route
// -----------------------------------------------------------------------------
$container->get('dispatcher')();
// End of index.php // End of index.php

View File

@ -5,6 +5,9 @@ namespace Aviat\AnimeClient\Auth;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\AnimeClient\Model\Anime as AnimeModel; use Aviat\AnimeClient\Model\Anime as AnimeModel;
/**
* Hummingbird API Authentication
*/
class HummingbirdAuth { class HummingbirdAuth {
use \Aviat\Ion\Di\ContainerAware; use \Aviat\Ion\Di\ContainerAware;
@ -31,19 +34,32 @@ class HummingbirdAuth {
public function __construct(ContainerInterface $container) public function __construct(ContainerInterface $container)
{ {
$this->setContainer($container); $this->setContainer($container);
$this->session = $container->get('sesion') $this->session = $container->get('session')
->getSegment(__NAMESPACE__); ->getSegment(__NAMESPACE__);
$this->model = new AnimeModel($container); $this->model = new AnimeModel($container);
} }
/**
* Make the appropriate authentication call,
* and save the resulting auth token if successful
*
* @param string $username
* @param string $password
* @return boolean
*/
public function authenticate($username, $password) public function authenticate($username, $password)
{ {
return $this->model->authenticate();
} }
/**
* Retrieve the authentication token from the session
*
* @return string
*/
public function get_auth_token() public function get_auth_token()
{ {
return $this->session->get('auth_token');
} }
} }

View File

@ -15,27 +15,16 @@ class Config {
* *
* @var array * @var array
*/ */
protected $config = []; protected $map = [];
/** /**
* Constructor * Constructor
* *
* @param array $config_files * @param array $config_files
*/ */
public function __construct(array $config_files = []) public function __construct(array $config_array = [])
{ {
// @codeCoverageIgnoreStart $this->map = $config_array;
if (empty($config_files))
{
require_once \_dir(CONF_DIR, 'config.php'); // $config
require_once \_dir(CONF_DIR, 'base_config.php'); // $base_config
$this->config = array_merge($config, $base_config);
}
else // @codeCoverageIgnoreEnd
{
$this->config = $config_files;
}
} }
/** /**
@ -46,9 +35,9 @@ class Config {
*/ */
public function get($key) public function get($key)
{ {
if (isset($this->config[$key])) if (array_key_exists($key, $this->map))
{ {
return $this->config[$key]; return $this->map[$key];
} }
return NULL; return NULL;
@ -63,7 +52,7 @@ class Config {
*/ */
public function set($key, $value) public function set($key, $value)
{ {
$this->config[$key] = $value; $this->map[$key] = $value;
return $this; return $this;
} }
} }

View File

@ -56,7 +56,7 @@ class Controller {
protected $base_data = [ protected $base_data = [
'url_type' => 'anime', 'url_type' => 'anime',
'other_type' => 'manga', 'other_type' => 'manga',
'nav_routes' => [] 'menu_name' => ''
]; ];
/** /**
@ -105,7 +105,7 @@ class Controller {
{ {
$errorHandler = $this->container->get('error-handler'); $errorHandler = $this->container->get('error-handler');
$errorHandler->addDataTable('Template Data', $data); $errorHandler->addDataTable('Template Data', $data);
$router = $this->container->get('router'); $router = $this->container->get('dispatcher');
if (isset($this->base_data)) if (isset($this->base_data))
{ {
@ -131,7 +131,7 @@ class Controller {
* *
* @param HtmlView $view * @param HtmlView $view
* @param string $template * @param string $template
* @param array|object $data * @param array $data
* @return void * @return void
*/ */
public function render_full_page($view, $template, array $data) public function render_full_page($view, $template, array $data)
@ -145,10 +145,10 @@ class Controller {
* Output a template to HTML, using the provided data * Output a template to HTML, using the provided data
* *
* @param string $template * @param string $template
* @param array|object $data * @param array $data
* @return void * @return void
*/ */
public function outputHTML($template, $data = []) public function outputHTML($template, array $data = [])
{ {
$view = new HtmlView($this->container); $view = new HtmlView($this->container);
$this->render_full_page($view, $template, $data); $this->render_full_page($view, $template, $data);

View File

@ -34,20 +34,6 @@ class Anime extends BaseController {
*/ */
protected $base_data; protected $base_data;
/**
* Route mapping for main navigation
* @var array $nav_routes
*/
private $nav_routes = [
'Watching' => '/anime/watching{/view}',
'Plan to Watch' => '/anime/plan_to_watch{/view}',
'On Hold' => '/anime/on_hold{/view}',
'Dropped' => '/anime/dropped{/view}',
'Completed' => '/anime/completed{/view}',
'Collection' => '/collection/view{/view}',
'All' => '/anime/all{/view}'
];
/** /**
* Constructor * Constructor
* *
@ -65,10 +51,10 @@ class Anime extends BaseController {
$this->model = new AnimeModel($container); $this->model = new AnimeModel($container);
$this->collection_model = new AnimeCollectionModel($container); $this->collection_model = new AnimeCollectionModel($container);
$this->base_data = array_merge($this->base_data, [ $this->base_data = array_merge($this->base_data, [
'menu_name' => 'anime_list',
'message' => '', 'message' => '',
'url_type' => 'anime', 'url_type' => 'anime',
'other_type' => 'manga', 'other_type' => 'manga',
'nav_routes' => $this->nav_routes,
'config' => $this->config, 'config' => $this->config,
]); ]);
} }

View File

@ -19,9 +19,9 @@ class Collection extends BaseController {
/** /**
* The anime collection model * The anime collection model
* @var object $collection_model * @var object $anime_collection_model
*/ */
private $collection_model; private $anime_collection_model;
/** /**
* Data to ve sent to all routes in this controller * Data to ve sent to all routes in this controller
@ -35,20 +35,6 @@ class Collection extends BaseController {
*/ */
protected $urlGenerator; protected $urlGenerator;
/**
* Route mapping for main navigation
* @var array $nav_routes
*/
private $nav_routes = [
'Watching' => '/anime/watching{/view}',
'Plan to Watch' => '/anime/plan_to_watch{/view}',
'On Hold' => '/anime/on_hold{/view}',
'Dropped' => '/anime/dropped{/view}',
'Completed' => '/anime/completed{/view}',
'Collection' => '/collection/view{/view}',
'All' => '/anime/all{/view}'
];
/** /**
* Constructor * Constructor
* *
@ -58,18 +44,13 @@ class Collection extends BaseController {
{ {
parent::__construct($container); parent::__construct($container);
if ($this->config->get('show_anime_collection') === FALSE)
{
unset($this->nav_routes['Collection']);
}
$this->urlGenerator = $container->get('url-generator'); $this->urlGenerator = $container->get('url-generator');
$this->collection_model = new AnimeCollectionModel($container); $this->anime_anime_collection_model = new AnimeCollectionModel($container);
$this->base_data = array_merge($this->base_data, [ $this->base_data = array_merge($this->base_data, [
'menu_name' => 'collection',
'message' => '', 'message' => '',
'url_type' => 'anime', 'url_type' => 'anime',
'other_type' => 'manga', 'other_type' => 'manga',
'nav_routes' => $this->nav_routes,
'config' => $this->config, 'config' => $this->config,
]); ]);
} }
@ -98,12 +79,12 @@ class Collection extends BaseController {
'list' => 'list' 'list' => 'list'
]; ];
$data = $this->collection_model->get_collection(); $data = $this->anime_collection_model->get_collection();
$this->outputHTML('collection/' . $view_map[$view], [ $this->outputHTML('collection/' . $view_map[$view], [
'title' => $this->config->get('whose_list') . "'s Anime Collection", 'title' => $this->config->get('whose_list') . "'s Anime Collection",
'sections' => $data, 'sections' => $data,
'genres' => $this->collection_model->get_genre_list() 'genres' => $this->anime_collection_model->get_genre_list()
]); ]);
} }
@ -121,8 +102,8 @@ class Collection extends BaseController {
'action' => $action, 'action' => $action,
'action_url' => $this->urlGenerator->full_url("collection/" . strtolower($action)), 'action_url' => $this->urlGenerator->full_url("collection/" . strtolower($action)),
'title' => $this->config->whose_list . " Anime Collection &middot; {$action}", 'title' => $this->config->whose_list . " Anime Collection &middot; {$action}",
'media_items' => $this->collection_model->get_media_type_list(), 'media_items' => $this->anime_collection_model->get_media_type_list(),
'item' => ($action === "Edit") ? $this->collection_model->get($id) : [] 'item' => ($action === "Edit") ? $this->anime_collection_model->get($id) : []
]); ]);
} }
@ -139,7 +120,7 @@ class Collection extends BaseController {
$this->redirect("collection/view", 303, "anime"); $this->redirect("collection/view", 303, "anime");
} }
$this->collection_model->update($data); $this->anime_collection_model->update($data);
$this->redirect("collection/view", 303, "anime"); $this->redirect("collection/view", 303, "anime");
} }
@ -157,7 +138,7 @@ class Collection extends BaseController {
$this->redirect("collection/view", 303, "anime"); $this->redirect("collection/view", 303, "anime");
} }
$this->collection_model->add($data); $this->anime_collection_model->add($data);
$this->redirect("collection/view", 303, "anime"); $this->redirect("collection/view", 303, "anime");
} }

View File

@ -26,20 +26,6 @@ class Manga extends Controller {
*/ */
protected $base_data; protected $base_data;
/**
* Route mapping for main navigation
* @var array $nav_routes
*/
private $nav_routes = [
'Reading' => '/manga/reading{/view}',
'Plan to Read' => '/manga/plan_to_read{/view}',
'On Hold' => '/manga/on_hold{/view}',
'Dropped' => '/manga/dropped{/view}',
'Completed' => '/manga/completed{/view}',
'All' => '/manga/all{/view}'
];
/** /**
* Constructor * Constructor
* *
@ -51,10 +37,10 @@ class Manga extends Controller {
$config = $container->get('config'); $config = $container->get('config');
$this->model = new MangaModel($container); $this->model = new MangaModel($container);
$this->base_data = array_merge($this->base_data, [ $this->base_data = array_merge($this->base_data, [
'menu_name' => 'manga_list',
'config' => $this->config, 'config' => $this->config,
'url_type' => 'manga', 'url_type' => 'manga',
'other_type' => 'anime', 'other_type' => 'anime'
'nav_routes' => $this->nav_routes
]); ]);
} }

View File

@ -12,7 +12,7 @@ use Aviat\Ion\Di\ContainerInterface;
/** /**
* Basic routing/ dispatch * Basic routing/ dispatch
*/ */
class Router extends RoutingBase { class Dispatcher extends RoutingBase {
/** /**
* The route-matching object * The route-matching object
@ -109,7 +109,7 @@ class Router extends RoutingBase {
* @param object $route * @param object $route
* @return void * @return void
*/ */
public function dispatch($route = NULL) public function __invoke($route = NULL)
{ {
$error_handler = $this->container->get('error-handler'); $error_handler = $this->container->get('error-handler');
@ -264,4 +264,4 @@ class Router extends RoutingBase {
return $output_routes; return $output_routes;
} }
} }
// End of Router.php // End of Dispatcher.php

View File

@ -2,11 +2,9 @@
namespace Aviat\AnimeClient\Helper; namespace Aviat\AnimeClient\Helper;
use Aura\Html\Helper\AbstractHelper;
use Aviat\AnimeClient\MenuGenerator; use Aviat\AnimeClient\MenuGenerator;
class Menu extends AbstractHelper { class Menu {
use \Aviat\Ion\Di\ContainerAware; use \Aviat\Ion\Di\ContainerAware;

View File

@ -1,19 +0,0 @@
<?php
namespace Aviat\AnimeClient\Helper;
use Aura\Html\Helper\AbstractHelper;
use Aviat\AnimeClient\UrlGenerator;
class UrlHelper extends AbstractHelper {
/**
* Helper entry point
*
* @return UrlHelper
*/
public function __invoke()
{
return $this;
}
}

View File

@ -7,9 +7,8 @@ use Aviat\Ion\Di\ContainerInterface;
/** /**
* Helper object to manage menu creation and selection * Helper object to manage menu creation and selection
*/ */
class MenuGenerator extends RoutingBase { class MenuGenerator extends UrlGenerator {
use \Aviat\Ion\Di\ContainerAware;
use \Aviat\Ion\StringWrapper; use \Aviat\Ion\StringWrapper;
use \Aviat\Ion\ArrayWrapper; use \Aviat\Ion\ArrayWrapper;
@ -27,6 +26,13 @@ class MenuGenerator extends RoutingBase {
*/ */
protected $menus; protected $menus;
/**
* Request object
*
* @var Aura\Web\Request
*/
protected $request;
/** /**
* Create menu generator * Create menu generator
* *
@ -37,6 +43,7 @@ class MenuGenerator extends RoutingBase {
parent::__construct($container); parent::__construct($container);
$this->menus = $this->config->get('menus'); $this->menus = $this->config->get('menus');
$this->helper = $container->get('html-helper'); $this->helper = $container->get('html-helper');
$this->request = $container->get('request');
} }
/** /**
@ -49,16 +56,11 @@ class MenuGenerator extends RoutingBase {
// Note: Children menus have urls based on the // Note: Children menus have urls based on the
// current url path // current url path
/* /*
$parsed = [ parsed = {
'menu_name' => [ menu_name: {
'items' => [ title: 'full_url_path'
'title' => 'full_url_path', }
], }
'children' => [
'title' => 'full_url_path'
]
]
]
*/ */
$parsed = []; $parsed = [];
@ -68,14 +70,8 @@ class MenuGenerator extends RoutingBase {
$parsed[$name] = []; $parsed[$name] = [];
foreach ($menu['items'] as $path_name => $partial_path) foreach ($menu['items'] as $path_name => $partial_path)
{ {
$title = $this->string($path_name)->humanize()->titleize(); $title = (string) $this->string($path_name)->humanize()->titleize();
$parsed[$name]['items'][$title] = $this->string($menu['route_prefix'])->append($partial_path); $parsed[$name][$title] = (string) $this->string($menu['route_prefix'])->append($partial_path);
}
// @TODO: Handle child menu(s)
if (count($menu['children']) > 0)
{
} }
} }
@ -91,16 +87,29 @@ class MenuGenerator extends RoutingBase {
public function generate($menu) public function generate($menu)
{ {
$parsed_config = $this->parse_config(); $parsed_config = $this->parse_config();
// Bail out early on invalid menu
if ( ! $this->arr($parsed_config)->has_key($menu))
{
return '';
}
$menu_config = $parsed_config[$menu]; $menu_config = $parsed_config[$menu];
// Array of list items to add to the main menu foreach($menu_config as $title => $path)
$main_menu = []; {
$selected = $this->string($path)->contains($this->path());
$link = $this->helper->a($this->url($path), $title);
$attrs = ($selected)
? ['class' => 'selected']
: [];
// Start the menu list $this->helper->ul()->rawItem($link, $attrs);
$helper->ul(); }
// Create the menu html
return $this->helper->ul();
} }
} }
// End of MenuGenerator.php // End of MenuGenerator.php

View File

@ -11,6 +11,9 @@ use Aviat\Ion\Di\ContainerInterface;
* Base for routing/url classes * Base for routing/url classes
*/ */
class RoutingBase { class RoutingBase {
use \Aviat\Ion\StringWrapper;
/** /**
* Injection Container * Injection Container
* @var Container $container * @var Container $container
@ -56,5 +59,58 @@ class RoutingBase {
return $routing_config[$key]; return $routing_config[$key];
} }
} }
/**
* Get the current url path
*
* @return string
*/
public function path()
{
$request = $this->container->get('request');
$path = $request->server->get('REQUEST_URI');
$cleaned_path = $this->string($path)
->trim()
->trimRight('/')
->ensureLeft('/');
return (string) $cleaned_path;
}
/**
* Get the url segments
*
* @return array
*/
public function segments()
{
$path = $this->path();
$segments = explode('/', $path);
return $segments;
}
/**
* Get a segment of the current url
*
* @param int $num
* @return string|null
*/
public function get_segment($num)
{
$segments = $this->segments();
return (array_key_exists($num, $segments)) ? $segments[$num] : NULL;
}
/**
* Retrieve the last url segment
*
* @return string
*/
public function last_segment()
{
$segments = $this->segments();
return end($segments);
}
} }
// End of RoutingBase.php // End of RoutingBase.php

View File

@ -28,7 +28,6 @@ class ArrayType {
'filter' => 'array_filter', 'filter' => 'array_filter',
'flip' => 'array_flip', 'flip' => 'array_flip',
'intersect' => 'array_intersect', 'intersect' => 'array_intersect',
'has_key' => 'array_key_exists',
'keys' => 'array_keys', 'keys' => 'array_keys',
'merge' => 'array_merge', 'merge' => 'array_merge',
'pad' => 'array_pad', 'pad' => 'array_pad',
@ -91,6 +90,16 @@ class ArrayType {
} }
} }
/**
* Does the passed key exist in the current array?
*
* @return bool
*/
public function has_key($key)
{
return array_key_exists($key, $this->arr);
}
/** /**
* Fill an array with the specified value * Fill an array with the specified value
* *

View File

@ -28,18 +28,6 @@ function is_not_selected($a, $b)
return ($a !== $b) ? 'selected' : ''; return ($a !== $b) ? 'selected' : '';
} }
/**
* Get the last segment of the current url
*
* @return string
*/
function last_segment()
{
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$segments = explode('/', $path);
return end($segments);
}
/** /**
* Determine whether to show the sub-menu * Determine whether to show the sub-menu
* *

View File

@ -1,13 +1,13 @@
<?php <?php
use Aviat\Ion\Di\Container; use Aviat\Ion\Di\Container;
use Aviat\AnimeClient\Router; use Aviat\AnimeClient\Dispatcher;
use Aviat\AnimeClient\Config; use Aviat\AnimeClient\Config;
use Aviat\AnimeClient\UrlGenerator; use Aviat\AnimeClient\UrlGenerator;
use Aura\Web\WebFactory; use Aura\Web\WebFactory;
use Aura\Router\RouterFactory; use Aura\Router\RouterFactory;
class RouterTest extends AnimeClient_TestCase { class DispatcherTest extends AnimeClient_TestCase {
protected $container; protected $container;
protected $router; protected $router;
@ -33,16 +33,24 @@ class RouterTest extends AnimeClient_TestCase {
'_FILES' => [] '_FILES' => []
]); ]);
$old_config = $this->container->get('config');
// Add the appropriate objects to the container // Add the appropriate objects to the container
$this->container = new Container([ $this->container = new Container([
'config' => new Config($config), 'config' => $old_config,
'request' => $web_factory->newRequest(), 'request' => $web_factory->newRequest(),
'response' => $web_factory->newResponse(), 'response' => $web_factory->newResponse(),
'aura-router' => $router_factory->newInstance(), 'aura-router' => $router_factory->newInstance(),
'error-handler' => new MockErrorHandler() 'error-handler' => new MockErrorHandler()
]); ]);
$this->router = new Router($this->container); if ( ! empty($config))
{
$config = new Config($config);
$this->container->set('config', $config);
}
$this->router = new Dispatcher($this->container);
$this->config = $this->container->get('config'); $this->config = $this->container->get('config');
$this->urlGenerator = new UrlGenerator($this->container); $this->urlGenerator = new UrlGenerator($this->container);
$this->container->set('url-generator', $this->urlGenerator); $this->container->set('url-generator', $this->urlGenerator);

View File

@ -0,0 +1,59 @@
<?php
use Aura\Html\HelperLocatorFactory;
use Aviat\Ion\Friend;
use Aviat\Ion\Di\Container;
use Aviat\AnimeClient\Helper;
use Aviat\AnimeClient\Config;
use Aviat\AnimeClient\MenuGenerator;
class MenuGeneratorTest extends AnimeClient_TestCase {
protected $generator;
protected $friend;
public function setUp()
{
parent::setUp();
$config = $this->container->get('config');
$config->set('menus', [
'anime_list' => [
'route_prefix' => '/anime',
'items' => [
'watching' => '/watching',
'plan_to_watch' => '/plan_to_watch',
'on_hold' => '/on_hold',
'dropped' => '/dropped',
'completed' => '/completed',
'all' => '/all'
]
],
]);
$this->generator = new MenuGenerator($this->container);
}
public function testSanity()
{
$generator = new MenuGenerator($this->container);
$this->assertInstanceOf('Aviat\AnimeClient\MenuGenerator', $generator);
}
public function testParseConfig()
{
$friend = new Friend($this->generator);
$expected = [
'anime_list' => [
'Watching' => '/anime/watching',
'Plan To Watch' => '/anime/plan_to_watch',
'On Hold' => '/anime/on_hold',
'Dropped' => '/anime/dropped',
'Completed' => '/anime/completed',
'All' => '/anime/all'
]
];
$this->assertEquals($expected, $friend->parse_config());
}
}

View File

@ -0,0 +1,51 @@
<?php
use Aviat\AnimeClient\RoutingBase;
class RoutingBaseTest extends AnimeClient_TestCase {
public function setUp()
{
parent::setUp();
$this->routingBase = new RoutingBase($this->container);
}
public function dataSegments()
{
return [
'empty_segment' => [
'request_uri' => ' // ',
'path' => '/',
'segments' => ['', ''],
'last_segment' => NULL
],
'three_segments' => [
'request_uri' => '/anime/watching/list ',
'path' => '/anime/watching/list',
'segments' => ['', 'anime', 'watching', 'list'],
'last_segment' => 'list'
]
];
}
/**
* @dataProvider dataSegments
*/
public function testSegments($request_uri, $path, $segments, $last_segment)
{
$this->setSuperGlobals([
'_SERVER' => [
'REQUEST_URI' => $request_uri
]
]);
$this->assertEquals($path, $this->routingBase->path(), "Path is invalid");
$this->assertEquals($segments, $this->routingBase->segments(), "Segments array is invalid");
$this->assertEquals($last_segment, $this->routingBase->last_segment(), "Last segment is invalid");
foreach($segments as $i => $value)
{
$this->assertEquals($value, $this->routingBase->get_segment($i), "Segment {$i} is invalid");
}
}
}

View File

@ -2,54 +2,12 @@
/** /**
* Global setup for unit tests * Global setup for unit tests
*/ */
use Aura\Web\WebFactory;
use Aviat\AnimeClient\Config; use Aviat\AnimeClient\Config;
use Aviat\Ion\Di\Container; use Aviat\Ion\Di\Container;
use Aviat\AnimeClient\UrlGenerator; use Aviat\AnimeClient\UrlGenerator;
// -----------------------------------------------------------------------------
// Mock the default error handler
// -----------------------------------------------------------------------------
class MockErrorHandler {
public function addDataTable($name, Array $values) {}
}
// -----------------------------------------------------------------------------
// Define a base testcase class
// -----------------------------------------------------------------------------
/**
* Base class for TestCases
*/
class AnimeClient_TestCase extends PHPUnit_Framework_TestCase {
protected $container;
public function setUp()
{
parent::setUp();
$config = new Config([
'asset_path' => '//localhost/assets/',
'databaase' => [],
'routes' => [
'common' => [],
'anime' => [],
'manga' => []
]
]);
$container = new Container([
'config' => $config,
'error-handler' => new MockErrorHandler()
]);
$container->set('url-generator', new UrlGenerator($container));
$this->container = $container;
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Autoloaders // Autoloaders
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -72,7 +30,7 @@ define('CONF_DIR', _dir(APP_DIR, 'config'));
define('SRC_DIR', _dir(ROOT_DIR, 'src')); define('SRC_DIR', _dir(ROOT_DIR, 'src'));
define('BASE_DIR', _dir(SRC_DIR, 'Base')); define('BASE_DIR', _dir(SRC_DIR, 'Base'));
require _dir(ROOT_DIR, '/vendor/autoload.php'); require _dir(ROOT_DIR, '/vendor/autoload.php');
require _dir(SRC_DIR, 'functions.php'); require _dir(SRC_DIR, '/functions.php');
/** /**
* Set up autoloaders * Set up autoloaders
@ -95,4 +53,71 @@ spl_autoload_register(function ($class) {
$_SESSION = []; $_SESSION = [];
$_COOKIE = []; $_COOKIE = [];
// -----------------------------------------------------------------------------
// Mock the default error handler
// -----------------------------------------------------------------------------
class MockErrorHandler {
public function addDataTable($name, array $values=[]) {}
}
// -----------------------------------------------------------------------------
// Define a base testcase class
// -----------------------------------------------------------------------------
/**
* Base class for TestCases
*/
class AnimeClient_TestCase extends PHPUnit_Framework_TestCase {
protected $container;
public function setUp()
{
parent::setUp();
$config_array = [
'asset_path' => '//localhost/assets/',
'databaase' => [],
'routing' => [
],
'routes' => [
'convention' => [
'default_controller' => '',
'default_method' => '',
],
'common' => [],
'anime' => [],
'manga' => []
]
];
$di = require _dir(APP_DIR, 'bootstrap.php');
$container = $di($config_array);
$container->set('error-handler', new MockErrorHandler());
$this->container = $container;
}
/**
* Set arbitrary superglobal values for testing purposes
*
* @param array $supers
* @return void
*/
public function setSuperGlobals($supers = [])
{
$default = [
'_GET' => $_GET,
'_POST' => $_POST,
'_COOKIE' => $_COOKIE,
'_SERVER' => $_SERVER,
'_FILES' => $_FILES
];
$web_factory = new WebFactory(array_merge($default,$supers));
$this->container->set('request', $web_factory->newRequest());
$this->container->set('response', $web_factory->newResponse());
}
}
// End of bootstrap.php // End of bootstrap.php