├── _config.yml ├── .gitignore ├── docs ├── more.md ├── structure.md ├── contents.md ├── views.md ├── routing.md └── controllers.md ├── .travis.yml ├── index.php ├── composer.json ├── LICENSE ├── tests └── OnePHP │ └── OneFrameworkTest.php ├── .htaccess ├── README.md └── src └── OnePHP └── one_framework.php /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-tactile 2 | highlighter: rouge 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .gitignore 3 | apigen.phar 4 | phpunit.phar 5 | .DS_Store 6 | src�/.DS_Store 7 | vendor 8 | -------------------------------------------------------------------------------- /docs/more.md: -------------------------------------------------------------------------------- 1 | ## ONE PHP Micro Framework Documentation 2 | ## More 3 | ##### Routing Note: 4 | ###### If you want to see the /index.php/ in all URLS change the defined constant: APP_NAME in the Framework class and delete the .htaccess from the project. 5 | 6 | #### Modifying the Core: 7 | #### 1- First check the constants defined in the defineConstants method in the Kernel 8 | #### 2- Add your custom methods or libraries 9 | 10 | ###### Contribute and improve this documentation. 11 | ###### Click Edit and Fork the project. 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | #one php tests 2 | language: php 3 | 4 | php: 5 | # using major version aliases 6 | 7 | # aliased to a recent 5.4.x version 8 | - 5.4 9 | # aliased to a recent 5.5.x version 10 | - 5.5 11 | # aliased to a recent 5.6.x version 12 | - 5.6 13 | # aliased to a recent 7.x version 14 | - 7.0 15 | # aliased to a recent hhvm version 16 | - hhvm 17 | 18 | # optionally set up exclutions and allowed failures in the matrix 19 | matrix: 20 | allow_failures: 21 | - php: 7.0 22 | - php: hhvm 23 | 24 | before_install: 25 | - composer self-update 26 | 27 | install: 28 | - composer update --no-interaction --prefer-source --dev $COMPOSER_EXTRA_ARGS 29 | 30 | script: "phpunit ./tests/OnePHP/OneFrameworkTest.php" 31 | -------------------------------------------------------------------------------- /docs/structure.md: -------------------------------------------------------------------------------- 1 | ## ONE PHP Micro Framework Documentation 2 | 3 | This is the directory structure you will end up with following the instructions in the Installation Guide. 4 | Note: You can use controllers or not, but is always recomended for big projects. 5 | #### MVC 6 | 7 | |-- ROOT 8 | | |-- .htacess 9 | | |-- index.php 10 | | |-- src/ 11 | | |-- |-- OnePHP/ 12 | | |-- |-- |-- one_framework.php 13 | | |-- |-- controllers/ 14 | | |-- |-- views/ 15 | | |-- |-- libs/ 16 | | |-- public/ 17 | 18 | #### All your code must go inside src/ folder. 19 | ### Next: [Routing ](routing.md "Start with routings") 20 | 21 | ###### Contribute and improve this documentation. 22 | ###### Click Edit and Fork the project. 23 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | get('/', function() use ( $app ){//Action on the Root URL 13 | echo 'Hello world'; 14 | }); 15 | 16 | //test with slug in URL ( ':name' = '{name}' ) 17 | $app->get('/:name', function( $name ) use ( $app ){ 18 | echo "

Hello $name

"; 19 | }); 20 | 21 | //simple Json Response example 22 | $app->get('/json/:name', function( $name ) use ( $app ){ 23 | return $app->JsonResponse(array('name' => $name)); 24 | }); 25 | 26 | $app->respond( function() use ( $app ){ 27 | return $app->ResponseHTML('

This is a response with code 404.

', 404); 28 | }); 29 | 30 | //Run 31 | $app->listen(); 32 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "julces/oneframework", 3 | "type": "library", 4 | "description": "One PHP Restful Microframework", 5 | "keywords": ["One","Micro","Minimalist","Restful","PHP","Microframework"], 6 | "homepage": "https://github.com/juliomatcom/one-php-microframework", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Julio Cesar Martin", 11 | "email": "juliomatcom@yandex.com", 12 | "homepage": "http://oneframework.net/" 13 | }, 14 | { 15 | "name": "One Framework Community", 16 | "homepage": "https://github.com/juliomatcom/one-php-microframework/graphs/contributors" 17 | } 18 | ], 19 | "require": { 20 | "php": ">=5.3.0" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "4.*" 24 | }, 25 | "autoload": { 26 | "files": [ 27 | "src/OnePHP/one_framework.php" 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/contents.md: -------------------------------------------------------------------------------- 1 | ## ONE PHP Micro Framework Documentation 2 | Just 2 simple class to help you develop easy and fast websites and webservices for webs 2.0 and allow you to create your own microframework easily. 3 | 4 | #### Table of contents: 5 | ##### 1- [Folder structure ](structure.md "Folder structure Normal or MVC") 6 | ##### 2- [Routing ](routing.md "Start with routings") 7 | ##### 3- [Controllers ](controllers.md "Using your controllers with One Framework") 8 | ##### 4- [Views ](views.md "Render views from controllers with One Framework") 9 | ##### 5- [More](more.md "More documentation of the One Framework") 10 | 11 | 12 | #### Simplest example: 13 | ```php 14 | //index.php file 15 | require_once('src/OnePHP/one_framework.php'); 16 | $app = new \OnePHP\App(); 17 | 18 | $app->get('/',function() use ($app){//Action 19 | echo 'Hello world'; 20 | }); 21 | $app->listen(); 22 | ``` 23 | 24 | 25 | 26 | ###### Contribute and improve this documentation. 27 | ###### Click Edit and Fork the project. 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 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 all 13 | 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 THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /docs/views.md: -------------------------------------------------------------------------------- 1 | ## ONE PHP Micro Framework Documentation 2 | ### Views: 3 | 4 | ### To add a view just create .php files in your a new folder project named /views/ then use Response to render it: 5 | #### Rendering a view 6 | ```php 7 | // file: /src/controllers/book.php 8 | // view is located in /src/views/books_list_view.php 9 | $app->post('/books/',function() use ($app){ 10 | $books = $this->getBooks(); 11 | return $app->Response('books_list_view.php', array('books' => $books)); 12 | }); 13 | ``` 14 | #### You can serve static files in your views files just locating them in the top of Root folder '/' like: ( See [Folder structure ](structure.md "Folder structure Normal or MVC") ) 15 | 16 | ```html 17 | 18 | 19 | 20 | 21 | 22 | 23 | ``` 24 | ##### You can change the default directory of view in the constants of de Framework 25 | The $app var and Vars passed to Views are globally accesible from any view loaded by Response(). 26 | 27 | ### Next: [More](more.md "More documentation of the One Framework") 28 | 29 | ###### Contribute and improve this documentation. 30 | ###### Click Edit and Fork the project. 31 | -------------------------------------------------------------------------------- /docs/routing.md: -------------------------------------------------------------------------------- 1 | ## ONE PHP Micro Framework Documentation 2 | ### Routing: 3 | 4 | #### Action on GET Request: 5 | ```php 6 | //index.php file 7 | require_once('src/OnePHP/one_framework.php'); 8 | $app = new \OnePHP\App(); 9 | 10 | $app->get('/',function() use ($app){//Action 11 | echo 'Hello world'; 12 | }); 13 | $app->listen(); 14 | ``` 15 | 16 | #### Action on POST Request with slugs: (same with PUT and DELETE) 17 | ##### Slugs are defined by {x} or :x inside a Route 18 | 19 | Examples 20 | ```php 21 | //$id_book will be the value passed on the URL 22 | $app->put('/book/:id_book/',function($id_book) use ($app){ 23 | //update... 24 | }); 25 | 26 | $app->delete('/book/{id_book}/',function($id_book) use ($app){ 27 | //delete... 28 | }); 29 | ``` 30 | #### Respond all Request (if no match) 31 | ```php 32 | $app->respond( function() use ( $app ){ 33 | return $app->ResponseHTML('

This is a response with code 404.

', 404); 34 | }); 35 | ``` 36 | 37 | #### Generating new routes with getRoute 38 | ```php 39 | About 40 | 41 | 42 | Edit $book 43 | 44 | ``` 45 | 46 | ### Next: [Controllers ](controllers.md "Using your controllers with One Framework") 47 | 48 | ###### Contribute and improve this documentation. 49 | ###### Click Edit and Fork the project. 50 | -------------------------------------------------------------------------------- /docs/controllers.md: -------------------------------------------------------------------------------- 1 | ## ONE PHP Micro Framework Documentation 2 | ### Controllers: 3 | 4 | Include in your index.php (front controller) all your controllers files then just add some Actions. 5 | 6 | #### Using Restful Actions on Books 7 | ```php 8 | // $id_book will be the value passed on the URL 9 | // file: src/controllers/main.php 10 | 11 | //create 12 | $app->post('/books/',function() use ($app){ 13 | $handler = new BookHandler(); 14 | $book = $handler->create( $app->getRequest() ); 15 | 16 | return $app->Response('view.php',array('book' => $book),201); 17 | }); 18 | 19 | $app->get('/books/{id_book}/',function($id_book) use ($app){ 20 | $handler = new BookHandler(); 21 | $book = $handler->get($id_book); 22 | 23 | return $app->Response('view.php',array('book' => $book)); 24 | }); 25 | 26 | $app->put('/books/{id_book}/',function($id_book) use ($app){ 27 | $handler = new BookHandler(); 28 | $book = $handler->update($id_book,$app->getRequest()); 29 | 30 | return $app->Response('view.php',array('book' => $book)); 31 | }); 32 | 33 | $app->delete('/books/{id_book}/',function($id_book) use ($app){ 34 | $handler = new BookHandler(); 35 | $res = $handler->delete($id_book); 36 | 37 | return $app->Response('view.php',array('deleted' => $res)); 38 | }); 39 | 40 | ``` 41 | You can read more about restful Actions in: 42 | [restapitutorial.com ](http://www.restapitutorial.com/lessons/httpmethods.html "restapitutorial.com") 43 | 44 | 45 | ### Next: [Views ](views.md "Render views from controllers with One Framework") 46 | 47 | 48 | ###### Contribute and improve this documentation. 49 | ###### Click Edit and Fork the project. 50 | -------------------------------------------------------------------------------- /tests/OnePHP/OneFrameworkTest.php: -------------------------------------------------------------------------------- 1 | tryMatch('/','/', array()); 20 | 21 | /* Dynamic routes */ 22 | //with :slug 23 | 24 | //Do NOT match 25 | $this->tryMatch('/hello/:name','/hello/', array(), false); 26 | 27 | $this->tryMatch('/hello/:name','/hello/juliomatcom', array( 28 | 'name' => 'juliomatcom' 29 | )); 30 | $this->tryMatch('/hello/:name/age/:age','/hello/juliomatcom/age/25', array( 31 | 'name' => 'juliomatcom', 32 | 'age' => 25 33 | )); 34 | 35 | //with {slug} 36 | $this->tryMatch('/hello/{name}','/hello/juliomatcom', array( 37 | 'name' => 'juliomatcom' 38 | )); 39 | $this->tryMatch('/hello/{name}/age/{age}','/hello/juliomatcom/age/25', array( 40 | 'name' => 'juliomatcom', 41 | 'age' => 25 42 | )); 43 | } 44 | 45 | public function testMethod(){ 46 | $app = new \OnePHP\App(); 47 | 48 | $func = function() { 49 | return true; 50 | }; 51 | //default HTTP Requests in OneFramework 52 | $app->get('/get', $func); 53 | $app->post('/post', $func); 54 | $app->put('/put', $func); 55 | $app->delete('/delete', $func); 56 | 57 | $routes = $app->getRoutes(); 58 | 59 | //check if routes are found 60 | $this->assertEquals('/get', $routes['GET'][0]->route ); 61 | $this->assertEquals('/post', $routes['POST'][0]->route ); 62 | $this->assertEquals('/put', $routes['PUT'][0]->route ); 63 | $this->assertEquals('/delete', $routes['DELETE'][0]->route ); 64 | } 65 | 66 | private function tryMatch($route, $uri, array $expected_slugs = array(), $expected = true ){ 67 | 68 | $routeObj = new \OnePHP\Route( $route , function ( $name ) { } ); 69 | 70 | $uri_segments = preg_split('/[\/]+/',$uri,null,PREG_SPLIT_NO_EMPTY); 71 | 72 | $route_segments = preg_split('/[\/]+/',$routeObj->route,null,PREG_SPLIT_NO_EMPTY); 73 | $slugs = array(); 74 | 75 | $matched = \OnePHP\CoreFramework::CompareSegments($uri_segments,$route_segments,$slugs); 76 | 77 | //function was found 78 | $this->assertEquals($expected, $matched, "Cant match this route: '$route' with '$uri'\n"); 79 | //slugs values was properly saved 80 | $this->assertEquals($expected_slugs, $slugs, 'Final slugs does not match'); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | # Use the front controller as index file. It serves as a fallback solution when 2 | # every other rewrite/redirect fails (e.g. in an aliased environment without 3 | # mod_rewrite). Additionally, this reduces the matching process for the 4 | # start page (path "/") because otherwise Apache will apply the rewriting rules 5 | # to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl). 6 | DirectoryIndex index.php 7 | 8 | 9 | RewriteEngine On 10 | 11 | # Determine the RewriteBase automatically and set it as environment variable. 12 | # If you are using Apache aliases to do mass virtual hosting or installed the 13 | # project in a subdirectory, the base path will be prepended to allow proper 14 | # resolution of the app.php file and to redirect to the correct URI. It will 15 | # work in environments without path prefix as well, providing a safe, one-size 16 | # fits all solution. But as you do not need it in this case, you can comment 17 | # the following 2 lines to eliminate the overhead. 18 | RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ 19 | RewriteRule ^(.*) - [E=BASE:%1] 20 | 21 | # Sets the HTTP_AUTHORIZATION header removed by apache 22 | RewriteCond %{HTTP:Authorization} . 23 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 24 | 25 | # Redirect to URI without front controller to prevent duplicate content 26 | # (with and without `/app.php`). Only do this redirect on the initial 27 | # rewrite by Apache and not on subsequent cycles. Otherwise we would get an 28 | # endless redirect loop (request -> rewrite to front controller -> 29 | # redirect -> request -> ...). 30 | # So in case you get a "too many redirects" error or you always get redirected 31 | # to the start page because your Apache does not expose the REDIRECT_STATUS 32 | # environment variable, you have 2 choices: 33 | # - disable this feature by commenting the following 2 lines or 34 | # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the 35 | # following RewriteCond (best solution) 36 | RewriteCond %{ENV:REDIRECT_STATUS} ^$ 37 | RewriteRule ^index\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L] 38 | 39 | # If the requested filename exists, simply serve it. 40 | # We only want to let Apache serve files and not directories. 41 | RewriteCond %{REQUEST_FILENAME} -f 42 | RewriteRule .? - [L] 43 | 44 | # Rewrite all other queries to the front controller. 45 | RewriteRule .? %{ENV:BASE}/index.php [L] 46 | 47 | 48 | 49 | 50 | # When mod_rewrite is not available, we instruct a temporary redirect of 51 | # the start page to the front controller explicitly so that the website 52 | # and the generated links can still be used. 53 | RedirectMatch 302 ^/$ /index.php/ 54 | # RedirectTemp cannot be used instead 55 | 56 | 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # One PHP MicroFramework 2 | An extremely light-weight and small Restful Micro-Framework MVC for Web 2.0 that doesn't get in your way, based on Symfony and ExpressJS. No Config. 3 | 4 | [![Build Status](https://travis-ci.org/juliomatcom/one-php-microframework.svg?branch=master)](https://travis-ci.org/juliomatcom/one-php-microframework) 5 | [![Latest Stable Version](https://poser.pugx.org/julces/oneframework/v/stable)](https://packagist.org/packages/julces/oneframework) 6 | [![Latest Unstable Version](https://poser.pugx.org/julces/oneframework/v/unstable)](https://packagist.org/packages/julces/oneframework) 7 | [![License](https://poser.pugx.org/julces/oneframework/license)](https://packagist.org/packages/julces/oneframework) 8 | 9 | ### :loudspeaker: *I stopped developing new features for OnePHP. If you feel like you have the time, you are welcome to [contact me](https://twitter.com/juliomatcom) or [PR](https://github.com/juliomatcom/one-php-microframework/pulls) and keep this cool framework up to date.* 10 | --- 11 | ## Simplest usage: 12 | ```php 13 | // index.php 14 | require_once('src/OnePHP/one_framework.php'); 15 | $app = new \OnePHP\App(); 16 | 17 | $app->get('/:name',function( $name ) use ( $app ){//Action 18 | echo "Hello $name"; 19 | }); 20 | $app->listen(); 21 | ``` 22 | 23 | ### Install: 24 | 1- With [**Composer**](https://getcomposer.org/ "download Composer") or download Master [**ZIP**](https://github.com/juliomatcom/one-php-microframework/archive/master.zip "download One PHP Master version"): 25 | ``` 26 | composer create-project julces/oneframework 27 | ``` 28 | 2- Include **one_framework.php** in your project and copy the **.htaccess** file in the **Root Folder** to use the **index.php** as your front controller. See **file structure** [here](docs/structure.md) for more info. 29 | 3- Run **App->listen()** after adding some Actions 30 | 31 | ### Why use this tiny Microframework? 32 | **One PHP** is perfect for you if you need to quickly write **small** and **fast** Web 2.0 applications with: 33 | 1- **Restful** Routes 34 | 2- Easy and clean (GET, POST, PUT, DELETE...) **Requests** management 35 | 3- Restful **Response** with **HTTP Status Code** and custom **Headers** 36 | 4- **PHP** native **Views** 37 | 5- **No dependencies**, add extra libraries only when you need it. 38 | #### Do not use One PHP if: 39 | 1- You are building big full stack projects 40 | 2- You need big **built-in** libraries like Doctrine and others 41 | 42 | 43 | 44 | 45 | ### Basic Usage 2: Respond to all Requests (if no other match) 46 | ```php 47 | $app->respond( function() use ( $app ){ 48 | return $app->ResponseHTML('

This is a response with code 404.

', 404); 49 | }); 50 | ``` 51 | 52 | ## Read the [Documentation](docs/contents.md "Documentation") 53 | 54 | ### Contribute, it's easy! 55 | Found a **bug**, need **directions** 56 | or just want to say hi ? 57 | Let me know, **Fork** the project, create an **issue** or **contact** me. 58 | 59 | Follow [@juliomatcom](https://twitter.com/juliomatcom "News and updates") to keep up to date 60 | -------------------------------------------------------------------------------- /src/OnePHP/one_framework.php: -------------------------------------------------------------------------------- 1 | request = Request::createFromGlobals(); 27 | } 28 | 29 | //Most popular HTTP Methods 30 | public abstract function get($uri, callable $callback); 31 | public abstract function post($uri, callable $callback); 32 | public abstract function put($uri, callable $callback); 33 | public abstract function delete($uri, callable $callback); 34 | 35 | /** 36 | * Start listen for requests 37 | */ 38 | public abstract function listen(); 39 | 40 | /** 41 | * Get request Object 42 | * @return Request class 43 | */ 44 | public function getRequest(){ 45 | return $this->request; 46 | } 47 | 48 | /** 49 | * Set response HTTP Status Code 50 | * @param int $status default: OK 200 51 | * @return int status code sent 52 | */ 53 | public function setStatusCode($status = 200){ 54 | if ($status != 200){ 55 | if (!function_exists('http_response_code'))//PHP < 5.4 56 | {//send header 57 | header('X-PHP-Response-Code: '.$status, true, $status); 58 | } 59 | else http_response_code($status); 60 | } 61 | return $status; 62 | } 63 | 64 | /** 65 | *********** CORE FUNCTIONS *********** 66 | */ 67 | 68 | /** 69 | * Traverse the routes and match the request, execute the callback 70 | * @param string $method REQUEST_METHOD 71 | * @param array $routes Routes Objects 72 | * @param array $slugs Add any Slugs value found in the Request path (order matters) 73 | * @return bool true if Route was found and callback executed, false otherwise 74 | */ 75 | protected function traverseRoutes($method = 'GET', array $routes, array &$slugs){ 76 | if (isset($routes[$method])){ 77 | foreach($routes[$method] as $route) 78 | if($func = $this->processUri($route, $slugs)){ 79 | //call callback function with params in slugs 80 | call_user_func_array($func, $slugs); 81 | return true; 82 | } 83 | } 84 | return false; 85 | } 86 | 87 | protected function getSegment($segment_number){ 88 | $uri = $this->request->getRequestedUri(); 89 | $uri_segments = preg_split('/[\/]+/',$uri,null,PREG_SPLIT_NO_EMPTY); 90 | 91 | return isset($uri_segments[$segment_number]) ? $uri_segments[$segment_number] : false; 92 | } 93 | 94 | private function processUri($route, &$slugs = array()){ 95 | $url =$this->request->getRequestedUri(); 96 | $uri = parse_url($url, PHP_URL_PATH); 97 | $func = $this->matchUriWithRoute($uri, $route, $slugs); 98 | return $func ? $func : false; 99 | } 100 | 101 | static function matchUriWithRoute($uri, $route, &$slugs){ 102 | $uri_segments = preg_split('/[\/]+/', $uri, null, PREG_SPLIT_NO_EMPTY); 103 | 104 | $route_segments = preg_split('/[\/]+/', $route->route, null, PREG_SPLIT_NO_EMPTY); 105 | 106 | if (CoreFramework::compareSegments($uri_segments, $route_segments, $slugs)){ 107 | //route matched 108 | return $route->function; //Object route 109 | } 110 | return false; 111 | } 112 | 113 | /** Match 2 uris 114 | * @param $uri_segments 115 | * @param $route_segments 116 | * @return bool 117 | */ 118 | static function CompareSegments($uri_segments, $route_segments, &$slugs){ 119 | 120 | if (count($uri_segments) != count($route_segments)) return false; 121 | 122 | foreach($uri_segments as $segment_index => $segment){ 123 | $segment_route = $route_segments[$segment_index]; 124 | //different segments must be an {slug} | :slug 125 | $is_slug = preg_match('/^{[^\/]*}$/', $segment_route) || preg_match('/^:[^\/]*/', $segment_route,$matches); 126 | 127 | if ($is_slug){//Note php does not support named parameters 128 | if (strlen(trim($segment)) === 0){ 129 | return false; 130 | } 131 | $slugs[ str_ireplace(array(':', '{', '}'), '', $segment_route) ] = $segment;//save slug key => value 132 | } 133 | else if($segment_route !== $segment && $is_slug !== 1) 134 | return false; 135 | } 136 | //match with every segment 137 | return true; 138 | } 139 | } 140 | 141 | /** 142 | * Class App 143 | * One PHP MVC Micro Framework 144 | * Contact: juliomatcom@yandex.com 145 | * Twitter @juliomatcom 146 | * Contribute to the project in Github 147 | * https://github.com/juliomatcom/one-php-microframework 148 | * 149 | * Controllers must be in APP_DIR/controllers 150 | * Views must be in APP_DIR/views 151 | * Assets must be in APP_DIR/public/ 152 | * 153 | * @version 0.6.0 154 | * @author Julio Cesar Martin 155 | */ 156 | class App extends CoreFramework{ 157 | //instances vars and predefined configs 158 | protected $db; 159 | protected $prod = false; 160 | 161 | /** 162 | * Initialize Framework Core 163 | * @param bool $prod Enviroment, set to false for Enable Debugging 164 | */ 165 | public function __construct($prod = false){ 166 | parent::__construct(); 167 | 168 | define('APP_DIR', $this->getRootDir() .'/../'); //if your project is in src/ like in documentation, if not correct this 169 | define('VIEW_DIR', APP_DIR .'views/'); 170 | define('CONTROLLER_DIR', APP_DIR .'controllers/'); 171 | define('VIEWS_ROUTE', APP_DIR .'views/');//deprecated since 0.4 172 | define('CONTROLLERS_ROUTE', APP_DIR .'controllers/');//deprecated since 0.4 173 | 174 | $this->setEnvironment($prod); 175 | } 176 | 177 | /* 178 | * Get framework Directory 179 | */ 180 | public function getRootDir() 181 | { 182 | return __DIR__; 183 | } 184 | 185 | /** 186 | * Change environment to prod or not 187 | * @param $prod bool 188 | */ 189 | public function setEnvironment($prod = false){ 190 | $this->prod = $prod ? ENV_PROD : ENV_DEV; 191 | } 192 | 193 | /** 194 | * Process the request and Return a Response 195 | * @param $uri string for the Route example: /book/{number}/edit 196 | * @param callable $function executable 197 | */ 198 | public function get($uri,callable $callback){ 199 | //save route and function 200 | $this->routes['GET'][] = new Route($uri, $callback); 201 | } 202 | 203 | /** 204 | * Process a POST Request 205 | * @param $uri string 206 | * @param callable $function executable 207 | */ 208 | public function post($uri,callable $callback){ 209 | $this->routes['POST'][] = new Route($uri, $callback); 210 | } 211 | 212 | /** 213 | * Process a PUT Request 214 | * @param $uri string 215 | * @param callable $function executable 216 | */ 217 | public function put($uri,callable $callback){ 218 | $this->routes['PUT'][] = new Route($uri, $callback); 219 | } 220 | 221 | /** 222 | * Process a DELETE Request 223 | * @param $uri string 224 | * @param callable $function executable 225 | */ 226 | public function delete($uri,callable $callback){ 227 | $this->routes['DELETE'][] = new Route($uri, $callback); 228 | } 229 | 230 | /** 231 | * Process all Request 232 | * @param $uri string 233 | * @param callable $function executable 234 | */ 235 | public function respond(callable $callback){ 236 | $this->routes['respond'] = new Route('', $callback); 237 | } 238 | 239 | /** 240 | * Look for match request in routes, execute the callback function 241 | */ 242 | public function listen(){ 243 | $slugs = array(); 244 | 245 | $run = $this->traverseRoutes($this->request->getMethod(), $this->routes, $slugs); 246 | 247 | if(!$run && (!isset($this->routes['respond']) || empty($this->routes['respond']))){ 248 | return $this->error("Route not found for Path: '{$this->request->getRequestedUri()}' with HTTP Method: '{$this->request->getMethod()}'. ", 1 ); 249 | } 250 | else if(!$run){ //respond for all request; 251 | $callback = $this->routes['respond']->function; 252 | $callback(); 253 | } 254 | return true; 255 | } 256 | 257 | public function getRoutes(){ 258 | return $this->routes; 259 | } 260 | /** 261 | * Create a route to the app 262 | * @param $uri 263 | * @return string new URL 264 | */ 265 | public function generateRoute($uri){ 266 | return (APP_NAME != '') ?('/'.APP_NAME.$uri) : $uri; 267 | } 268 | 269 | public function getRoute($uri){//deprecated since 0.5 270 | return $this->generateRoute($uri); 271 | } 272 | 273 | /** 274 | * Get current enviroment 275 | * @return bool True if Production is ON 276 | */ 277 | public function getEnvironment(){ 278 | return $this->prod ? ENV_PROD : ENV_DEV; 279 | } 280 | 281 | public function Redirect($href){ 282 | echo header('Location: '.$href); 283 | } 284 | 285 | /** 286 | * Return HTTP Response from view. 287 | * @param string $filename src or content 288 | * @param array $vars Data to pass to the View 289 | * @param int $status Set the response status code. 290 | * @param array $headers Set response headers. 291 | * @param int $asText Echo as text 292 | */ 293 | public function Response($filename = '', array $vars = array(), $status = 200, array $headers = array(),$asText = 0){ 294 | $this->setStatusCode($status); 295 | 296 | if (count($headers)){//add extra headers 297 | $this->addCustomHeaders($headers); 298 | } 299 | //pass to the view 300 | if (!$asText){ 301 | $view = new View(VIEWS_ROUTE.$filename, $vars, $this); 302 | $view->load(); 303 | } 304 | else echo $filename; 305 | } 306 | 307 | public function ResponseHTML($html = '', $status = 200, array $headers = array()){ 308 | return $this->Response($html, array(), $status, $headers, true); 309 | } 310 | 311 | /** 312 | * Send json encoded Response 313 | * @param mixed $data 314 | * @param int $status 315 | * @param array $headers 316 | */ 317 | public function JsonResponse($data = null, $status = 200, array $headers = array() ){ 318 | $this->setStatusCode($status); 319 | 320 | header('Content-Type: application/json');//set content type to Json 321 | if (count($headers)){//add extra headers 322 | $this->addCustomHeaders($headers); 323 | } 324 | 325 | echo json_encode($data); 326 | } 327 | 328 | 329 | private function addCustomHeaders(array $headers = array()){ 330 | foreach($headers as $key=>$header){ 331 | header($key.': '.$header); 332 | } 333 | } 334 | 335 | /** 336 | * Show framework's errors 337 | * @param string $msg 338 | * @param int $number 339 | */ 340 | public function error($msg = '', $number = 0){ 341 | $status = 500; 342 | switch ($number){ 343 | case 1://not found 344 | $status = $this->setStatusCode(404); 345 | break; 346 | default://internal server error code 347 | $this->setStatusCode(500); 348 | break; 349 | } 350 | 351 | if ($this->getEnvironment() == ENV_PROD){ 352 | echo "
353 |

:(

354 |

Sorry there is a problem with this request.

355 |

The server return $status status code.

356 |

Please try later or contact us.

357 |
"; 358 | } 359 | else if ($this->getEnvironment() == ENV_DEV){//debug enable 360 | echo"
361 | \"One 362 |

Error

363 |

The server return $status status code.

364 |

$msg

"; 365 | 366 | switch($number){ 367 | case 1: 368 | echo " 369 |

Note: Routes begin always with '/' character.

"; 370 | break; 371 | default: 372 | $this->setStatusCode(500); 373 | break; 374 | } 375 | 376 | echo "

Exception:

"; 377 | throw new \Exception($msg); 378 | echo "
"; 379 | } 380 | else{ 381 | // Here your custom environments 382 | } 383 | return false; 384 | } 385 | } 386 | 387 | /** 388 | * Class Route 389 | * Formed by a string with the path and one callback function 390 | * @author Julio Cesar Martin 391 | */ 392 | class Route{ 393 | public $route; 394 | public $function; 395 | 396 | /** 397 | * @param string $routeKey like /books/{id}/edit 398 | * @param callable $func Function 399 | */ 400 | public function __construct($routeKey = '', callable $func){ 401 | $this->route = $routeKey; 402 | $this->function = $func; 403 | } 404 | } 405 | 406 | /** 407 | * Class Request 408 | * Manage request params 409 | * @author Julio Cesar Martin 410 | */ 411 | class Request{ 412 | private $get; 413 | private $post; 414 | private $files; 415 | private $server; 416 | private $cookie; 417 | private $method; 418 | private $requested_uri; 419 | private $body = null; 420 | 421 | public function __construct(array $GET = array(), array $POST = array(), array $FILES = array(), array $SERVER = array(), array $COOKIE = array()){ 422 | $this->get = $GET; 423 | $this->post = $POST; 424 | $this->files = $FILES; 425 | $this->server = $SERVER; 426 | $this->cookie = $COOKIE; 427 | $this->method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET'; 428 | $this->requested_uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/' ; 429 | } 430 | 431 | public static function createFromGlobals(){ 432 | return new Request($_GET,$_POST,$_FILES,$_SERVER,$_COOKIE); 433 | } 434 | 435 | /** 436 | * Get query param passed by URL 437 | * @param $key 438 | * @return value or false 439 | */ 440 | public function get($key){ 441 | return isset($this->get[$key]) ? $this->get[$key] : false; 442 | } 443 | 444 | /** 445 | * Get post variables 446 | * @param $key 447 | * @return value or false 448 | */ 449 | public function post($key){ 450 | return isset($this->post[$key]) ? $this->post[$key] : false; 451 | } 452 | 453 | public function server($key){ 454 | return isset($this->server[$key]) ? $this->server[$key] : false; 455 | } 456 | 457 | public function cookie($key){ 458 | return isset($this->cookie[$key]) ? $this->cookie[$key] : false; 459 | } 460 | 461 | /** 462 | * Returns the Request Body content from POST,PUT 463 | * For more info see: http://php.net/manual/en/wrappers.php.php 464 | */ 465 | public function getBody(){ 466 | if ($this->body == null) 467 | $this->body = file_get_contents('php://input'); 468 | return $this->body; 469 | } 470 | 471 | /** 472 | * Get headers received 473 | * @param $key 474 | * @return value or false 475 | */ 476 | public function header($key){ 477 | return isset($_SERVER['HTTP_'.strtoupper($key)]) ? $_SERVER['HTTP_'.strtoupper($key)] : false; 478 | } 479 | 480 | public function getMethod(){ 481 | return $this->method; 482 | } 483 | 484 | public function getRequestedUri(){ 485 | return $this->requested_uri; 486 | } 487 | } 488 | 489 | /** 490 | * Class View 491 | * Load a view File with access to data and Framework 492 | * @author Julio Cesar Martin 493 | */ 494 | class View 495 | { 496 | protected $data; 497 | protected $framework; 498 | protected $src; 499 | 500 | /** 501 | * @param $src Source file to load 502 | * @param array $vars Associative key , values 503 | * @param null $framework isntance 504 | */ 505 | public function __construct($src, array $vars = array(), App $framework = null){ 506 | $this->data = $vars; 507 | $this->framework = $framework; 508 | $this->src = $src; 509 | } 510 | 511 | /** 512 | * Renders a view 513 | * @throws Exception if View not found 514 | */ 515 | public function load(){ 516 | $app = $this->framework; 517 | $data = $this->data; //deprecated, vars are passed directly since version 0.0.4 518 | extract($this->data, EXTR_OVERWRITE);//set global all variables to the view 519 | 520 | if (file_exists($this->src)) 521 | include_once($this->src); //scoped to this class 522 | else{ 523 | if($this->framework ){ 524 | if($app->getEnvironment() == ENV_DEV) 525 | return $app->error("View filename '{$this->src}' NOT found in '". VIEWS_ROUTE."'.
526 | Maybe you need to change the App::APP_DIR or App::VIEW_DIR Constant to your current folder structure.",2); 527 | else 528 | return $app->error('',2); 529 | } 530 | } 531 | } 532 | } 533 | --------------------------------------------------------------------------------