Git Product home page Git Product logo

framework's Introduction

WebFiori Framework

Note: This repo contains the core of the framework. Application template can be found in the repo webfiori/app

What is WebFiori Framework?

WebFiori Framework is a mini web development framework which is built using PHP language. The framework is fully object-oriented (OOP). It uses semi-MVC model, but it does not force it. The framework comes with many features which can help in making your website or web application up and running in no time.

Supported PHP Versions

Build Status

Key Features

  • Provide minimum utilities to setup a small/medium web application.
  • Theming and the ability to create multiple UIs for the same web app using any CSS or JavaScript framework.
  • Building and manipulating the DOM of a web page inside PHP.
  • Basic template engine.
  • Fast and simple routing engine.
  • Creation of web services (or APIs) that supports JSON with data filtering and validation.
  • Middleware support for HTTP requests filtering before reaching application level.
  • Basic support for MySQL and MSSQL schema and query building.
  • Lightweight. The total size of framework core files is less than 3 megabytes.
  • Access management by assigning system user a set of privileges.
  • Customized sessions manager.
  • Support for creating and sending nice-looking HTML emails.
  • Autoload of user defined classes (loading composer packages also supported).
  • Ability to create background tasks and let them run in specific time using CRON.
  • Well-defined file upload and file handling sub-system.
  • Basic support for creating CLI Applications.

Standard Libraries

Following table shows build status of the standard libraries that the framework is composed of. The build is based on the latest stable PHP release.

Library Build Latest
HTTP
File
Json
UI
Collections
Database
CLI
Mailer
Errors and Exceptions Handler

Problems Solved

One of the things that any developer cares about any software project is the problem or problems it solves. As for WebFiori framework, It can help in solving the following problems:

  • The ability to create a customized links to web pages as needed by using Routing.
  • No need for touching HTML to play with the DOM by using UI Library of the framework.
  • Run PHP code as a CRON task through HTTP protocol or through terminal as a Background Job.
  • Changing whole user interface by changing one line of code through Theming.
  • Ability to move the source code of the web application without having to do a lot of re-configuration.
  • Sending HTML email messages with attachments without having to write a lot of code.
  • Solved the issues which are found in default PHP session management implementation by implementing a custom Sessions Management System.
  • Reduce the number of dependencies at which a developer need to set up a web application.

Getting Started

To learn the basics of how to use the framework, please head on to https://webfiori.com/learn. You can also read same docs which can be found in docs repo. In addition to that, you can read the API docs of the framework at the official website.

Setup

Local Development Environment

If you plan to test the framework on your local machine, the recommended way is to have AMP stack (Apache, MySQL and PHP). There are many available online. We suggest to use the ones that are offered by Bitnami. You can go to https://bitnami.com/stacks/infrastructure to check the available options.

After installing AMP stack, you can either use composer to install the framework or install it manually by download it through https://webfiori.com/download. If you plan to use composer, then you must first download composer from their website: https://getcomposer.org/download/. Once downloaded, place the .phar file in the folder htdocs or your server root. Once you do that, run the terminal in htdocs and run the following command:

php composer.phar create-project --prefer-dist webfiori/app my-site

This command will create new folder with the name my-site and install the framework inside it.

For more information about how to set up the framework, check here.

Contribution

For information on how to contribute to the project, check here.

Notes

  • If you think that there is a better way of doing things or wants new feature, feel free to drop an issue.
  • To report security vulnerabilities, please email [email protected].

License

The project is licensed under MIT license.

framework's People

Contributors

ibrahimbeladi avatar usernane avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

ossdev07

framework's Issues

[Enhancement] Add Support for More Middleware Groups

Currently, when a new route is created, it will be added to a middleware group called global automatically. The framework supports 4 types of routes, API, closure and a page route. Each has its own method. Currently, there is no difference in the way for creating routes except for the method that will be used to create the route.

Also, at the end, the two routes will be similar even though they where added using different methods. So, the only current benefet of the methods is to organize routes.

What if we add another benefit to that? For example, if a route is created using the method Router::api(), it should be added to the middleware group global and another group called api. This would add extra feature to the method.

Suggested Groups:

The following groups are suggested:

  • Router::api(): Add to the group global and api.
  • Router::closure(): Add to the group global and closure.
  • Router::view(): Add to the group global and web.
  • Router::addRoute(): Add to the group global only.

Add a Way to Force a Specific CRON Job to Execute Through CLI

Currently, it is possible to only check if it is time to run jobs in CLI. It would be great if we have the ability to force a single job to execute through CLI. For example, the command would be something like the following:

php WebFiori.php --force-cron <job-name>

[Bug] A Bug Which Can Be Seen When Trying to Open Cron Web Interface with Password

Problem

When trying to access CRON web interface, a loop of redirect happes when the password is set. After inspecting the values which could cause the issue, it was found that the password is the cause. In one page, the password was set. While when redirecting to the other page the password is not set. The cause of this bug is that the framework tries to auto-register jobs before the password is set.

Suggested Solution

One of the solutions is to make the framework register jobs after the password is set.

[Improvment] No Need to Return Namespace for Auto-Register Method

Problem

In the method WebFioriApp::autoregister(), it is noticed that the namespace of the class must be returned in order to be registered. The return statement can be removed if application is well structured.

Solution

To auto-register classes without returning the namespace, we have to construct the namespace of the class using two arguments which we already have. The first one is the name of the application folder which is represented by the constant APP_DIR_NAME and the other argument which is the name of the folder that holds the classes that will be auto-registered.

[Feature Request] Add Support for Redirect in Routing

Problem

Suppose that I have a route which has the URI https://example.com/view-user/{user-id}. After a while, system owners decided to change the structure of the URI to be https://example.com/users/user-profile/{user-id}. In this case, the old URI should redirect to the new URI. Currently, this can be achieved by converting the first route to a closure route and defining the redirect in the closure as follows:

Router::closure([
    'path' => 'view-user/{user-id}',
    'route-to' => function() {
        $id = Router::getVarValue('user-id');
        Response::addHeader('location', 'users/user-profile/'.$id);
        Response::send();
    }
]);

Better Solution

What if the class Router has a method that can be used to create a redirect route in one single line? The signature of the method can be as follows:

Router::redirect($oldRoute, $newRoute, $redirectCode = 301);

A usage for the method can be as follows:

Router::redirect('view-user/{user-id}', 'users/user-profile/{user-id}', 301);

[Enhancement] Improve the Class Email Message

This issue contains some suggestions which will improve the class EmailMessage and make it more consistent with how the DOM is handled by the class WebPage since the two uses the same classes to create the final HTML document.

  • Rename the method EmailMessage::insertNode() to EmailMessage::insert() and make it works the same way as the method 1WebPage::insert()`.
  • Rename the method EmailMessage::document() to EmailMessage::getDocument().
  • Add new method: EmailMessage::getChildByID() which should work the same way as the method WebPage::getChildByID

Support For Intractive Mode in CLI

Currently, CLI of the framework can run one command at a time. One great feature would be the ability to run the framework in interactive mode. For example, we can pass a parameter like -i to enable interactive mode.

Move UI Related Class to a Sub-Folder in Another Namespace

It seems that the framework has its own UI components which are drived from the library phpStructs. The classes are currently placed in the folder '/entity' under the namespace '\webfiori\entity'.

Most probably, there will be more UI related things in the future. I suggest that every component that is related to UI is placed in a folder called 'ui' which should be in the root or inside the '/entity' folder. I also suggest that all UI classes to be added to the namespace '\webfiori\ui'.

[Bug] CRON Web Interface Gives 404

Problem

After defining the constant CRON_THROUGH_HTTP and trying to access web interface of jobs management, it gives a 404 - not found error. If a job is scheduled, everything will work without any issues.

[Bug] Execution of The Command 'create' Halt When Creating a Table

Problem

When trying to create a table class which references another table and the other table was not found, an exception is thrown. The exception has following information:

Uncaught Exception
Exception Message: Class 'database\common\UsersTable' not found
Exception Class: Error
Exception Code: 0
File: vendor/webfiori/framework/src/framework/cli/CreateTableObj.php
Line: 105

The cause of the error is most probably caused by missing use Error; statement at the top of the class CreateTableObj.

Adding A Constant Value to Represents Start Time of The framework

This constant can be used as a benchmark for how much time it takes to process a request. For sure it can be used to do more.

A suggested name for the constant is MICRO_START. The value of the constant should be taken from the method microtime(true). The definition of the constant should be somewhere in the class WebFiori.php.

[Bug] Execution of Command 'Create' Stops Because of an Error

Problem

When creating new database table and trying to reference a table class which does not exist, the execution of the command will stops with exception message Class 'app\db\SomeClass' not found. This will result in loosing any data which was provided for the command and it is annoying as it will result in making the developer enter all new table information again.

Suggested Solution

Instead of making the command stops, a message that says the table class was not found should appear and ask the user to type in another class.

[Bug] Permission Denied When Creating Autolader Cache or Sessions

Problem

For unkown reason, when the framework is loaded using composer, the permissions of the folder app/storage is changed to "read only" mode. This causes the application to fail during initialization with error message PHP Warning: fopen(app/storage/autoload.cache) failed to open stream: Permission denied in vendor/webfiori/framework/src/framework/AutoLoader.php on line 622. This also applies to sessions which are stored as files.

Temporary Solution

A temporary solution to the problem is to rename the storage folder to any other name and manually create new folder with the name storage.

[Bug] Force Execute Output Won't Show

Problem

When forcing a job to execute, the output window will stay empty and the job will seems as if it is still executing. This happen when defining the global constant JSON_PROP_STYLE and setting is value to something other than kebab.
image

[Bug] A PHP Warning is Shown By The Autoloader

Problem

A PHP warning that says PHP Warning: Invalid argument supplied for foreach() in /cygdrive/c/Server/apache2/htdocs/resortana3/vendor/webfiori/framework/src/framework/AutoLoader.php on line 460 is shown by the autoloader when it fails to scan a directory.

Solution

Add a check condition to the body of the method _addSrachDirectoryHelper2 to check for the return value of the method scandir()

[Feature Request] Support for Grouping Routes

Problem

Suppose that I have 3 pages with following links:

  • https://example.com/users
  • https://example.com/users/view-user/{user-id}
  • https://example.com/users/add-user

The 3 pages share all properties including middleware and request methods and so on. To create routes for the 3, I must call the method which is used to add routes 3 times as follows:

Router::view([
    'path' => '/users', 
    'route-to' => ListUsersPage::class,
    'case-sensitive' => false,
    'middleware' => [
        'sample-middleware','sample-middleware-2'
    ],
    'methods' => 'get'
]);
Router::view([
    'path' => '/users/view-user/{user-id}', 
    'route-to' => ViewUserPage::class,
    'case-sensitive' => false,
    'middleware' => [
        'sample-middleware','sample-middleware-2'
    ],
    'methods' => 'get'
]);
Router::view([
    'path' => '/users/add-user', 
    'route-to' => AddUserPage::class,
    'case-sensitive' => false,
    'middleware' => [
        'sample-middleware','sample-middleware-2'
    ],
    'methods' => 'get'
]);

As you can see, there are many lines which are repeated more than once. We have a code smell here. What if we can make this more compact?

Suggested Solution

Add new method to the class Router which could be used to group routes based on the path part of the URI. Once grouped, all routes in the specified path will share same group properties. For example, the code above could be refactored to be something similar to the following:

Router::group([
    'path' => '/users', 
    'case-sensitive' => false,
    'middleware' => [
        'sample-middleware','sample-middleware-2'
    ],
    'methods' => 'get',
    'routes' => [
        [
            'path' => '/', 
            'route-to' => ListUsersPage::class,
        ],
        [
            'path' => '/view-user/{user-id}', 
            'route-to' => ViewUserPage::class,
        ]
        [
            'path' => '/add-user', 
            'route-to' => AddUserPage::class,
        ]
    ]
]);

[Bug] A Warning Caused By Autolader When Cache File Does Not Exist

Proplem

When the file app/storage/autoloade.cache does not exist or the autoloader was unable to create the file, it generates the following warning: PHP Warning: fclose() expects parameter 1 to be resource, bool given in /cygdrive/c/Server/apache2/htdocs/YCRM/vendor/webfiori/framework/src/framework/AutoLoader.php on line 623.

Solution

There should be a check for the return type of the method fopen() before trying to close the resource.

[Enhancement] Improve How System Configuration is Stored

Current Situation

Currently, the framework uses 3 classes to keep system configuration settings such as database connections and application name in addition to SMTP connections. This approach is good because it places different configurations in different places. One problem with this configuration is that it mixes the configuration of the framework with the configuration of the app. Also, this approach makes the developer do modifications to files which should not be changed manually.

Suggested Way

I suggest that all application related configuration to be added to one class in the folder app. The class name can be AppConfig for example. the class should hold all application related settings including:

  • SMTP Connections
  • Database connections
  • Application name, release date and version.
  • Other settings such as default language and theme.

Improvments to The Class Autoloader

Autoload Speed

By observing the code which is used to auto load classes, I can see that it creates a set of directories at which the search algorithm will be applied to. in the body of the method loadClass(), there exist a loop which go through all the directories and check for .php file existence. In my opinion, this process can be improved by creating a hash-map for all PHP classes which exist in a directory if it is included in the autoloader search paths.

Autoload of composer packager

It would be huge improvement if the auto loader can load the classes which exist in the vendor folder of composer.

[Feature Request] Allow The Developer to Change the Location of Application Folder

Problem

Currently, the developer have only the option to add his sources to the folder app. This means that the developer must add all his classes to the namespace app in order to not violate PSR-4.

Proposed Solution

One way to allow the developer to change the application folder name is to have a global constant which can be used to point to application root folder. The constant can be defined as part of the class GlobalConstants.

[Enhancement] Move CRON Web Interface Credentials Information to Class 'AppConfig'

Problem

Currently, the password which is used to login to CRON Web Interface must be hashed first and then set using the method Cron::password() manually. For normal people, this can be annoying task as it must be performed manually.

Suggested Solution

Since the password can be configured, why not to store it in the class AppConfig to make it part of the application configuration variables? If we do that, then it is possible later on to set the password using CLI commands.

[Enhancement] Add The Ability to Create Themes Using the Command 'create'

Problem

One of the good features of the framework is the ability to create system entities using the command create. Themes are considered one of the system entities. It would be greate to have your theme created using command line.

Suggested Workflow

The following steps is a suggestion on how the command will work.

  • Ask for theme class information (name, namespace, the path at which the class will be created at).
  • Ask for theme name.
  • Ask for theme description.
  • Ask for theme author name.
  • Ask for theme author url.
  • Ask for license name.
  • Ask for license url.

After the command finishes execution, it should create 5 classes in theme folder as follows:

  • The main theme class that extends the class Theme.
  • A class which has the name HeadSection that holds the tags which will be exist in the tag <head>.
  • A class which has the name HeaderSection that represents header section of the theme.
  • A class which has the name FooterSection that represents footer section of the theme.
  • A class which has the name AsideSection that represents aside section of the theme.

[Enhancement] Add a Way for The Application to Re-Create Initialization Classes

Problem

If the folder app/ini was deleted, the initialization classes will also be deleted and will have to add them manually. What if there is a way for the application to generate deleted classes again?

Proposed Solution

Similar to the class AppConfig, There should be a way to re-create the classes as they are important part of the application. The logic for creating the classes again can be added to the class ConfigController.

[Feature Request] Add Support for Auto-Service Registration

Problem

One of the common things that usually is performed is to add services manager in addition to the services it manages in one folder. For example, they could be added to the folder apis/public/user. The services will belong to the namespace apis\public\user. Currently, each service must be registered using the method WebServicesManager::addService() in the constructor of the services manager.

Suggested Solution

One solution is to have new method called WebServicesManager::registerServices(). This method should work as follows, it scans the directory at which the manager exist on and locate any PHP class which is prefixed with the word Service and add it to the manager.

[Bug] An Error Which Can Be Seen After Installing the framework and Running CLI

Problem

This bug happens only once. After installing the framework using the command php composer create-project --prefer-dist webfiori/app and running CLI of the framework, an error which says PHP Warning: mkdir(): File exists in C:\Server\apache2\htdocs\cli\test4\vendor\webfiori\framework\webfiori\framework\AutoLoader.php on line 619.

When running CLI again, the error disappears.

[Feature Request] Updating Home Page Using The Command `update-settings`

Problem

It is noticed that the link to home page in the class AppConfig depends on the constant CLI_HTTP_HOST. For this reason, it is noticed that the host part is appended to home page link. Instead of including the whole link, it would be better to have only the path part in the URL. This will help in making the application more portable.

Coding Standards Enforcement

Use something like https://github.com/FriendsOfPHP/PHP-CS-Fixer

php .\php-cs-fixer fix --config=.php_cs.dist
<?php
$finder = PhpCsFixer\Finder::create()
    ->exclude('php-cs-fixer') // if php-cs-fixer is downloaded manually
    ->in(__DIR__)
    ->append([__DIR__.'/php-cs-fixer']);

$config = PhpCsFixer\Config::create()
    ->setRules([
        'single_line_after_imports' => true,
        'global_namespace_import' => true,
        'no_unused_imports' => true,
        'single_import_per_statement' => true,
        'ordered_imports' => true,
        'phpdoc_var_annotation_correct_order' => true,
        'single_blank_line_at_eof' => true,
        'blank_line_after_namespace' => true,
        'line_ending' => true,
        'phpdoc_trim_consecutive_blank_line_separation' => true,
        'single_blank_line_before_namespace' => true,

    ])
    ->setFinder($finder);

return $config;

[Enhancement] Improve The Pages of CRON Web Interface

Problem

The current look and feel of CRON web interface pages looks like as if it was created back in the day when internet was started. Also, it had some issues which are related to UX.

Suggested Solution

Update the whole pages which are related to managing CRON jobs throgh HTTP to use a better material-design library called Vuetify. The pages include the following:

  • CronView
  • CronLoginView
  • CronTasksView
  • CronTaskView

Add a Way to Check If CRON Job is Forced to Execute

One of the features of the framework is to force a scheduled tasks to run using HTTP protocol. Suppose that if the task is forced to run, I need to perform something else if the task is forced to execute like logging some info or store the IP address at which the force execute was initiated from.

Currently, there is no way to tell if a job is forced except if execution log is enabled. The log isn't good enough. It would be great if there is a method which can be used to tell if the scheduler is being forced to execute.

Move Inline JavaScript Code in CRON Pages to External JavaScript Files

When source code of CRON related views (or pages) is viewed, a lot of JavaScript code is seen there which makes the code looks not good. For example, you can check here.

I would suggest that JavaScript code to be moved outside in an actual JS file to make it easier for maintenance and readability. I suggest that there should be a folder with the name res in the root that can have the files.

If anyone has a better suggestion, that would be great.

[Refactoring] Rename the Method Router::view() to Router::page()

The name of the method does not reflect the actual thing that the method will do.

The method is currently used to route to pages, not views.

The definition of a view is that it is a section of the page (single component). For example, a page might have more than one view. One to show user information and another one to show a list of actions that can be performed on the user.

While the defition of a page is that it is a collection of views when grouped will render into a full web page.

Logout Issue

When the user is logged out, the language is reset to English.

[Enhancement] Make Default File Creation be Same as Choosen Namespace

Problem

Currently, when creating any system entity using the command webfiori create, the default creation place does not corresponds to chosen namespace. For example, when creating a database table and choosing the namespace coolApp\db, it will show the folder app\database as default creation place. Why not to make the default folder be coolApp\db? This will allow the application to follow PSR-4 by default without having to type the name of the folder.

Collecting CRON Output or Errors

Suppose that I implemented a CRON job to fail if certain conditions where met and the job has returned false. What if the job may fail for multiple reasons and I would like to know why did it fail? Currently, it is possible to tell what is the cause of the fail.

What we need is a way to log the things which can happen while executing the job and show the exact cause in case of forcing job execution or even in normal execution flow.

[Bug] Multiple Foreign Keys to Same Table Result in Error

Problem

Suppose that I have a table class with name UserInfoTable. Also, suppose that I would like to create a table with name UserTasksTable. Assume that the table will have two Foreign Keys which references the table UserInfoTable. When using the command create to create the new table, the command will create the new table with two use statements for the class UserInfoTable. This will result in a error message which looks like the following when running the application: Cannot use app\database\UserInfoTable as UserInfoTable because the name is already in use.

Solution

The use statement should be included only once even if the class is referenced twice.

[Feature Request] Add Support for Routing to Class Methods

Problem

When creating a route to a class or a PHP file, the whole logic must exist in the constructor of the class. To make the class or PHP file acts as an actual controller, it would be good idea to have the option to route to specific method in the class or file. This would help in making the framework more MVC-Like

Suggested Solution

One possible solution is to add support for one more option in the method Router::addRoute(). The name of the option can be action. The value of the index can be the name of the class method that will be called.

Router::addRoute([
    'path' => 'say-hi',
    'route-to' => HiClass::class,
    'action' => 'sayHi'
]);

In the given sample code, we assume that the class HiClass has a public method which has the name sayHi.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.