TidyPHP is a micro MVC PHP Framework made to understand how PHP Frameworks work behind the scense and build fast and tidy php web applications.
This framework made for learning prupose and may have some issues and still under development.
Getting Started
Run this command from any directory to install new TidyPHP Application. Required PHP 7.4.7 or newer.
composer create-project tidyphp/tidyphp [app-name]
Replace [app-name] with your need directory name for your new application. and to run the application for development you must start from public path. or simply do this.
cd [app-name]
composer serve
Documentation
Configrations
using the power of .env file you can change your database informations. you can change app name or url.
Note url will be generated automaticlly without attach it to .env file.
APP_NAME=TidyPHP
URL = http://localhost:8080
DB_DRIVER=mysql
DB_DATABASE=tidy
DB_USERNAME=root
DB_PASSWORD=
DB_HOST=localhost
Routing
All the routes are defined in routes/web.php file. you can use two methods get or post . if you want to go yoururl/profile you can do one ot these ways.
use App\Controllers\HomeController;
use Tidy\Http\Route;
Route::get('/profile' , function() {
return view('home');
});
Route::get('/profile', [HomeController::class , 'index']);
you can also accept paramters in your route and nameing the route to get the route by route() function.
use App\Controllers\HomeController;
use Tidy\Http\Route;
Route::get('/user/{id}', [HomeController::class , 'user'])->name('user.profile');
Route::post('/user/store', [HomeController::class , 'store'])->name('store');
in your view you can route to any exists route. if the route not exists 404 page will be returned.
<form action="" method="post">
<input type="text" name="user_name">
<input type="submit" name="sumbit"value="">
form>
you can path the paramter you need in your route. in the case of user.profile route accept {id} so you need to path number to the route() method. if there exist route have two params like user/{id}/{secid} you must path array have 2 numbers to route() method. also you can use redirect() method to redirect to the route you need to go.
// App/Controllers/HomeController.php
public function index() {
return redirect(route('user.profile' , $id));
// route('some.name' , [$id , $secid]);
}
Controllers
as we mention in Routing you can define route
Route::get('/user/{id}', [HomeController::class , 'user'])->name('user.profile');
you can find the Controllers in App/Controllers and the previews route will lead you to the method user and the route paramters will be passed to the method
namespace App\Controllers;
use App\Models\User;
class HomeController {
public function user ($id) {
$data['user'] = User::find($id);
return view('user.index' , $data);
}
}
Views
The main file that Views rendered from is views/layouts/app.php. just put in it the basic structure of your HTML , css and js links.
and add {{content}} string inside the body.
<body>
{{content}}
body>
The other files will extend from views/layouts/app.php file and replace the {{content}} string with the file content.
if you have assets like css,images,js make sure to put them in public/assets and use asset() method
"text/css" rel="stylesheet" href="" />
In Controller you can render view with the data you need in the view
namespace App\Controllers;
use App\Models\User;
use App\Models\Post;
class HomeController {
public function user ($id) {
$data['user'] = User::find($id);
$data['posts'] = Post::where(['user_id' , '=' , $id])->get();
return view('user.index' , $data);
}
}
when i path user.index to view() function that mean there is directory user/index.php locatied in views path.
And in views/user/index.php i can use the data like this :
$user->name ?> Posts :p>
foreach($posts as $post) : ?>
<p> $post->status ?> p> endforeach; ?>
you may need rendering view not extend views/layouts/app.php in this case you can use makeView() and path to it dirictory name and needed data if exists
if i have main/index.php path and i need to path to it all users and apply make the file does not extend from the defualt path i can use this :
namespace App\Controllers;
use App\Models\User;
use Tidy\View\View;
class HomeController {
public function index () {
$data['users'] = User::all();
return View::makeView('main.index' , $data);
}
Validation
you may have a form and you want to validate it after submit, so we simply make the action go to our route and then make a validate to the request by the validate() method.
if the validate have any errors it will redirect with the errors to the same page.
so let's define our route :
Route::post('/store/{id}', [HomeController::class , 'store'])->name('store');
you can path an id or not , if you path an id you may need to accept it at the store() function in controller and do your validatation!
so if you have this simple form routes to our route name store
">
in HomeController , store() method we do our validation and use request() method to get the requested form data by the names of the form.
namespace App\Controllers;
use App\Models\User;
use Tidy\Http\Request;
use Tidy\View\View;
class HomeController {
public function store (Request $request , $id ) {
$data = $request->validate(
['name' => 'required|string|max:50',
'email'=> 'required|email|between:6,50' ,
'image' => 'image|mimes:jpg,png'
]
);
User::create( [
'name' => request('name') ,
'email' => request('email') ,
'image' => request('image') ,
]
);
return redirect(route('home' , $id));
}
After this you may need to show the errors after redirect back if the errors exists. you can simply render all errors or render specific error with error() method.
// or load specific error by error() method
">
// you may need to load all errors
if (hasErrors()): ?>
foreach(errors() as $error): ?>
<p class="text-danger">
$error ?>
p>
<br>
endforeach; ?>
endif; ?> // or load specific error by error() method if (hasErrors()): ?> <p class="has-text-danger"> error('name'); ?> p> endif; ?>
The rules of validation
stringcheck if the value is string.numbercheck if the value is numeric.alnumcheck if the value is alpha numbers.requiredreturn error if the value empty string.imagecheck if the value is image.mimescheck the file extention example:mimes:jpeg,png.emailcheck if the value is email.betweencheck if the value length between two numbers. example:between:5,50.emailcheck if the value is email.maxcheck if the value length not exceed than the number example :max:60.mincheck if the value length not less than the number example :min:6.
Database
Query Builder
to runing database queries must use the powerfull DB class. you can execute on it many options like where , orWhere, orderBy, groupBy, whereIn , and many other options to make it eaiser than runing simple queries.
in example we are in controller and we need to get all of users table , we can use the DB like this.
use Tidy\Database\DB;
// App/Controllers/HomeCotroller.php
class HomeController {
public function index () {
$data = DB::table('users')->get();
return view('home' , $data);
}
Select
if you want to select specific colms from your table. you can use select() method.
DB::table('users')->select('id')->get();
// OR
DB::table('users')->select(['name' , 'email'])->get();
Where Clauses
you can control your query more than this by applying methods like
where(),orWhere(),andWhere()whereIn(),orWhereIn(),andWhereIn()notWhereIn(),andWhereNotIn(),orWhereNotIn()
you can not apply and , or methods without applying where methods first to make the query works fine.
DB::table('users')->select('id')->where(['country' , '=' , 'egypt'])
->orWhereNotIn('id' , ['1' , '2' , '3'])->get();
DB::table('users')->whereIn('id' , ['1' , '2' , '3'])->andWhere(['id' , '>' , '6'])->get();
DB::table('users')->where(['id' , '>' , '6'])->andWhere(['country' , '=' , 'egypt'])->get();
Ordering
orderBy() method accept the defult order the given argument asc order, you can order by desc order by passing second paramter 'desc' to the function. also there is latest() method that return the latest rows inserted to your table, it will return by defualt the latest rows by the id you can override it to date or anything.
DB::table('users')->where(['id' , '>' , '6'])->orderBy('id')->get();
DB::table('users')->where(['id' , '>' , '6'])->orderBy('id' , 'desc')->get(); // DESC
DB::table('users')->where(['id' , '>' , '6'])->orWhereIn('country' , ['egypt' , 'uk' , 'us'])
->latest('date')->get(); // latest() return ordered by id by defualt
Grouping
Grouping by groupBy() and having() methods. for aggregate functions like this:
DB::table('users')->groupBy('id')->having('id', '>', 6)->get();
let's introduce our first() and take() methods by simple example. you can use first() instead of get() method. let's do a simple query to get the most frequency name in your table
DB::table('users')->select(['COUNT(name) as name_count' , 'name'])
->groupBy('name')->orderBy('name_count' , 'desc')->first();
// you can also take the first 3 by take() function
DB::table('users')->select(['COUNT(name) as name_count' , 'name'])
->groupBy('name')->latest('name_count')->take(3)->get();
there is also another methods we can use instead of get() . exists() methods return true if there is availabe rows in your query. also you have count() method that return the number of rows returned from query.
DB::table('users')->where(['id' , '=' , 3])->exists();
// how many users located in egypt,germany,canda.
DB::table('users')->whereIn('country' , ['egypt' , 'germany' , 'canda'])->count();
Eloquent Model
models are located in App/Models path and it must extend Model class to interacte with database table. the model let you read, insert, update , delete rows from the table.
Table Name
The default table name will be the plural of the class name , so if class User the table name will be users. but you can simply override the default by $table property .
namespace App\Models;
use Tidy\Database\Model\Model;
class User extends Model {
protected static $table = 'my_users';
}
Retrieving Data
Once you created your model, you can start retrieving data from your database. first you can use all() method to retrieve all the rows from your table
foreach(User::all() as $user ) {
echo $user->name;
}
also every model has a Query builder too , you can apply to it all where() orderBy() groupBy() methods and use the power of get() first() count() exists() methods on it. also you can select specific colms to retrieve but in another way this time .
where() orderBy() groupBy() methods accept another paramter $columns i can path to it an array or just simple string to select specific colms.
methods who accept two paramters the third paramter will be the colums paramter , and if accept one paramter the second will be the columns paramter . it will be default * .
// examples:
User::where(['id' , '=' , 5] , 'id')->orWhereIn('id' , [1,7,8])->get();
User::whereIn( 'id' , [1,7,8], ['id', 'name'])->latest()->get();
// most frequency of names in your table
User::groupBy('name' , ['COUNT(name) as name_count' , 'name'])->latest('name_count')->first();
// count the people in specific countries.
User::whereIn('country' , ['egypt' , 'us'], ['name' , 'country'])->count();
you can use find()method to find row by the id.
$user = User::find(2);
Affect tables
also you can apply create() update() delete() methods also on the model.
// insert
User::create(
[
'name' => 'aminyasser' ,
'email' => '[email protected]',
'password' => md5('122131') ,
]
);
// update
User::update( 5 ,
[
'name' => 'aminyasser' ,
'email' => '[email protected]',
'password' => md5('122131') ,
]
);
// delete
User::delete(5);
