Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c4af2aa
ci: Updated Workflows
usernane Jan 15, 2026
9f9aff6
ci: Update PHPUnit Version for PHP 8.5
usernane Jan 15, 2026
778128f
ci: Added Concurrency Control
usernane Jan 15, 2026
41c42ca
docs(readme): Updated PHP Version
usernane Jan 15, 2026
29a9e00
chore: Remove Funding Info
usernane Jan 15, 2026
868e123
fix: Request Method not Allowed
usernane Jan 19, 2026
c67616e
refactor: Migrations Creation Process
usernane Jan 19, 2026
237dd96
refactor: Migrations System Refactor
usernane Jan 19, 2026
3b1c77e
Create AttributeTableWriter.php
usernane Jan 20, 2026
92b86f6
Create DomainEntityWriter.php
usernane Jan 20, 2026
3754c03
Create RepositoryWriter.php
usernane Jan 20, 2026
5067f41
Create RestServiceWriter.php
usernane Jan 20, 2026
8faefd7
Create CreateDomainEntity.php
usernane Jan 20, 2026
6f4a7fc
feat: Create Attributes Table
usernane Jan 20, 2026
71d34ec
Create CreateRestService.php
usernane Jan 20, 2026
2a88eb7
Update RepositoryWriter.php
usernane Jan 20, 2026
980209f
Create CreateRepository.php
usernane Jan 20, 2026
74b6959
Update CreateCommand.php
usernane Jan 20, 2026
d142174
Create CreateDomainEntityTest.php
usernane Jan 20, 2026
f00a100
Create CreateRepositoryTest.php
usernane Jan 20, 2026
eee51ca
refactor: How to Locate `ClassLoader`
usernane Jan 20, 2026
d505785
Update .gitignore
usernane Jan 20, 2026
153732c
refactor: Use of Lines Instead of String Concat
usernane Jan 20, 2026
18da8fa
refactor: Added Code Normalization
usernane Jan 20, 2026
4d486b2
feat: Add New Method" `method`
usernane Jan 20, 2026
bebe151
feat: Add `property` and `constant`
usernane Jan 20, 2026
0eb7760
feat: Doc-block Builder
usernane Jan 20, 2026
ff37c27
feat: Added `getCode`
usernane Jan 20, 2026
9e11d2b
feat: Attributes
usernane Jan 20, 2026
57656d7
refactor: Throw Exceptions on Errors
usernane Jan 20, 2026
f54ed91
feat: Code Reuse Helpers
usernane Jan 20, 2026
d3b2407
feat: Chaining
usernane Jan 20, 2026
9c06b94
chore: Merge pull request #277 from WebFiori/refactor-create
usernane Jan 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/FUNDING.yml

This file was deleted.

9 changes: 7 additions & 2 deletions .github/workflows/php81.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
name: Build PHP 8.1
name: PHP 8.1

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -104,7 +109,7 @@ jobs:
code-coverage:
name: Coverage
needs: test
uses: WebFiori/workflows/.github/workflows/coverage-codecov.yaml@main
uses: WebFiori/workflows/.github/workflows/coverage-codecov.yaml@v1.2.1
with:
php-version: '8.1'
coverage-file: 'php-8.1-coverage.xml'
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/php82.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
name: Build PHP 8.2
name: PHP 8.2

on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -105,7 +109,7 @@ jobs:
code-coverage:
name: Coverage
needs: test
uses: WebFiori/workflows/.github/workflows/coverage-codecov.yaml@main
uses: WebFiori/workflows/.github/workflows/coverage-codecov.yaml@v1.2.1
with:
php-version: '8.2'
coverage-file: 'php-8.2-coverage.xml'
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/php83.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
name: Build PHP 8.3
name: PHP 8.3

on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main, dev ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -105,7 +109,7 @@ jobs:
code-coverage:
name: Coverage
needs: test
uses: WebFiori/workflows/.github/workflows/coverage-codecov.yaml@main
uses: WebFiori/workflows/.github/workflows/coverage-codecov.yaml@v1.2.1
with:
php-version: '8.3'
coverage-file: 'php-8.3-coverage.xml'
Expand Down
20 changes: 5 additions & 15 deletions .github/workflows/php84.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
pull_request:
branches: [ main ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -106,23 +110,9 @@ jobs:
code-coverage:
name: Coverage
needs: test
uses: WebFiori/workflows/.github/workflows/coverage-codecov.yaml@main
uses: WebFiori/workflows/.github/workflows/coverage-codecov.yaml@v1.2.1
with:
php-version: '8.4'
coverage-file: 'php-8.4-coverage.xml'
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

code-quality:
name: Code Quality
needs: test
uses: WebFiori/workflows/.github/workflows/quality-sonarcloud.yaml@main
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

release-prod:
name: Prepare Production Release Branch / Publish Release
needs: [code-coverage, code-quality]
uses: WebFiori/workflows/.github/workflows/release-php.yaml@main
with:
branch: 'main'
132 changes: 132 additions & 0 deletions .github/workflows/php85.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
name: PHP 8.5

on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10

env:
SA_SQL_SERVER_PASSWORD: ${{ secrets.SA_SQL_SERVER_PASSWORD }}
MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }}

services:
sqlserver:
image: mcr.microsoft.com/mssql/server:2019-latest
env:
SA_PASSWORD: ${{ secrets.SA_SQL_SERVER_PASSWORD }}
ACCEPT_EULA: Y
MSSQL_PID: Express
ports:
- "1433:1433"
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }}
MYSQL_DATABASE: testing_db
MYSQL_ROOT_HOST: '%'
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
fail-fast: true

name: Run PHPUnit Tests

steps:
- name: Clone Repo
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.5
extensions: mysqli, mbstring, sqlsrv
tools: phpunit:12.5.4, composer

- name: Install ODBC Driver for SQL Server
run: |
curl https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc
curl https://packages.microsoft.com/config/ubuntu/22.04/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list
sudo apt update
sudo ACCEPT_EULA=Y apt install mssql-tools18 unixodbc-dev msodbcsql18

- name: Wait for SQL Server
run: |
for i in {1..12}; do
if /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -P '${{ secrets.SA_SQL_SERVER_PASSWORD }}' -Q 'SELECT 1' -C > /dev/null 2>&1; then
echo "SQL Server is ready"
break
fi
echo "Waiting for SQL Server... ($i/12)"
sleep 10
done

- name: Create SQL Server Database
run: /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -P '${{ secrets.SA_SQL_SERVER_PASSWORD }}' -Q 'create database testing_db' -C

- name: Setup MySQL Client
run: |
sudo apt update
sudo apt install mysql-client-core-8.0

- name: Wait for MySQL
run: |
until mysqladmin ping -h 127.0.0.1 --silent; do
echo 'waiting for mysql...'
sleep 1
done

- name: Create MySQL Database
run: |
mysql -h 127.0.0.1 -u root -p${{ secrets.MYSQL_ROOT_PASSWORD }} -e "CREATE DATABASE IF NOT EXISTS testing_db;"

- name: Install Dependencies
run: composer install --prefer-source --no-interaction

- name: Execute Tests
run: phpunit --configuration=tests/phpunit10.xml --coverage-clover=clover.xml

- name: Rename coverage report
run: |
mv clover.xml php-8.5-coverage.xml

- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: code-coverage
path: php-8.5-coverage.xml


code-coverage:
name: Coverage
needs: test
uses: WebFiori/workflows/.github/workflows/coverage-codecov.yaml@v1.2.1
with:
php-version: '8.5'
coverage-file: 'php-8.5-coverage.xml'
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

code-quality:
name: Code Quality
needs: test
uses: WebFiori/workflows/.github/workflows/quality-sonarcloud.yaml@v1.2.1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

release-prod:
name: Prepare Production Release Branch / Publish Release
needs: [code-coverage, code-quality]
uses: WebFiori/workflows/.github/workflows/release-php.yaml@v1.2.1
with:
branch: 'main'
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ App/Config/*
*.Identifier
tests/clover.xml
/.vscode
/App
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</p>

<p align="center">
<a href="https://github.com/WebFiori/framework/actions"><img src="https://github.com/WebFiori/framework/actions/workflows/php84.yml/badge.svg?branch=main"></a>
<a href="https://github.com/WebFiori/framework/actions"><img src="https://github.com/WebFiori/framework/actions/workflows/php85.yml/badge.svg?branch=main"></a>
<a href="https://codecov.io/gh/WebFiori/framework">
<img src="https://codecov.io/gh/WebFiori/framework/branch/main/graph/badge.svg" />
</a>
Expand Down Expand Up @@ -34,7 +34,7 @@ WebFiori Framework is a mini web development framework which is built using PHP
|<a target="_blank" href="https://github.com/WebFiori/framework/actions/workflows/php82.yml"><img src="https://github.com/WebFiori/framework/actions/workflows/php82.yml/badge.svg?branch=main"></a>|
|<a target="_blank" href="https://github.com/WebFiori/framework/actions/workflows/php83.yml"><img src="https://github.com/WebFiori/framework/actions/workflows/php83.yml/badge.svg?branch=main"></a>|
|<a target="_blank" href="https://github.com/WebFiori/framework/actions/workflows/php84.yml"><img src="https://github.com/WebFiori/framework/actions/workflows/php84.yml/badge.svg?branch=main"></a><br>|

|<a target="_blank" href="https://github.com/WebFiori/framework/actions/workflows/php85.yml"><img src="https://github.com/WebFiori/framework/actions/workflows/php85.yml/badge.svg?branch=main"></a><br>|

## Key Features

Expand Down
35 changes: 20 additions & 15 deletions WebFiori/Framework/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -384,11 +384,14 @@ public static function initiate(string $appFolder = 'App', string $publicFolder
*/
define('PUBLIC_FOLDER', $publicFolder);
}
if (!defined('WF_CORE_PATH')) {
if (!defined('WF_CORE_PATHS')) {
/**
* Path to WebFiori's core library.
* Possible Paths to WebFiori's core library.
*/
define('WF_CORE_PATH', ROOT_PATH.DS.'vendor'.DS.'webfiori'.DS.'framework'.DS.'WebFiori'.DS.'Framework');
define('WF_CORE_PATHS', [
ROOT_PATH.DS.'vendor'.DS.'webfiori'.DS.'framework'.DS.'WebFiori'.DS.'Framework',
ROOT_PATH.DS.'WebFiori'.DS.'Framework'
]);
}
self::initAutoLoader();
self::checkStandardLibs();
Expand Down Expand Up @@ -649,20 +652,22 @@ private static function initAutoLoader() {
* Initialize autoloader.
*/
if (!class_exists('WebFiori\Framework\Autoload\ClassLoader',false)) {
$autoloader = WF_CORE_PATH.DIRECTORY_SEPARATOR.'Autoload'.DIRECTORY_SEPARATOR.'ClassLoader.php';

if (!file_exists($autoloader)) {
throw new \Exception('Unable to locate the autoloader class.');
}
require_once $autoloader;
}
self::$AU = ClassLoader::get();
foreach (WF_CORE_PATHS as $path) {
$autoloader = $path.DIRECTORY_SEPARATOR.'Autoload'.DIRECTORY_SEPARATOR.'ClassLoader.php';

if (!class_exists(APP_DIR.'\\Init\\InitAutoLoad')) {
Ini::createAppDirs();
Ini::get()->createIniClass('InitAutoLoad', 'Add user-defined directories to the set of directories at which the framework will search for classes.');
if (file_exists($autoloader)) {
require_once $autoloader;
self::$AU = ClassLoader::get();
}
if (!class_exists(APP_DIR.'\\Init\\InitAutoLoad')) {
Ini::createAppDirs();
Ini::get()->createIniClass('InitAutoLoad', 'Add user-defined directories to the set of directories at which the framework will search for classes.');
}
self::call(APP_DIR.'\\Init\\InitAutoLoad::init');
return;
}
}
self::call(APP_DIR.'\\Init\\InitAutoLoad::init');
throw new \Exception('Unable to locate the autoloader class.');
}
/**
* Initialize global constants which has information about framework version.
Expand Down
25 changes: 25 additions & 0 deletions WebFiori/Framework/Cli/Commands/CreateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@
use WebFiori\Framework\Cli\CLIUtils;
use WebFiori\Framework\Cli\Helpers\ClassInfoReader;
use WebFiori\Framework\Cli\Helpers\CreateAPITestCase;
use WebFiori\Framework\Cli\Helpers\CreateAttributeTable;
use WebFiori\Framework\Cli\Helpers\CreateBackgroundTask;
use WebFiori\Framework\Cli\Helpers\CreateCLIClassHelper;
use WebFiori\Framework\Cli\Helpers\CreateCleanArchStack;
use WebFiori\Framework\Cli\Helpers\CreateDBAccessHelper;
use WebFiori\Framework\Cli\Helpers\CreateDomainEntity;
use WebFiori\Framework\Cli\Helpers\CreateFullRESTHelper;
use WebFiori\Framework\Cli\Helpers\CreateMiddleware;
use WebFiori\Framework\Cli\Helpers\CreateMigration;
use WebFiori\Framework\Cli\Helpers\CreateRepository;
use WebFiori\Framework\Cli\Helpers\CreateRestService;
use WebFiori\Framework\Cli\Helpers\CreateTableObj;
use WebFiori\Framework\Cli\Helpers\CreateThemeHelper;
use WebFiori\Framework\Cli\Helpers\CreateWebService;
Expand Down Expand Up @@ -82,11 +87,20 @@ public function exec() : int {
} else if ($answer == 'Database table class.') {
$create = new CreateTableObj($this);
$create->readClassInfo();
} else if ($answer == 'Attribute-based table schema (Clean Architecture).') {
$create = new CreateAttributeTable($this);
$create->writeClass();
} else if ($answer == 'Entity class from table.') {
$this->createEntityFromQuery();
} else if ($answer == 'Pure domain entity (Clean Architecture).') {
$create = new CreateDomainEntity($this);
$create->writeClass();
} else if ($answer == 'Web service.') {
$create = new CreateWebService($this);
$create->readClassInfo();
} else if ($answer == 'Annotation-based REST service (Clean Architecture).') {
$create = new CreateRestService($this);
$create->writeClass();
} else if ($answer == 'Middleware.') {
$create = new CreateMiddleware($this);
$create->readClassInfo();
Expand All @@ -108,6 +122,12 @@ public function exec() : int {
$create->readEntityInfo();
$create->confirnIncludeColsUpdate();
$create->writeClass();
} else if ($answer == 'Repository class (Clean Architecture).') {
$create = new CreateRepository($this);
$create->writeClass();
} else if ($answer == 'Complete clean architecture stack (Entity + Table + Repository).') {
$create = new CreateCleanArchStack($this);
return $create->writeClasses();
} else if ($answer == 'Complete REST backend (Database table, entity, database access and web services).') {
$create = new CreateFullRESTHelper($this);
$create->readInfo();
Expand All @@ -127,13 +147,18 @@ public function exec() : int {
private function getWhat() {
$options = [];
$options['table'] = 'Database table class.';
$options['table-attributes'] = 'Attribute-based table schema (Clean Architecture).';
$options['entity'] = 'Entity class from table.';
$options['domain-entity'] = 'Pure domain entity (Clean Architecture).';
$options['web-service'] = 'Web service.';
$options['rest-service'] = 'Annotation-based REST service (Clean Architecture).';
$options['task'] = 'Background Task.';
$options['middleware'] = 'Middleware.';
$options['command'] = 'CLI Command.';
$options['theme'] = 'Theme.';
$options['db'] = 'Database access class based on table.';
$options['repository'] = 'Repository class (Clean Architecture).';
$options['clean-stack'] = 'Complete clean architecture stack (Entity + Table + Repository).';
$options['rest'] = 'Complete REST backend (Database table, entity, database access and web services).';
$options['api-test'] = 'Web service test case.';
$options['migration'] = 'Database migration.';
Expand Down
Loading
Loading