For all the documentations and videos i followed to learn programming, some concepts seemed bit overwhelming. Therefore, i started copying and pasting a lot of code to get things completed. Everything worked very well until i asked myself, will i ever try to understand WHAT and HOW.
A bit of framework which tries to simplify creating php web projects.
Define your routes at src/Core/routes.php
Adding a new routes
$router->get('about','PagesController@about');
$router->post('contact','ContactsController@save');
'get' and 'post' are the request types, you can additionally use 'delete' & 'patch'
'about' and 'contact' are the requested URL.
'PagesController' is the name of the Controller.
'about' and 'save' are the methods declared inside their controllers.
'@' is used as a separator.
All controllers must be placed inside src/Controllers folder. ( A bit opinionated :) )
User request can be handled with various methods of Request class.
Capture the URL of the request
Request::url();
Capture request method (get,post, patch ...)
Request::method();
Capture a specific $_GET value of the request
Request::query($field);
Here the $field is the name of the anticipated field.
Capture a specific $_POST value of the request
Request::request($field);
Here the $field is the name of the anticipated field.
Capture all the $_POST values of request
Request::all();
Capture all the properties uploaded files
Request::file();
Bit supports two types of responses, View and JSON
Respond as a view page
Response::view('viewfile',$dataToBePassed);
viewfile is the name of placed in view folder, viewfile can be of names *.view.php or *.php or *.html
$dataToBePassed is the data variable that needs to be passed to the view
Respond with JSON data
Response::json($data);
$data must be of type array
Example of the usage of request and response methods. We will try to display the data entered by user
namespace Bit\Controllers;
use Bit\Core\Response;
use Bit\Core\Request;
/**
* OrderController
*/
class OrderController
{
public function newOrder()
{
$userOrder = [];
//Request::all() will provide all the $_POST values
foreach(Request::all() as $field => $value)
{
$userOrder[$field] = $value;
}
//ConfirmOrder is the view page and we are passing user's
//entered data to this view with array $userOrder
Response::view('ConfirmOrder',compact($userOrder));
}
}
Sessions in Bit can be manipulated with some of the methods defined in the Sessions class.
Store a new Session data.
Session::set($key,$value);
$key is the unique identifier of the data that can be stored in Session. $value is the data that needs to be stored in session
Retrieving Session data
Session::get($key);
$key is the unique identifier of the data that was previously saved
Destroy specific Session data
Session::unset($key);
Destroy all the Session data
Session::clear();
Bit helps us to deal with files operations easily with LocalFileHandler class. You can also use third party packages like flysystem, but the adapter class must implement FileHandlerInterface. Unlike other classes it does not use Static methods.
The LocalFileHandler class is already bound to App Container, so there is no need to instantiate it.
Get file name
$uploadedFile = Request::file();
App::get('filesystem')->getfilename($uploadedFile);
Get file size
$uploadedFile = Request::file();
App::get('filesystem')->getsize($uploadedFile);
Get file extension
$uploadedFile = Request::file();
App::get('filesystem')->getextension($uploadedFile);
Copy File to a new destination
$uploadedFile = Request::file();
App::get('filesystem')->copy($uploadedFile, $destination);
Delete file at a location
App::get('filesystem')->delete($filepath);
Create a new directory
App::get('filesystem')->createDir($directoryPath, $permissions);
$permissions signifies the directory permissions, its defaults to 755
Bit makes interaction with variety of databases easy. It uses the QueryBuilder class which acts as a wrapper around php's PDO class. It supports all the database types which is supported by PDO. So, you need to make sure that PDO drivers for the database type is installed in the system.
Configurations for the database can be defined in the configs.php file, explanation has been provided in the later part of this documentation.
QueryBuilder class is already bound to App container already. So it can be acccesed with App::get('database')
Retrieving data from a table
App::get('database')->selectAll($tablename);
Retrieving data from particular columns from a table
App::get('database')->select($tablename, $parameters);
$parameters can be single value or an array
Executing Raw SQl queries
App::get('database')->query($query, $clauses);
$query is the prepared statement e.g.
select * from Orders where OrderID = :orderID and Customer = :Customer
$clauses must be an associative array of column names and values which are defined in the prepared statement $query, e.g.
$clauses = ['orderID' => 23, 'Customer' => 'John'];
The concept of Model in MVC (Real World) is still bit unclear for me. In Bit Models are like collaborator which deals with data of a particular table only. Feel free to add business logic to these.
Models should be placed in the Models Folder. You can extend the BaseModel class in your Model class to take advantage of the simple data manipulation methods.
If your model extends BaseModel class then it must declare the table() property.
namespace Bit\Models;
/**
* Order Model
*/
class Order extends BaseModel
{
//Should return the tablename
//which this Model will deal with
protected function table()
{
return 'Orders';
}
}
Some of the methods for handling data are
Finds all records based on provided conditions
$values = ['orderID' => 23, 'Customer' => 'John'];
(new Order)->find($values);
Finds first record based on provided conditions
$values = ['order' => 'Expresso'];
(new Order)->findFirst($values);
Get all the data of the Model
(new Order)->findAll();
Save data in Model
$data = ['order' => 'Expresso', 'table' => 4, 'quantity' => 'min',
'Customer' => 'smith'];
(new Order)->save($data);
You can only save one record at a time
Update data in Model
$newValues = ['order' => 'latte', 'quantity' => 'max'];
$conditions = ['orderID' => 43, 'Customer' => 'smith'];
(new Order)->update($newValues, $conditions);
Delete data from the Model
$cancelOrder = ['Customer' => 'smith'];
(new Order)->delete($cancelOrder);
Authentication in Bit is just bare bones. LocalAuthentication class is responsible for handling authentication, it only uses php sessions, nothing more fancy. It implements the AuthenticationInterface. You can replace it with any other authentication types like JWT, but make sure to implement the interface AuthenticationInterface.
LocalAuthentication is bound to the App Container and can be accessed by App::get('auth')
Log a user into the system
App::get('auth')->login($user, $redirectPath);
$user is associative array of clauses to check if record exists in table $redirectPath is the route path where user will be redirected if credentials match.
Example
namespace Bit\Controllers;
use Bit\Core\Response;
use Bit\Core\Request;
use Bit\Core\App;
/**
* UserController
*/
class UserController
{
public function loginpage()
{
//In the example we are hard coding,
//in your case it should have come from
//Request::all() or $_POST values
$user = [ 'email' =>'[email protected]',
'password' => 'myPasswordIsComplicated',];
//User will be redirected to 'logged' route if
//credentials matches the data in User table
App::get('auth')->login($user,'logged');
}
Log a user out of the system
App::get('auth')->logout($redirectPath);
$redirectPath is the route where user will be redirected
Check if a user is logged in or not
App::get('auth')->check($redirectPath);
$redirectPath is the route where user will be redirected if system finds that the request did not came from logged in user.
This method can act as a guard to restrict users from accessing resources or pages which is meant for logged in user only.
Example
namespace Bit\Controllers;
use Bit\Core\Response;
use Bit\Core\Request;
use Bit\Core\App;
use Bit\Models\User;
/**
* UserController
*/
class UserController
{
public function profile()
{
//user will be redirected to 'login' route
// in case system finds user is not logged in
App::get('auth')->check('login');
$user = Request::request($userID);
$userData = (new User)->findFirst($user);
Response::view('UserProfile',compact('userData'));
}
App Container sounds overwhelming but, in Bit its just a class which can saves various kind of values by keys.Think of it as an associative array. Its only purpose is to access objects easily.
Do not try to make it more complicated.
New Configurations and objects can be bound to app class in the src/Core/Bindings.php page
App::bind('keyname', new YourObject())
App::get('keyname')
'keyname' is the name of the key, which can be used later to retrive the value.
App::bind() binds values to App Container App::get() retrives the value bound by keyname
You can define various types of configurations in the configs.php file. This file expects a return type of array. This file can be excluded from the version control to avoid sensitive data to be part of package.
Define your database configurations
'database' => [
'dbdriver' => 'databasedriver',
'dbname' => 'databasename',
'host' => 'databasehost',
'username' => 'databaseuser',
'password' => 'password',
'options' => ['other options']
]
configs file returns an associative array.
New configurations like caching and logging can be added to it.
You can bind new configurations by appending new values in configs.php
'mail' => [
'driver' => 'mailchimp',
'apikey' => '124scs5$34jsd',
'type' => 'tsl',
...........................
]
Bind your new configs in src/Core/Bindings.php
App::bind('mail' , App::get('configs')['mail']));
....more improvements underway