• Uzuvi
  • GitHub

    Unreally Lightweight and
    Flexible PHP Framework

    0.052Mb  ●  Last Update 24 Jan 2020

  • Flexible Routes

    	Route::handle($url, "about", function() {
    		tpl::include('about.html');
    	});
    
  • Convenient Templates

    	<? tpl::begin('base'); ?>
    		hello
    	<? tpl::end(); ?>
    
  • Elegant Models

    	class Movies {
    		static function get($rowid) {
    			return Db::get("movies", $rowid);
    		}
    	}
    
  • Obvious Controllers

    	class MoviesController {
    		static function get($rowid) {
    			Response::json(Movies::get($rowid);
    		}
    	}
    
  • Simple JSON API

    	Route::handle($url, "api/movies/get/{id}", function($id) {
    		MoviesController::get($id);
    	});
    
  • SVG Icons

    	<body>
    		<?=svg::icon('arrow-right')?>
    		Result will be: <svg class='icon'><use xlink:href='#arrow-right'></svg>"
    	</body>
    
  • Documentation

    File Structure

    /project
    	/core
    		/ajax.js            - usefull ajax function with form data support
    		/utils.js           - common JS functions
    		/autoload.php       - autoloader class
    		/ds.php             - data storage class to work with sqlite3
    		/mail.php           - mail class
    		/route.php          - route class
    		/svg.php            - svg icons class
    		/tpl.php            - HTML template engine
    		/utils.php          - common PHP functions
    	/.htaccess             - redirects all requests to index.php
    	/theme.css             - base css
    	/base.html             - base template
    	/index.html            - main page
    	/_movies.php           - movies model
    	/_moviescontroller.php - movies controller
    	/index.php             - index.php handles pages and api requests
    	/icons.svg             - svg icons sprite
    	/favicon.png
    

    Routes

    First, in the .htaccess I configure URL handling like this:
    //.htaccess
    	
    php_flag short_open_tag on
    RewriteEngine on
    RewriteRule sqlite3$ forbidden
    
    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php?method=$1 [QSA]
    
    Then, in the index.php I handle pages and API requests like this:
    // index.php
    
    <?php
    	require_once(__DIR__.'/core/autoload.php');
    	session_start();
    	tpl::cd(__DIR__);
    	autoload::addfolder(__DIR__);
    	ds::connect(__DIR__.'/database.sqlite3');
    	$method = $_GET['method'];
    	
    	// Api Routes
    	//---------------------------------------------------------------------------
    	Route::handle($method, "api-(\\w+)-(\\w+)-(\\w+)", 
    		function($class, $method, $rowid) {
    			call_user_func_array("{$class}Controller::ajax_$method", [$rowid]);
    	});
    	Route::handle($method, "api-(\\w+)-(\\w+)", 
    		function($class, $method) {
    			call_user_func_array("{$class}Controller::ajax_$method", []);
    	});
    	
    	// Pages Routes
    	//---------------------------------------------------------------------------
    	Route::handle($method, "(.*)", function($page) {
    		$page or $page = "index";
    		include(__DIR__ . "/$page.html");
    	});
    

    Templates

    For example if you have base.html template:
    // base.html
    
    <!doctype html>
    <html>
    	<head>
    		<title> .. </title>
    	</head>
    	<body>
    		<?=$content?>
    	</body>
    </html>
    
    And footer.html template:
    // footer.html
    
    <footer> Support: example@exmple.com </footer>
    
    You can use it in index.html like this:
    // index.html
    
    <? tpl::begin('base'); ?>
    	hello
    	<? tpl::include('footer'); ?>
    <? tpl::end(); ?>	
    
    Templates directory can be configured like this:
    // index.php
    	...
     	tpl::cd(__DIR__);
     	...
    

    Models

    I create each model as a class in a separate file - usual approach. What is not usual: this framework advice you to create models as a facade. All functions in class are static. I think this style can be called facade-based style. Notice that snake-case naming is used in examples. But in your project you can use camel-case or any other you like.
    // _movies.php	
    <?php
    	class Movies
    	{
    		static $table = "movies";
    		
    		static add($values) {
    			return ds::add(self::$table, $values);
    		}
    		static remove($rowid) {
    			return ds::remove(self::$table, $rowid);
    		}
    		static update($rowid, $values) {
    			return ds::update(self::$table, $rowid, $values);
    		}
    		static get($rowid) {
    			return ds::get(self::$table, $rowid);
    		}
    		static show($limit = 200) {
    			$table = self::$table;
    			return ds::qsa("select * from $table limit ?", [$limit]);
    		}
    		static find_by_director($director_id) {
    			$table = self::$table;
    			return ds::qsa("select * from $table where director_id=?", [$director_id]);
    		}
    	}
    	
    	// You can use Movies class later like this:
    	
    	$movie_id = Movies::add(['title' => 'Pink Panther']);
    	
    	$director = People::find_by_name('Blake Edwards');
    	
    	Movies::update($movie_id, ['director_id' => $director->rowid]);
    	
    	Movies::remove($movie_id);
    
    

    Controllers

    I create each controller as a class in a separate file - usual approach. What is not usual: this framework advice you to create controllers as a facade. All functions in class are static. I think this style can be called facade-based style. Notice that snake-case naming is used in examples. But in your project you can use camel-case or any other you like.
    // _moviescontroller.php		
    <?php
    	class MoviesController
    	{
    		static ajax_add() {
    			$rowid = Movies::add($_POST);
    			Response::json(Movies::get($rowid));
    		}
    		
    		static ajax_remove($rowid) {
    			Response::json(Movies::remove($rowid));
    		}
    		
    		static ajax_update($rowid) {
    			Response::json(Movies::update($rowid, $_POST));
    		}
    		
    		static ajax_get($rowid) {
    			Response::json(Movies::get($rowid));
    		}
    		
    		static ajax_show() {
    			Response::json(Movies::show($_POST['limit']));
    		}
    	}
    
    Later you can use MoviesController in ajax requests.

    Rest API

    You can use MoviesController in ajax requests. Remember, this example will work only if routes configured as in example before
    // main.js	
    window.on("load", () => {
    	ajax("api-movies-add", {values: {title: "Pink Panther"}}).then(() => {
    		clog("Movie added");
    	});
    	
    	ajax("api-movies-get-1", {json: true}).then((json) => {
    		clog("Movie 01", json);
    	});
    	
    	ajax("api-movies-update-1", {values: {title: "Rand" + Date.now()}}).then(() => {
    		clog("Movie updated");
    	});
    	
    	ajax("api-movies-show", {json: true, values: {limit: 100}}).then((json) => {
    		clog("Movies:", json);
    	});
    });
    

    Svg Icons

    Svg class will help you to use svg icons in HTML templates. First, I somehow, for example manually, create icons.svg file which is svg sprite file:
    // icons.svg
    
    <svg hidden>
    	<symbol id="arrow-right" viewBox="0 0 448 512">
    		<path d="M218.101 38.101L198.302 ... 0z"></path>
    	</symbol>
    	<symbol id="question" viewBox="0 0 384 512">
    		<path d="M 194.94878,0.15609503 ... z"></path>
    	</symbol>
    	...
    </svg>
    
    Then I include this file in base HTML template, for example in the base.html
    // base.html
    
    <!doctype html>
    <html>
    	<head>
    		<title> .. </title>
    	</head>
    	<body>
    		<?php include(__DIR__.'/icons.svg')?>
    		...
    	</body>
    </html>
    
    After that I can use Svg::icon(...) method to insert svg icons into HTML. For example in the index.html like this:
    // index.html
    <? tpl::begin('base'); ?>
    
    	<?=svg::icon('arrow-right')?>
    	<?=svg::icon('question')?>
    	
    	Result will be:
    	
    	<svg class='icon'><use xlink:href='#arrow-right'></svg>"
    	<svg class='icon'><use xlink:href='#question'></svg>"
    	
    <? tpl::end(); ?>	
    
    To make it really work you also should add CSS like this:
    // theme.css
    svg.icon { max-width: 1em; max-height: 1em; display: inline-flex; 
    	vertical-align: middle; fill: currentColor;  }
    
    Done
    Uzuvi ©2020 uzuvi.site