├── .editorconfig ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE.txt ├── Lib └── Routing │ └── Route │ └── PageRoute.php ├── README.markdown ├── Test └── Case │ └── AllPageRouteTest.php └── composer.json /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = false 5 | 6 | [*] 7 | indent_style = tab 8 | indent_size = 2 9 | charset = "utf-8" 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.yml] 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | 8 | env: 9 | global: 10 | - PLUGIN_NAME=PageRoute 11 | - REQUIRE="" 12 | - DB=mysql CAKE_VERSION=2.7 13 | matrix: 14 | - DB=mysql CAKE_VERSION=2.4 15 | - DB=mysql CAKE_VERSION=2.7 16 | 17 | matrix: 18 | include: 19 | - php: 5.4 20 | env: 21 | - COVERALLS=1 22 | - php: 5.4 23 | env: 24 | - PHPCS=1 25 | - php: 5.4 26 | env: 27 | - FOC_VALIDATE=1 28 | 29 | before_script: 30 | - git clone https://github.com/FriendsOfCake/travis.git --depth 1 ../travis 31 | - ../travis/before_script.sh 32 | 33 | script: 34 | - ../travis/script.sh 35 | 36 | after_success: 37 | - ../travis/after_success.sh 38 | 39 | notifications: 40 | email: false 41 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | PageRoute loves to welcome your contributions. There are several ways to help out: 4 | * Create a ticket in GitHub, if you have found a bug 5 | * Write testcases for open bug tickets 6 | * Write patches for open bug/feature tickets, preferably with testcases included 7 | * Contribute to the [documentation](https://github.com/josegonzalez/cakephp-page-route/tree/gh-pages) 8 | 9 | There are a few guidelines that we need contributors to follow so that we have a 10 | chance of keeping on top of things. 11 | 12 | ## Getting Started 13 | 14 | * Make sure you have a [GitHub account](https://github.com/signup/free) 15 | * Submit a ticket for your issue, assuming one does not already exist. 16 | * Clearly describe the issue including steps to reproduce when it is a bug. 17 | * Make sure you fill in the earliest version that you know has the issue. 18 | * Fork the repository on GitHub. 19 | 20 | ## Making Changes 21 | 22 | * Create a topic branch from where you want to base your work. 23 | * This is usually the develop branch 24 | * To quickly create a topic branch based on master; `git branch 25 | master/my_contribution master` then checkout the new branch with `git 26 | checkout master/my_contribution`. Better avoid working directly on the 27 | `master` branch, to avoid conflicts if you pull in updates from origin. 28 | * Make commits of logical units. 29 | * Check for unnecessary whitespace with `git diff --check` before committing. 30 | * Use descriptive commit messages and reference the #ticket number 31 | * Core testcases should continue to pass. You can run tests locally or enable 32 | [travis-ci](https://travis-ci.org/) for your fork, so all tests and codesniffs 33 | will be executed. 34 | * Your work should apply the CakePHP coding standards. 35 | 36 | ## Which branch to base the work 37 | 38 | * Bugfix branches will be based on develop branch. 39 | * New features that are backwards compatible will be based on develop branch 40 | * New features or other non-BC changes will go in the next major release branch. 41 | 42 | ## Submitting Changes 43 | 44 | * Push your changes to a topic branch in your fork of the repository. 45 | * Submit a pull request to the repository with the correct target branch. 46 | 47 | ## Testcases and codesniffer 48 | 49 | PageRoute tests requires [PHPUnit](http://www.phpunit.de/manual/current/en/installation.html) 50 | 3.5 or higher. To run the testcases locally use the following command: 51 | 52 | ./lib/Cake/Console/cake test PageRoute AllPageRoute 53 | 54 | To run the sniffs for CakePHP coding standards 55 | 56 | phpcs -p --extensions=php --standard=CakePHP ./app/Plugin/PageRoute 57 | 58 | Check the [cakephp-codesniffer](https://github.com/cakephp/cakephp-codesniffer) 59 | repository to setup the CakePHP standard. The README contains installation info 60 | for the sniff and phpcs. 61 | 62 | 63 | # Additional Resources 64 | 65 | * [CakePHP coding standards](http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html) 66 | * [Bug tracker](https://github.com/josegonzalez/cakephp-page-route/issues) 67 | * [General GitHub documentation](https://help.github.com/) 68 | * [GitHub pull request documentation](https://help.github.com/send-pull-requests/) 69 | * #cakephp IRC channel on freenode.org 70 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011 Jose Diaz-Gonzalez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Lib/Routing/Route/PageRoute.php: -------------------------------------------------------------------------------- 1 | 'PageRoute', 'page' => '[\/\w_-]+') 20 | * ); 21 | * 22 | * Note that if a page has the same name as a controller/plugin, the page will 23 | * take precedence since it is included before Router::__connectDefaultRoutes() 24 | * is called. 25 | * 26 | * @author Jose Gonzalez (support@savant.be) 27 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 28 | * @see CakeRoute 29 | */ 30 | class PageRoute extends CakeRoute { 31 | 32 | /** 33 | * An array of additional parameters for the Route. 34 | * 35 | * @var array 36 | * @access public 37 | */ 38 | public $options = array( 39 | 'controller' => 'pages', 40 | 'action' => 'display', 41 | 'page' => '[\/\w_-]+', 42 | ); 43 | 44 | /** 45 | * Constructor for a Route 46 | * 47 | * @param string $template Template string with parameter placeholders 48 | * @param array $defaults Array of defaults for the route. 49 | * @param string $options Array of parameters and additional options for the Route 50 | * @return void 51 | */ 52 | public function __construct($template, $defaults = array(), $options = array()) { 53 | $options = array_merge($this->options, (array)$options); 54 | parent::__construct($template, $defaults, $options); 55 | } 56 | 57 | /** 58 | * Parses a string url into an array. If a page is found, it is parsed into 59 | * the pass key in the route params 60 | * 61 | * @param string $url The url to parse 62 | * @return mixed false on failure, or an array of request parameters 63 | * @throws MissingViewException if a viewpath is missing 64 | */ 65 | public function parse($url) { 66 | $params = parent::parse($url); 67 | if (!$params || empty($params['page'])) { 68 | return false; 69 | } 70 | 71 | $path = trim(str_replace('//', '', (string)$params['page']), '/'); 72 | $viewPath = APP . 'View' . DS . $this->options['controller'] . DS . $path . '.ctp'; 73 | if (!file_exists($viewPath)) { 74 | throw new MissingViewException($viewPath); 75 | } 76 | 77 | $params['pass'] = Sanitize::clean(explode('/', $path)); 78 | $params['controller'] = $this->options['controller']; 79 | $params['action'] = $this->options['action']; 80 | $params['plugin'] = null; 81 | unset($params['page']); 82 | 83 | return $params; 84 | } 85 | 86 | /** 87 | * Reverse route page shortcut urls. Treats all existing page routes as normal 88 | * Can optionally validate a page path using the 'validate' key 89 | * 90 | * @param array $url Array of parameters to convert to a string. 91 | * @return mixed either false or a string url. 92 | */ 93 | public function match($url) { 94 | if (!isset($url['controller']) || !isset($url['action'])) { 95 | return false; 96 | } 97 | 98 | if ($url['controller'] != $this->options['controller'] || $url['action'] != $this->options['action']) { 99 | return false; 100 | } 101 | 102 | if (isset($url[0]) && !isset($url['page'])) { 103 | $url['page'] = $url[0]; 104 | } 105 | 106 | if (!isset($url['page'])) { 107 | return false; 108 | } 109 | 110 | if (isset($url['validate']) && $url['validate'] == true) { 111 | $path = trim(str_replace('//', '', (string)$url['page']), '/'); 112 | if (!file_exists(APP . 'View' . DS . $this->options['controller'] . DS . $path . '.ctp')) { 113 | return false; 114 | } 115 | } 116 | 117 | unset($url[0], $url['prefix'], $url['plugin'], $url['validate']); 118 | return parent::match($url); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | [![Build Status](https://img.shields.io/travis/josegonzalez/cakephp-page-route/master.svg?style=flat-square)](https://travis-ci.org/josegonzalez/cakephp-page-route) 2 | [![Coverage Status](https://img.shields.io/coveralls/josegonzalez/cakephp-page-route.svg?style=flat-square)](https://coveralls.io/r/josegonzalez/cakephp-page-route?branch=master) 3 | [![Total Downloads](https://img.shields.io/packagist/dt/josegonzalez/cakephp-page-route.svg?style=flat-square)](https://packagist.org/packages/josegonzalez/cakephp-page-route) 4 | [![Latest Stable Version](https://img.shields.io/packagist/v/josegonzalez/cakephp-page-route.svg?style=flat-square)](https://packagist.org/packages/josegonzalez/cakephp-page-route) 5 | [![Documentation Status](https://readthedocs.org/projects/cakephp-page-route/badge/?version=latest&style=flat-square)](https://readthedocs.org/projects/cakephp-page-route/?badge=latest) 6 | [![Gratipay](https://img.shields.io/gratipay/josegonzalez.svg?style=flat-square)](https://gratipay.com/~josegonzalez/) 7 | 8 | # PageRoute Plugin 9 | 10 | Forget about cluttering your `routes.php` with zillions of `/page`-style routes. 11 | 12 | ## Background 13 | 14 | Someone in IRC was migrating tons of static pages into a fresh CakePHP install. In the webroot. I told him to move them into `app/View/Pages` and use routes to properly route everything. I also mentioned that rather than routing every static file one by one, it might be possible using a custom `CakeRoute` class, but didn't elaborate. 15 | 16 | So a few minutes of hacking later, and here I am with this lovely `PageRoute`. 17 | 18 | ## Requirements 19 | 20 | * PHP 5.2+ 21 | * CakePHP 2.x 22 | 23 | ## Installation 24 | 25 | _[Using [Composer](http://getcomposer.org/)]_ 26 | 27 | Add the plugin to your project's `composer.json` - something like this: 28 | 29 | { 30 | "require": { 31 | "josegonzalez/cakephp-page-route": "1.0.0" 32 | } 33 | } 34 | 35 | Because this plugin has the type `cakephp-plugin` set in it's own `composer.json`, composer knows to install it inside your `/Plugins` directory, rather than in the usual vendors file. It is recommended that you add `/Plugins/PageRoute` to your .gitignore file. (Why? [read this](http://getcomposer.org/doc/faqs/should-i-commit-the-dependencies-in-my-vendor-directory.md).) 36 | 37 | _[Manual]_ 38 | 39 | * Download this: [https://github.com/josegonzalez/cakephp-page-route/zipball/master](https://github.com/josegonzalez/cakephp-page-route/zipball/master) 40 | * Unzip that download. 41 | * Copy the resulting folder to `app/Plugin` 42 | * Rename the folder you just copied to `PageRoute` 43 | 44 | _[GIT Submodule]_ 45 | 46 | In your app directory type: 47 | 48 | git submodule add git://github.com/josegonzalez/cakephp-page-route.git Plugin/PageRoute 49 | git submodule init 50 | git submodule update 51 | 52 | _[GIT Clone]_ 53 | 54 | In your plugin directory type 55 | 56 | git clone git://github.com/josegonzalez/cakephp-page-route.git PageRoute 57 | 58 | ### Enable plugin 59 | 60 | In 2.0 you need to enable the plugin your `app/Config/bootstrap.php` file: 61 | 62 | CakePlugin::load('PageRoute'); 63 | 64 | If you are already using `CakePlugin::loadAll();`, then this is not necessary. 65 | 66 | 67 | ## Usage 68 | 69 | Way near the bottom of your `app/Config/routes.php` file, add the following: 70 | 71 | ```php 72 | 'pages', 'action' => 'display'), 75 | array('routeClass' => 'PageRoute') 76 | ); 77 | ``` 78 | 79 | And now you can remove all shortcuts to your `/pages/display/page-name` urls. Whenever you create a new `.ctp` file in `app/View/Pages`, this route will automatically detect it using a `file_exists()` call. Because of this, it is recommended to use this as one of the last, if not the last, route in your application, in order to minimize file-reads. 80 | 81 | It is also possible to customize the controller/action used for this. For example, we might want to use the `StaticPagesController::index()` instead of `PagesController::display()`. In that case, our `routes.php` would look like the following: 82 | 83 | ```php 84 | 'static_pages', 'action' => 'index'), 87 | array('routeClass' => 'PageRoute', 'controller' => 'static_pages', 'action' => 'index') 88 | ); 89 | ``` 90 | 91 | In this way, we can easily rename the `PagesController` to something less useful, and reuse the `PagesController` for something else - such as dynamic content from the database. 92 | 93 | Reverse routing will all work the same as it does without this route class. `array('controller' => 'pages', 'action' => 'display', 'about')` will be automatically converted to `array('controller' => 'pages', 'action' => 'display', 'page' =. 'about')` for backwards compatibility Please note that by default, the regex `[\/\w_-]+` is used to check the page validity, so you may need to update that regex in the Route options as follows: 94 | 95 | ```php 96 | App::uses('PageRoute', 'PageRoute.Routing/Route'); 97 | Router::connect('/:page', array('controller' => 'static_pages', 'action' => 'index'), 98 | array('routeClass' => 'PageRoute', 'page' => '[a-zA-Z]+') 99 | ); 100 | ``` 101 | 102 | Note that the `.` character has been disallowed in the default regex to remove the possibility of traversing the directory tree for security reasons. 103 | 104 | ## Todo 105 | 106 | * Unit Tests 107 | * Allow usage of the `.` character in routes 108 | * Add caching to file_exists calls 109 | -------------------------------------------------------------------------------- /Test/Case/AllPageRouteTest.php: -------------------------------------------------------------------------------- 1 | addTestDirectoryRecursive($path); 17 | 18 | return $suite; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "josegonzalez/cakephp-page-route", 3 | "description": "Automagically route /:page style routes without any fuss in CakePHP", 4 | "type": "cakephp-plugin", 5 | "keywords": [ 6 | "cakephp", 7 | "page", 8 | "static" 9 | ], 10 | "homepage": "http://github.com/josegonzalez/cakephp-page-route", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Jose Diaz-Gonzalez", 15 | "email": "email@josediazgonzalez.com", 16 | "homepage": "http://josediazgonzalez.com", 17 | "role": "Maintainer" 18 | } 19 | ], 20 | "require": { 21 | "composer/installers": "*" 22 | }, 23 | "support": { 24 | "email": "cakephp+page-route@josediazgonzalez.com", 25 | "issues": "https://github.com/josegonzalez/cakephp-page-route/issues", 26 | "source": "https://github.com/josegonzalez/cakephp-page-route" 27 | }, 28 | "extra": { 29 | "installer-name": "PageRoute" 30 | } 31 | } 32 | --------------------------------------------------------------------------------