bbn / bbn
PHP opinionated framework
Installs: 2 627
Dependents: 49
Suggesters: 0
Security: 0
Stars: 3
Watchers: 3
Forks: 7
Open Issues: 0
pkg:composer/bbn/bbn
Requires
- php: >=8.0
- ext-json: *
- ext-mbstring: *
- brick/phonenumber: 0.3.*
- composer/composer: 2.3.5
- czproject/git-php: 3.18.*
- dusterio/link-preview: 1.2.*
- erusev/parsedown: 1.7.*
- ezyang/htmlpurifier: ^4.13
- firebase/php-jwt: 5.2.*
- gettext/gettext: 4.8.1
- greenlion/php-sql-parser: 4.5.*
- mck89/peast: 1.13.*
- mollie/oauth2-mollie-php: ^2.0
- mpdf/mpdf: 8.0.*
- natxet/cssmin: 3.0.*
- nesbot/carbon: 2.57.*
- nikic/php-parser: 4.15.*
- opis/closure: ^3.5
- pear/archive_tar: 1.4.*
- phpdocumentor/reflection-docblock: 5.2.*
- phpmailer/phpmailer: 6.8.*
- psr/simple-cache: 1.0.*
- sabre/dav: 4.1.*
- scssphp/scssphp: 1.6.*
- sepia/po-parser: 6.0.*
- sunra/php-simple-html-dom-parser: 1.5.*
- tedivm/jshrink: 1.4.*
- tijsverkoyen/css-to-inline-styles: 2.2.*
- tplaner/when: 3.0.*
- wapmorgan/unified-archive: 0.1.*
- xemlock/htmlpurifier-html5: dev-master
- zordius/lightncandy: 1.2.*
Requires (Dev)
- friendsofphp/php-cs-fixer: 3.3.*
- mockery/mockery: 1.4.*
- pdepend/pdepend: 2.10.*
- phpmd/phpmd: 2.10.*
- phpunit/phpunit: 10.1.1
- phpunitgen/core: 3.0.*
- squizlabs/php_codesniffer: 3.6.*
- dev-master
- v1.x-dev
- 1.0.48
- 1.0.47
- 1.0.46
- 1.0.45
- 1.0.44
- 1.0.43
- 1.0.42
- 1.0.41
- 1.0.40
- 1.0.39
- 1.0.38
- 1.0.37
- 1.0.36
- 1.0.35
- 1.0.34
- 1.0.33
- 1.0.32
- 1.0.31
- 1.0.30
- 1.0.29
- 1.0.28
- 1.0.27
- 1.0.26
- 1.0.25
- 1.0.24
- 1.0.23
- 1.0.22
- 1.0.21
- 1.0.20
- 1.0.19
- 1.0.18
- 1.0.17
- 1.0.16
- 1.0.15
- 1.0.14
- 1.0.13
- 1.0.12
- 1.0.11
- 1.0.10
- 1.0.9
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1.x-dev
- 1.0.1
- 1.0.0
- 0.9.1
- v0.9.0
- dev-identities
- dev-warren-dev
- dev-abandoned_carts_email
- dev-shop_sales_emailing
- dev-insert_client_in_cart
- dev-tasks_notes
- dev-thomas-dev-vue3
- dev-vcs-mirko3
- dev-vcs-mirko2
- dev-vcs-mirko
- dev-vcs-class
- dev-check_content_type_update_2
- dev-check_content_type_update
- dev-shop-transactionslist-mirko
- dev-sales-shipping-mirko
- dev-email-sales-mirko
- dev-added_published_to_getAll
- dev-transactions-mirko
- dev-task-mirko
- dev-gridcount-mirko
- dev-userpvtwidgets-mirko
- dev-user-phone-login-mirko
- dev-meeting-dev
- dev-cron-runner
- dev-meeting
- dev-mk-comment-db
This package is auto-updated.
Last update: 2025-10-23 09:58:46 UTC
README
bbn
The PHP library used by app-UI
π¦ Installation
You can install the library via Composer:
{ "require": { "bbn/bbn": "dev/master" } }
π Overview
bbn is a PHP library designed for Single Page Applications (SPA).
It provides a comprehensive set of tools, including:
- βοΈ MVC framework
- π§ Powerful ORM
- Supports database structure analysis
- Provides numerous data retrieval methods
- ποΈ Options class β the foundation for many app-UI features
- π API integrations for:
- Virtualmin, Cloudmin, GitHub, GitLab, payment gateways, and more
- π History class β track and revert database changes
- πΌοΈ File manipulation utilities for:
- Files, images, and PDFs
- π§ Filesystem explorer
- β±οΈ Automated task management system
- β‘ Universal caching system
- π§± HTML generation classes
- π₯ User and group management
- π§© Parsers for PHP, JavaScript, and VueJS components
π§° app-UI Specific Features
- Notes
- Media manager
- Chat
- Clipboard
- CMS
- Dashboard
- Database management and synchronization
- I.D.E.
- Automated mailings
- Internationalization (i18n)
- Masking system for text
- Notification system
- Data observers
- Password management
- Planning and event management
- Project and workflow management
- Statistics system
- Static helper methods for all kinds of data
...and many other features!
βοΈ Framework Architecture
The bbn framework works with a router and a few configuration files.
An installer will be released in the future.
π§βπ» There is still a lot of ongoing work regarding code review, translations, and documentation.
Contributions are welcome!
π Typical Directory Structure
app-ui/
βββ data/
βββ src/
β βββ cfg/
β β βββ environments.yml
β β βββ settings.yml
β β βββ custom2.php
β βββ cli/
β βββ components/
β βββ lib/
β βββ locale/
β βββ mvc/
β β βββ css/
β β βββ html/
β β βββ js/
β β βββ model/
β β βββ private/
β β βββ public/
β βββ plugins/
β βββ router.php
β
βββ public_html/
β βββ .htaccess
β βββ index.php
π Request Lifecycle
1οΈβ£ Redirection
-
Request:
βhttps://myapp.com/just/testing
(which does not exist) -
.htaccess
rewrites all missing files toindex.php
. -
index.php
changes directory tosrc/
(outside the public root). -
The router (in
src/
) is loaded β usually symlinked fromvendor
.
2οΈβ£ Routing
-
The framework identifies its environment from:
hostname
app_path
insrc/cfg/environment.yml
-
Constants are defined and autoload is initialized.
-
Classes are instantiated based on configuration.
-
The MVC class looks for the appropriate controller in:
src/mvc/public/just/testing/
Depending on the request type:
- Landing page (GET):
src/mvc/public/just/testing/index.php
- POST request:
src/mvc/public/just/testing.php
If not found, it moves up the hierarchy:
src/mvc/public/just/index.php src/mvc/public/index.php
or for POST:
src/mvc/public/just.php
If none found β 404.
3οΈβ£ Execution
- Optional
src/custom1.php
is included with$bbn->mvc
. - If not in CLI mode:
- A session is started.
- Optional
src/custom2.php
is included ($bbn
may havemvc
,user
,session
).
- The MVC includes the controller.
4οΈβ£ Output
- Output buffer becomes the
content
property of the response. - Optional
src/custom3.php
is included (with$bbn->obj
). - Depending on request type:
- Landing page (GET): returns
content
with HTML headers. - POST request: returns JSON-encoded
mvc->obj
.
- Landing page (GET): returns
- If
obj
contains a file or image, response headers are set accordingly.
π§ Response Format
When clicking a link (handled by bbn-js
and bbn-vue
), the framework returns a JSON object with the following properties:
Name | Description |
---|---|
content |
HTML string injected into a container |
title |
Page title (prepended to site title) |
css |
CSS string inserted as a <style> tag |
script |
JavaScript function or VueJS anonymous component |
data |
Data object accessible by JavaScript |
The frontend libraries
bbn-js
andbbn-vue
handle all I/O:
They intercept local links, send POST requests, and process the JSON responses.
β‘ Quick Start Example
Below is a minimal example showing how to set up and run a simple bbn application.
ποΈ Project Structure
my-app/
βββ composer.json
βββ src/
β βββ cfg/
β β βββ environments.yml
β β βββ settings.yml
β βββ mvc/
β β βββ public/
β β βββ hello/
β β βββ index.php
β βββ router.php
βββ public_html/
βββ .htaccess
βββ index.php
βοΈ Configuration
composer.json
{ "require": { "bbn/bbn": "dev/master" } }
src/cfg/environments.yml
environments: dev: host: localhost app_path: /path/to/my-app/src db: engine: mysql host: 127.0.0.1 user: root pass: root dbname: myapp
src/cfg/settings.yml
mode: dev timezone: UTC locale: en
π§© Router
src/router.php
<?php require __DIR__ . '/../vendor/autoload.php'; $router = new \bbn\Mvc\Router(); $router->run();
π Entry Point
public_html/.htaccess
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.php [L]
public_html/index.php
<?php chdir(__DIR__ . '/../src/'); require 'router.php';
π§± Controller
src/mvc/public/hello/index.php
<?php /** @var bbn\Mvc\Model $model */ return [ 'title' => 'Hello World', 'content' => '<h1>Welcome to bbn!</h1>' ];
βΆοΈ Running the App
- Install dependencies:
composer install
- Start a local PHP server:
php -S localhost:8080 -t public_html
- Visit http://localhost:8080/hello
You should see:
Hello World β Welcome to bbn!
π§© Next Steps
- Explore the MVC structure under
src/mvc/
- Connect your database and start using the ORM
- Integrate with
bbn-vue
orbbn-js
for dynamic SPA behavior
π€ Contributing
We welcome contributions of all kinds β code, documentation, tests, translations, or ideas.
Your help is greatly appreciated in making bbn better for everyone.
π§ How to Contribute
- Fork the repository
- Create a new branch for your feature or fix:
git checkout -b feature/my-new-feature
- Make your changes and ensure that everything is working
- Commit your changes with a meaningful message:
git commit -m "Add support for XYZ feature"
- Push your branch to your fork:
git push origin feature/my-new-feature
- Open a Pull Request to the
master
branch
π§Ή Code Guidelines
- Follow PSR-12 coding standards
- Use clear and consistent naming conventions
- Add type hints and PHPDoc comments where appropriate
- Keep functions small and focused
- Write unit tests for new features whenever possible
π§ͺ Testing
Run the test suite using:
composer test
Please ensure that all tests pass before submitting a pull request.
π Translations
Weβre progressively translating the framework and documentation.
If youβd like to contribute translations, you can:
- Add new language files under
src/locale/
- Improve existing translations
π§Ύ Documentation
Help us improve the documentation by:
- Fixing typos or outdated examples
- Expanding missing sections
- Adding code samples or tutorials
All documentation files are located in the /docs
folder (coming soon).
ποΈ Roadmap & Issues
Check out the Issues section for:
- Ongoing bug reports
- Feature requests
- Upcoming milestones
You can also start a new discussion or suggest improvements.
π‘ Need Help?
If you encounter problems or have questions:
- Open a GitHub Issue
- Or reach out via our community channels (coming soon)
A few examples
ORM
<?php use bbn\X; /** @var bbn\Db $db */ // Returns an array with fields, cols and keys props which will give you all information about a table X::adump($db->modelize("my_table")); // Simple query X::adump($db->getRows("SELECT * FROM my_table WHERE status = ?", $var)); // Same query X::adump($db->select( "my_table", // table [], // all columns ["status" => $var] // WHERE )); // More arguments X::adump($db->rselectAll( "my_table", // table ["field1", "field2"], // columns [["id", "<", 25], ["name", "LIKE", "tri%"]], // WHERE ["date" => DESC, "name"], // ORDER 50, // LIMIT 20 // START )); // The full way X::adump($db->rselectAll([ 'tables' => ["my_table_name", "my_table_name2"], 'fields' => ["field1", "field2"], // all columns 'where' => [ 'logic' => 'OR', 'conditions' => [ 'user' => 'admin', 'conditions' => [ 'logic' => 'AND', 'conditions' => [ // Mixed mode allowed in filters [ 'field' => 'my_date', 'operator' => '<', 'exp' => 'NOW()' ], ["id", "<", 25] 'name' => 'tri%' ], ] ] ], 'join' => [ [ 'table' => 'my_table3', 'on' => [ [ 'field' => 'my_table3.uid', 'exp' => 'my_table.uid_table3' // Operator is = by default ] ] ] ], 'order' => ["date" => DESC, "name"], // ORDER 'group_by' => ['my_table.id'], 'limit' => 50, 'start' => 20 ]));
MVC
use bbn\X; /** @var bbn\Mvc\Controller $ctrl */ // the/path/to/the/controller X::adump($ctrl->getPath()); // The corresponding (= same path) model X::adump($ctrl->getModel()); // Another model to which we send data X::adump($ctrl->getModel('another/model', ['some' => 'data'])); X::adump( // HTML view with same path (in html) $ctrl->getView(), // with data sent to js $ctrl->getView('another/view', 'js', ['my_data' => 'my_value']), // encapsulated in a script tag $ctrl->getJs('another/view', ['my_data' => 'my_value']), // compiles and returns the Less code from the same path (in css) $ctrl->getLess(), // The post data $ctrl->post, // The get data $ctrl->get, // The files array (revisited) $ctrl->files, // an array of each bit of the path which are not part of (=after) the controller $ctrl->arguments, // an associative array that will be sent to the model if nothiung else is sent $ctrl->data, // Adds properties to $ctrl->data $ctrl->addData(['my' => 'var']) // Moves the request to another controller $ctrl->reroute('another/route') // Includes another controller $ctrl->add('another/controller', ['some' => 'data']), // Includes a private controller (unaccessible through URL) $ctrl->add('another/controller', [], true), // timer will be a property of the $ctrl->inc property, also available in the subsequent models $ctrl->addInc('timer', new bbn\Util\Timer()) ); // The most useful functions: // Fetches for everything related to the current controller (model, html, js, css) and combines the results into a single object ($ctrl->obj). That's the typical function for showing a page $ctrl->combo("My page title"); // Transform all input (get, post, files) data into a single data array // Fetches the corresponding model with this data // and returns its result as an object. // Typically used for write operations. $ctrl->action(); // The second parameter allows the javascript to access the model's data $ctrl->combo("My page title", true); // Here the second parameter is the data sent to javascript $ctrl->combo("My page title", ['my' => 'data']); ?>
Accessing the data through javascript
If the anonymous function returns a function, the data will be its second argument
(() => { return (container, data) => { if (data && data.success && data.color) { container.style.color = '#' + data.color; } }; })();
If the anonymous function returns an object, the data will reside in the source property
(() => { return { computed: { realColor() { return '#' + this.source.color } } }; })();
The HTML views are server-rendered and therefore can by default access all the data
Example of an HTML view
<div style="color: #{{color}}">Hello world</div>
Example of a PHP view
<div style="color: #<?= $color ?>"><?= _("Hello world") ?></div>
Option
The option system is built in a database with a table having the following structure:
Name | Description |
---|---|
id |
is the primary key |
id_parent |
has a constraint to id . It is nullable but all options but one (the root ) should have it set |
text |
Is a string which should be the title of the option |
code |
is a varchar which forms a unique key associated with id_parent , so 2 same codes can't co-exist with a same parent, except if they are NULL |
num |
is the position of the option among its siblings, if the parent option is orderable |
id_alias |
has also a constraint on id but is never mandatory. It is a reference to another option |
value |
(JSON) is whatever properties the option will hold; when you get an option you won't see value but all the properties you will get which are not in the aforementioned columns come from value |
cfg |
(JSON) is the configuration of the option defines how the children, or the whole tree below, will be fetched and displayed. The properties can be: - show_code The code matters- relations The kind of relation the alias will embody if any- show_value The value contains stuff and thre is no schema- orderable If true the num will be used for the options' order- schema An array of object describing the different properties held in value- language A language set so the options can be translated- children Allows the option to have children- inheritance Sets if these rules apply to children, children + grand-children, or all lineage- permissions True if the options below should have a permission- default The default value among the children- scfg A similar configuration object to apply to grand-children |
The code
system allows us to find an option just by its codes path.
For example the sequence of codes permissions
, ide
, appui
targets:
- in the option which has code
appui
whose parent is theroot
- in the option which has code
ide
- the option which has code
permissions
The order is reversed to go from the most precise to the most general when in fact the sequence is:
root
β‘οΈ appui
β‘οΈ ide
β‘οΈ permissions
use bbn\X; /** @var bbn\Appui\Option $option */ // Returns the option ID from its code sequence X::adump($option->fromCode('permissions', 'ide', 'appui')); // The whole option with the same arguments (which work for all fetching functions) X::adump($option->option('permissions', 'ide', 'appui')); // It works also with the ID: $id_option = $option->fromCode('permissions', 'ide', 'appui'); X::adump($option->option($id_option)); // ID is a 32 hex value, so a code shouldn't look like one // If the last parameter is an ID, it will take this ID as the root X::adump($option->option('test', 'page', $id_option)); // Is the same as X::adump($option->option('test', 'page', 'permissions', 'ide', 'appui')); // Then you can fetch options (i.e. the children of an option) in many different ways X::adump( // Only the IDs, in the right order if orderable $option->items($id_option), // Only the IDs, text, and code if applicable $option->options($id_option), // All the option properties (but cfg) $option->fullOptions($id_option), // Same as options but with an items property holding the lineage $option->tree($id_option), // Same as fullOptions but with an items property holding the lineage $option->fullTree($id_option), // Returns the code: permissions $option->code($id_option), // Returns the text $option->text($id_option), // You can insert whaever you like $option->add(['id_parent' => $id_option, 'text' => 'Hello', 'myProp' => 'myValue']) );