Skip to content

faustfizz/footup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Footup MVC PHP Framework

Footup Logo

FOOTUP MVC FRAMEWORK - 0.1.7-alpha.8

follow on Twitter

A Rich Featured LightWeight PHP MVC Framework :

  • CLI support for generating Controller, Model, Middle, Migration, Seeder, Assets and View files ( adhocore/php-cli modified and used thanks :) )
  • Translation support
  • Config using PHP File or .env (Rename env to .env)
  • Request
  • Response
  • Validator (Form Validation - Not validating UploadedFile) Thanks to pdscopes/php-form-validator
  • Pagination (Pagination and Pagination View) Thanks to iranianpep/paginator
  • Session
  • Email (CodeIgniter 4 Email Class)
  • Routing
  • Controller AND Middleware (But here we call it just Middle and are specific)
  • Model RelationShips ($hasOne, $hasMany, $belongsTo, $belongsToMany)
  • Model QueryBuilder
  • Model Events CallBacks
  • Files (Upload File)
  • Extensible (You can integrate any library you want and you can add (news folders and class) in the App Directory using psr4 autoloading mecanism)

ReadMe should be updated -- (Soon i'll create the docs website for FootUp PHP MVC Framework)


Directories tree

FOOTUP MVC Framework
├── app
│   ├── Config
│   │   ├── Autoload.php
│   │   ├── Config.php
│   │   ├── Constants.php
│   │   ├── Email.php
│   │   ├── Form.php
│   │   ├── Fuel.php
│   │   ├── Paginator.php
│   │   └── Routes.php
│   ├── Controller
│   │   ├── BaseController.php
│   │   └── Home.php
│   ├── Functions.php
│   ├── Lang
│   ├── Libs
│   ├── Middle
│   │   └── Maintenance.php
│   ├── Migration
│   ├── Model
│   │   └── Contact.php
│   ├── Seed
│   └── View
│       └── home.php
├── composer.json
├── core
│   ├── Boot.php
│   ├── Cli
│   │   ├── Commands
│   │   │   ├── Assets.php
│   │   │   ├── Controller.php
│   │   │   ├── Middle.php
│   │   │   ├── Migfree.php
│   │   │   ├── Migrate.php
│   │   │   ├── MigrateTrait.php
│   │   │   ├── Migrown.php
│   │   │   ├── Migrup.php
│   │   │   ├── Model.php
│   │   │   ├── Multiple.php
│   │   │   ├── Scaffold.php
│   │   │   ├── Seeder.php
│   │   │   ├── Seed.php
│   │   │   ├── Serve.php
│   │   │   └── View.php
│   │   ├── Exception
│   │   │   ├── Exception.php
│   │   │   ├── InvalidArgumentException.php
│   │   │   ├── InvalidParameterException.php
│   │   │   └── RuntimeException.php
│   │   ├── Helper
│   │   │   ├── InflectsString.php
│   │   │   ├── Normalizer.php
│   │   │   ├── OutputHelper.php
│   │   │   └── Shell.php
│   │   ├── Input
│   │   │   ├── Argument.php
│   │   │   ├── Command.php
│   │   │   ├── Groupable.php
│   │   │   ├── Option.php
│   │   │   ├── Parameter.php
│   │   │   ├── Parser.php
│   │   │   └── Reader.php
│   │   ├── IO
│   │   │   └── Interactor.php
│   │   ├── Konsole.php
│   │   ├── logo
│   │   ├── logo_txt
│   │   ├── Output
│   │   │   ├── Color.php
│   │   │   ├── Cursor.php
│   │   │   ├── Table.php
│   │   │   └── Writer.php
│   │   └── Tpl
│   │       ├── Controller.tpl
│   │       ├── Middle.tpl
│   │       ├── Migrate.tpl
│   │       ├── Model.tpl
│   │       ├── Seed.tpl
│   │       └── View.tpl
│   ├── Config
│   │   ├── Autoload.php
│   │   ├── Config.php
│   │   ├── DotEnv
│   │   │   ├── DotEnv.php
│   │   │   └── Exception
│   │   │       ├── Exception.php
│   │   │       └── InvalidPathException.php
│   │   ├── Email.php
│   │   └── Mime.php
│   ├── Controller.php
│   ├── Database
│   │   ├── DbConnection.php
│   │   ├── Migration
│   │   │   └── Migration.php
│   │   ├── Migration.php
│   │   ├── QueryBuilder.php
│   │   ├── Schema
│   │   │   ├── Column.php
│   │   │   ├── ForeignKey.php
│   │   │   ├── IndexColumn.php
│   │   │   ├── Index.php
│   │   │   ├── Schema.php
│   │   │   └── Table.php
│   │   ├── Seeder
│   │   │   └── Seeder.php
│   │   └── Seeder.php
│   ├── Debug
│   │   ├── Contracts
│   │   │   └── HandlersInterface.php
│   │   ├── Exceptions
│   │   │   ├── CompileErrorException.php
│   │   │   ├── CompileWarningException.php
│   │   │   ├── CoreErrorException.php
│   │   │   ├── CoreWarningException.php
│   │   │   ├── DepricatedException.php
│   │   │   ├── NoticeException.php
│   │   │   ├── ParseErrorException.php
│   │   │   ├── RecoverableErrorException.php
│   │   │   ├── StrictErrorException.php
│   │   │   ├── UserDeprecatedException.php
│   │   │   ├── UserErrorException.php
│   │   │   ├── UserNoticeException.php
│   │   │   ├── UserWarningException.php
│   │   │   └── WarningException.php
│   │   ├── Handlers.php
│   │   ├── HandlersSetter.php
│   │   ├── Reporter.php
│   │   ├── resources
│   │   │   ├── assets
│   │   │   │   ├── css
│   │   │   │   │   ├── custom.min.css
│   │   │   │   │   ├── enlighterjs.min.css
│   │   │   │   │   └── spectre.min.css
│   │   │   │   └── js
│   │   │   │       ├── custom.min.js
│   │   │   │       └── enlighterjs.min.js
│   │   │   └── views
│   │   │       └── 500.php
│   │   ├── Support
│   │   │   └── functions.php
│   │   └── View.php
│   ├── Files
│   │   ├── File.php
│   │   └── FileSystem.php
│   ├── footup-ascii-art.png
│   ├── Footup.php
│   ├── Functions.php
│   ├── Html
│   │   ├── Form.php
│   │   └── Html.php
│   ├── Http
│   │   ├── Request.php
│   │   ├── Response.php
│   │   └── Session.php
│   ├── I18n
│   │   ├── Exceptions
│   │   │   └── I18nException.php
│   │   ├── TimeDifference.php
│   │   └── Time.php
│   ├── Lang
│   │   ├── fr
│   │   │   ├── core.json
│   │   │   ├── date.json
│   │   │   ├── db.json
│   │   │   ├── email.json
│   │   │   ├── file.json
│   │   │   ├── http.json
│   │   │   ├── paginator.json
│   │   │   ├── validator.json
│   │   │   └── view.json
│   │   └── Lang.php
│   ├── Model.php
│   ├── Orm
│   │   ├── BaseModel.php
│   │   └── ModelQueryBuilder.php
│   ├── Paginator
│   │   ├── AbstractPaginator.php
│   │   ├── Page.php
│   │   ├── PaginatorException.php
│   │   ├── PaginatorInterface.php
│   │   ├── Paginator.php
│   │   └── View
│   │       └── default.php
│   ├── Routing
│   │   ├── Middle.php
│   │   ├── Route.php
│   │   └── Router.php
│   └── Utils
│       ├── Arrays
│       │   ├── Arrayable.php
│       │   ├── ArrDots.php
│       │   ├── Arr.php
│       │   ├── Collection.php
│       │   └── Dots.php
│       ├── ClassLocator.php
│       ├── Shared.php
│       ├── Str.php
│       └── Validator
│           ├── Validate.php
│           └── Validator.php
├── env
├── footup
├── LICENSE
├── public
│   ├── assets
│   │   ├── avatar.jpg
│   │   ├── css
│   │   │   └── style.css
│   │   └── js
│   │       └── script.js
│   ├── error
│   │   ├── 404.html
│   │   └── 500.html
│   ├── favicon.svg
│   ├── index.php
│   └── uploads
├── README.md
└── server.php

Description

FOOTUP MVC Framework focus primarily to speed and minimalistic. It's 250 Kb zip, 148 kb xz. It render withing 0.001 seconds (I used a PHP 8.0.7 environment to write and test it).

My goal is doing a thing that i'm the first person that use it with ease. I added some features that help me working faster on my all day's work.

Requirements

Yo ! You can download this directly and use it without no need to external dependancy. It support composer libraries but i have not published footup yet to packagist.

So you need:

  • PDO extension
  • mb_string
  • intl
  • json

WalkThrough

CLI

For now I added just generators commands

To show help:

nuka@hacker_pc:~$ php footup 

To generate controller:

nuka@hacker_pc:~$ php footup controller controllerName

Don't be so shy, try yourself

Request

The request and the router class are the BMW Motors They hold many thing helpful. Here how we use the request:

You are in the controller ? use like this :

// using get function to get the page=3 present in the url
$this->request->get("page");

// you can use like this to get the page
$this->request->page;

// What ? you typing enough ? and that ?
request()->page;

// And What ? how to get file with name: image ?
// You can use as below
$this->request->image; // or $this->request->file('image')

// And What if image[] as multiple files ?
// You can use as below
$this->request->files('image');

# Yes you can access the request using the global function request()

But Yes, with the request you can validate data via validator like this :

// using get function to validate the page=3 present in the url
$this->request->withGetInput()->validate(["page" => "is:int"]);

// What ? you typing enough ? and that ?
request()->withGetInput()->validate(["page" => "is:int"]);

# Yes you can access the request using the global function request()

Don't be so shy, explore the request class, your editor will autocomplete

The Response object is available in the controller :

// using get function to validate the page=3 present in the url
$this->response->json(["page" => 2]); // second parameter to echo directly

# Yes you can access the response using the global function response()

The Session

This is a shared class so the data withing it remain the same, here is the example :

// using set function to set session value
$this->session->set(["page" => 2]); // or $this->session->page = 2

// What ? you typing enough ? and that ?
session("page", 2); // session()->set("page", 2); or session()->page = 2;

// What ? i want to get the page ?
// So
session("page"); // session()->get("page"); or session()->page;

# Yes you can access the session using the global function session() as shown

Validator :

If you validate data with validator, the validate function return TRUE if all passed and FALSE otherwise

// Via request
// with post data
$this->request->withPostInput()->validate(["page" => "is:int"]);

// With post and get data
request()->withInput()->validate(["page" => "is:int"]);

// With other data
request()->with(["page" => 2])->validate(["page" => "is:int"]);

// So how to get Error ?
// Simple
validator()->getError("page"); // request()->getValidator()->getErrors(); to grab all

# Yes you can access the validator using the global function validator()
# You can validate using the global function validate() too

I will write documentation if if if .... LOL -- If you can do it, help me !

I think i don't like writing LOL

Using the Model

<?php

namespace App\Model;
use Footup\Model;

class Contact extends Model{
  // If not defined, the name of this class is used
  protected $table = 'contact';
  /**
   * PrimaryKey
   *
   * @var string
   */
  protected $primaryKey = 'idcont';

  protected $beforeInsert         = [];
  protected $beforeFind           = [];
  protected $beforeDelete         = [];
  protected $beforeUpdate         = [];
  protected $afterInsert          = [];
  protected $afterFind            = [];
  protected $afterDelete          = [];
  protected $afterUpdate          = [];
}

// Using the model Contact
.....
  use App\Model\Contact;
  ....
  // Retrouve tout | retrieve all
  $contacts = Contact::all();
  ------------ others methods --------------
  $c = new Contact();
  $contacts = $c->get();
  foreach($contacts as $contact)
    echo $contact->email;
  
  # you can also use 
  $contact->setEmail("fuck@you.yh");

  // Generating form ******
  $contact->getForm();

  var_dump($c->firstByEmail('faus@fizz.io'));
  ..........................
  

Globals Functions | Fonctions glabales

request($index = null, $arg = null)

  /**
   * Une fonction pour exposer l'objet Request
   *
   * @param mixed $index
   * @param mixed $arg
   * @return Footup\Http\Request|mixed
   */
  request($index = null, $arg = null)

calledController($withNamespace = true)

  /**
   * Retrouve le controlleur en cours d'utilisation
   *
   * @param boolean $withNamespace
   * @return string
   */
  calledController($withNamespace = true)

calledMethod()

  /**
   * Retrouve la méthode couremment utilisée
   *
   * method of the current called controller
   * 
   * @return string
   */
  calledMethod()

And many mores others globals functions

Uploading file | Téleverser un fichier

  #eg. file field = image
  # @uses one below
  request('image') or request()->image or request()->file('image')

  # remember that request is available directly in the controller so :
  $this->request->image

  # et pour enregistrer le fichier | and for saving :
  request('image')->save(?string $destinationName = null, bool $replace = true) or request()->image->save(?string $destinationName = null, bool $replace = true) or request()->file('image')->save(?string $destinationName = null, bool $replace = true)

  # remember that request is available directly in the controller so :
  $this->request->image

Getting Auto Genereted Form | Avoir un formulaire auto généré

  $contact = new ContactModel();
  $contact->getForm("#", [], true /* true to print */ )
  # or use
  echo $contact->getForm();

QueryBuilder Methods | Méthode de Model QueryBuilder

# model->from($table, $reset = true): $this

Utilise $reset = false si vous ne souhaiter pas recommencer une requête. Utilise $table pour changer de table (cette méthode vous l'utiliserez rarement)

# model->join($table, $fields, $type = 'INNER', $operator = '='): $this

  • $type doit être un dans ['INNER', 'LEFT OUTER', 'RIGHT OUTER', 'FULL OUTER']
  • $fields string|array ex: "user.id = article.id_user" | ["user.id" => "article.id_user"]

# model->leftJoin($table, $fields, $operator = '='): $this

  • $fields string|array ex: "user.id = article.id_user" | ["user.id" => "article.id_user"]

# model->rightJoin($table, $fields, $operator = '='): $this

  • $fields string|array ex: "user.id = article.id_user" | ["user.id" => "article.id_user"]

# model->where($key, $val = null, $operator = null, $link = ' AND ', $escape = true): $this

  • $key string|array ex: "id = 1" | ["id" => 1]
  • $link string where $link is AND | OR | IS
  • $fields string|array ex: "arnauld" | [2, 3, 5] for $operator IN | NOT IN

# model->whereOr($key, $val = null, $operator = null, $link = ' AND ', $escape = true): $this

  /**
    * @param string|array $key
    * @param null $operator
    * @param null $val
    * @return $this
    */
  public function whereOr($key, $val = null, $operator = null, $escape = true)

# model->whereIn($key, array $val, $escape = true) | whereOrIn($key, array $val, $escape = true): $this

  /**
   * @param $key
   * @param array $val
   * @return $this
   */
  public function whereIn($key, array $val, $escape = true)

# model->whereRaw($str) | whereOrRaw($str): $this

  /**
   * @param string $str
   * @return $this
   */
  public function whereRaw($str)

# model->whereNotIn($key, array $val, $escape = true) | whereOrNotIn($key, array $val, $escape = true): $this

  /**
   * @param $key
   * @param array $val
   * @return $this
   */
  public function whereNotIn($key, array $val, $escape = true)

# model->whereNotNull($key) | whereOrNotNull($key): $this

  /**
   * @param string $key
   * @return $this
   */
  public function whereNotNull($key)

# model->whereNull($key) | whereOrNull($key): $this

  /**
   * @param string $key
   * @return $this
   */
  public function whereNull($key)

# model->asc($field): $this

  /**
   * Adds an ascending sort for a field.
   *
   * @param string $field Field name
   * @return object Self reference
   */
  public function asc($field)

# model->desc($field): $this

  /**
   * Adds an descending sort for a field.
   *
   * @param string $field Field name
   * @return object Self reference
   */
  public function desc($field)

# model->orderBy($field, $direction = 'ASC'): $this

  /**
   * Adds fields to order by.
   *
   * @param string $field Field name
   * @param string $direction Sort direction
   * @return object Self reference
   */
  public function orderBy($field, $direction = 'ASC')

# model->insert($data): bool

  /**
   * Builds an insert query.
   *
   * @param array $data Array of key and values to insert
   * @return bool
   */
  public function insert(array $data = [])

# model->update($data): bool

Cette méthode doit être utilisée après une clause where

  /**
   * Builds an update query.
   *
   * @param array $data Array of keys and values, or string literal
   * @return bool
   */
  public function update($data)

# model->delete($where): bool

  /**
   * Builds a delete query.
   *
   * @param string|int|array $where Where conditions
   * @return bool
   */
  public function delete($where = null)

# model->sql($raw_sql): $this

Si $raw_sql est null, la méthode retourne une chaine de caractères, retourne $this sinon.

  /**
   * Gets or sets the SQL statement.
   *
   * @param string|array SQL statement
   * @return self|string SQL statement
   */
  public function sql($sql = null)

# model->save($objet = null, $db_fields = null): bool

  • $object: the object to get data on default: $this
  • $db_array: database fields ex: ['email', 'username']
  /**
   * Saves an object to the database.
   *
   * @param object $objet Class instance
   * @param array $db_fields Select database fields to save (insert or update)
   * @return boolean
   */
  public function save($objet = null, array $db_fields = null)

# model->remove($objet = null): bool

  • $object: the object to get primaryKey data on default: $this
  /**
   * Removes an object from the database.
   *
   * @param object
   * @return boolean
   */
  public function remove($objet = null)

NOTE: Si tu as déjà utilisé un framework comme CodeIgniter 4 tu maitriseras vite Autres méthodes groupBy, having, limit, offset, distinct, between, select, last, find, min, count, max, avg, one, first et des méthodes dynamiques comme firstBy{Field}, lastBy{Field}, findBy{Field} où {Field} est un attribut de la table.

/**
 * Gets the database connection instance PDO.
 *
 * @return object Database connection
 */
public function getDb()
  /**
   * Executes a sql statement.
   *
   * @return object Query results object
   * @throws Exception When database is not defined
   */
  public function execute(array $params = [])
  /**
   * Perform a query
   *
   * @param string $select
   * @param array|string $where
   * @param int $limit
   * @param int $offset
   * @return array - of object class
   */
  public function get($select = "*", $where = null, $limit = null, $offset = null)
  # Autres Méthodes
  ==================

  /**
   * Get the table name for this ER class.
   * 
   * @access public
   * @return string
   */
  getTable ()

  /**
   * Get the primaryKey
   * 
   * @access public
   * @return string
   */ 
  getPrimaryKey()

  /**
   * Get model property fields by data table.
   *
   * @access public
   * @return array of available columns
   */
  getFields()

  /**
   * Create new data row.
   *
   * @access public
   * @param array $properties
   * @return object Model instance
   * @return bool
   */
  create(Array $properties)

  /**
   * Find one model in the database.
   * or create if not exists.
   *
   * @access public
   * @param array $properties
   * @return object Model instance
   * @return array|bool if error occured
   */
  findOrCreate(Array $properties = null)

  /**
   * Find all model in the database.
   *
   * @access public
   * @param mixed $where
   * @return array|object
   */
  public static function all($where = null)

Exemple de création de Controller

<?php

namespace App\Controller;
use App\Model\Contact;

class Home extends BaseController{

  public function index(){
    // Retrouve la méthod utilisée | HTTP Verb
    if($this->request->method() === 'post'){

      // retrouve un fichier | retrouve uploaded file
      $image = $this->request->file('image');
      // save
      $image->save();
      // get the name of the moved file 
      echo $image->name;
    }

    // Using model Contact
    // all() est la seule méthode statique | all() is the only static method
    $contacts = Contact::all();
    $contacts = (new Contact())->get());
    
    // Afficher la vue | display the vue
    return $this->view("accueil", [
        "titre" => "Accueil"
    ]);
  }

}
  

Credits Libraries

Paginator iranianpep/paginator

Form Validator pdscopes/php-form-validator

PHP Arrays pdscopes/php-arrays

PHP CLI by Adhocore adhocore/php-cli

License

BSD 3-Clause License

Copyright (c) 2021, Faustfizz youssoufmbae2@gmail.com All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.