Skip to content

Commit

Permalink
Updated assets to v1.0.0 and minor divers corrections [SLE-192]
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelgfeller committed May 15, 2024
1 parent 849dc8f commit 5ac7231
Show file tree
Hide file tree
Showing 56 changed files with 221 additions and 209 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
operating-system: [ ubuntu-latest ]
php-versions: [ '8.2' ]
test-database: [ 'slim_example_project_test' ]
sql-time-zone: [ 'Europe/Zurich' ]
name: PHP ${{ matrix.php-versions }} Test

services:
Expand Down Expand Up @@ -61,7 +62,7 @@ jobs:
run: mysql -uroot -proot -e "SHOW VARIABLES LIKE 'version%';"

- name: Set MySQL timezone to swiss time
run: mysql -uroot -proot -e "SET GLOBAL time_zone = '+01:00';"
run: mysql -uroot -proot -e "SET GLOBAL time_zone = '${{ matrix.sql-time-zone }}';"

- name: Create database
run: mysql -uroot -proot -e 'CREATE DATABASE IF NOT EXISTS ${{ matrix.test-database }} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'
Expand Down
94 changes: 48 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,32 @@
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)

Real-world example of a modern [Slim 4](https://www.slimframework.com/) web application with a scalable
structure and a variety of components and features to get started quickly.

This project showcases the implementation of a simple yet robust
[architecture](https://github.com/samuelgfeller/slim-example-project/wiki/Architecture)
with a variety of backend and
frontend features built using the Slim 4 micro-framework.
The base for this project was the official
[Slim-Skeleton](https://github.com/slimphp/Slim-Skeleton) and Odan's [slim4-skeleton](https://github.com/odan/slim4-skeleton).
structure and a variety of components and features.

Current best practices and programming principles are applied throughout the project and
adhering to the Single Responsibility Principle
([SRP](https://github.com/samuelgfeller/slim-example-project/wiki/Single-Responsibility-Principle-(SRP)))
is a key focus.
External library dependencies are [kept to a minimum](https://github.com/samuelgfeller/slim-example-project/wiki/Libraries-and-Framework)
to facilitate maintenance and ensure long-term viability.

Current best practices and modern principles are applied throughout the project.
Extra care was taken to follow the
Single Responsibility Principle ([SRP](https://github.com/samuelgfeller/slim-example-project/wiki/Single-Responsibility-Principle-(SRP))).
The [architecture](https://github.com/samuelgfeller/slim-example-project/wiki/Architecture)
is inspired by the Domain Driven Design ([DDD](https://en.wikipedia.org/wiki/Domain-driven_design))
and the [Vertical Slice Architecture](https://www.youtube.com/watch?v=L2Wnq0ChAIA).

A detailed [**documentation**](https://github.com/samuelgfeller/slim-example-project/wiki) explains the project structure, components, design choices and features.
The base for this project was the official
[Slim-Skeleton](https://github.com/slimphp/Slim-Skeleton) and the [slim4-skeleton](https://github.com/odan/slim4-skeleton).

Please read the [**installation guide**](https://github.com/samuelgfeller/slim-example-project/wiki/Installation-Guide)
to get started.
A detailed [**documentation**](https://github.com/samuelgfeller/slim-example-project/wiki) explains how the project is built,
components, design choices and features.

Stripped down versions of this repository are available as skeleton
templates.
With frontend [slim-starter](https://github.com/samuelgfeller/slim-starter) or just for an API:
[slim-api-starter](https://github.com/samuelgfeller/slim-api-starter).
With frontend [**slim-starter**](https://github.com/samuelgfeller/slim-starter) or just for an API:
[**slim-api-starter**](https://github.com/samuelgfeller/slim-api-starter).

Please read the [**installation guide**](https://github.com/samuelgfeller/slim-example-project/wiki/Installation-Guide)
to get started.

## Features
All the features were developed with an effort to ensure maximum user-friendliness.
Expand All @@ -41,33 +42,32 @@ The backend, efficient and secure.
This project is currently designed for non-profit organizations or foundations that require a platform
to manage and maintain a record of communication through notes of people they help.

**Project components:**
**Technologies:**

* [Dependency Injection](https://github.com/samuelgfeller/slim-example-project/wiki/Dependency-Injection)
* [Slim 4 micro-framework](https://github.com/slimphp/Slim)
* [Dependency Injection](https://github.com/samuelgfeller/slim-example-project/wiki/Dependency-Injection) - [PHP-DI](https://php-di.org/)
* [Session and flash messages](https://github.com/samuelgfeller/slim-example-project/wiki/Session-and-Flash-messages)
* [Template rendering](https://github.com/samuelgfeller/slim-example-project/wiki/Template-rendering) - [PHP-View](https://github.com/slimphp/PHP-View)
* [Logging](https://github.com/samuelgfeller/slim-example-project/wiki/Logging) - [Monolog](https://github.com/Seldaek/monolog)
* [Database migrations](https://github.com/samuelgfeller/slim-example-project/wiki/Database-Migrations) - [Phinx](https://phinx.org/)
* [Validation](https://github.com/samuelgfeller/slim-example-project/wiki/Validation) - [cakephp/validation](https://book.cakephp.org/4/en/core-libraries/validation.html)
* [Mailing](https://github.com/samuelgfeller/slim-example-project/wiki/Mailing) - [Symfony Mailer](https://symfony.com/doc/current/mailer.html)
* [Localization](https://github.com/samuelgfeller/slim-example-project/wiki/Translations) - [gettext](https://www.gnu.org/software/gettext/)
* [Query Builder](https://github.com/samuelgfeller/slim-example-project/wiki/Repository-and-Query-Builder) - [cakephp/database](https://book.cakephp.org/5/en/orm/query-builder.html)
* [Integration / unit testing](https://github.com/samuelgfeller/slim-example-project/wiki/Writing-Tests) - [PHPUnit](https://github.com/sebastianbergmann/phpunit/) - [test-traits](https://github.com/samuelgfeller/test-traits)
* [Error handling](https://github.com/samuelgfeller/slim-example-project/wiki/Error-Handling) - [slim-error-renderer](https://github.com/samuelgfeller/slim-error-renderer)
* [GitHub Actions](https://github.com/samuelgfeller/slim-example-project/wiki/GitHub-Actions) and [Scrutinizer](https://github.com/samuelgfeller/slim-example-project/wiki/How-to-set-up-Scrutinizer)
* [Coding standards fixer](https://github.com/samuelgfeller/slim-example-project/wiki/Coding-Standards-Fixer) - [PHP-CS-Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer)
* [Static code analysis](https://github.com/samuelgfeller/slim-example-project/wiki/PHPStan-Static-Code-Analysis) - [PHPStan](https://github.com/phpstan/phpstan)

**Functionalities demonstrating real-world features:**

* [Authentication](https://github.com/samuelgfeller/slim-example-project/wiki/Authentication) (login)
and [authorization](https://github.com/samuelgfeller/slim-example-project/wiki/Authorization) (permissions)
* Account verification and [password reset](https://github.com/samuelgfeller/slim-example-project/wiki/Authentication#password-forgotten)
via email link and token
* [Request throttling](https://github.com/samuelgfeller/slim-example-project/wiki/Security#request-throttling) -
protection against rapid fire and distributed brute force attacks (time throttling and captcha)
* [Localization](https://github.com/samuelgfeller/slim-example-project/wiki/Translations) - English, German and French
* [Validation](https://github.com/samuelgfeller/slim-example-project/wiki/Validation)
* [Template rendering](https://github.com/samuelgfeller/slim-example-project/wiki/Template-rendering) with native PHP syntax (easily interchangeable with twig)
* [Dark theme](https://github.com/samuelgfeller/slim-example-project/wiki/Dark-Theme)
* [Advanced error handling](https://github.com/samuelgfeller/slim-example-project/wiki/Error-Handling)
* [Integration & unit testing](https://github.com/samuelgfeller/slim-example-project/wiki/Writing-Tests)
with fixtures and data providers
* [Database migrations](https://github.com/samuelgfeller/slim-example-project/wiki/Database-Migrations) and [seeding](https://github.com/samuelgfeller/slim-example-project/wiki/Database-Migrations#seeding)
* [Query Builder](https://github.com/samuelgfeller/slim-example-project/wiki/Repository-and-Query-Builder)
* [Logging](https://github.com/samuelgfeller/slim-example-project/wiki/Logging)
* [Mailing](https://github.com/samuelgfeller/slim-example-project/wiki/Mailing)
* [Simple console commands](https://github.com/samuelgfeller/slim-example-project/wiki/Console-Commands)
* [Scrutinizer](https://github.com/samuelgfeller/slim-example-project/wiki/How-to-set-up-Scrutinizer)
* [GitHub Actions](https://github.com/samuelgfeller/slim-example-project/wiki/GitHub-Actions)

**Functionalities demonstrating real-world features:**

protection against brute force and password spraying attacks
* User management for administrators
* 4 user roles and different permissions
* User activity history
Expand All @@ -76,6 +76,7 @@ to manage and maintain a record of communication through notes of people they he
* Note creation and mutation
* Hidden notes from unauthorized users
* Dashboard with panels
* [Dark / light theme](https://github.com/samuelgfeller/slim-example-project/wiki/Dark-Theme)


<details>
Expand All @@ -85,7 +86,7 @@ to manage and maintain a record of communication through notes of people they he
Link: [Login](https://demo.slim-example-project.samuel-gfeller.ch)
Username: `admin@user.com`
Password: `12345678`
The database is reset regularly.
The database is regularly reset.

</details>

Expand Down Expand Up @@ -120,16 +121,16 @@ implementations of features.
However, I find them often
too complex, where the code makes too much "behind the scenes" and with lots of dependencies,
which can lead to time-consuming refactoring on version changes.
I also dislike having to follow the propitiatory rules of a framework and
I also dislike having to follow the propitiatory rules of a framework [which often don't
follow best practices](https://www.reddit.com/r/PHP/comments/131t2k1/laravel_considered_harmful)
and
much prefer the freedom of a micro-framework and carefully
[choosing the libraries](https://github.com/samuelgfeller/slim-example-project/wiki/Libraries-and-Framework#choosing-the-right-libraries)
I want to use.
[choosing the libraries](https://github.com/samuelgfeller/slim-example-project/wiki/Libraries-and-Framework#choosing-the-right-libraries) and structure
that make sense for the project.
This lets me stay in control of the codebase, keep it lightweight,
performant and tailored to the needs of the project, and it's easier to maintain
and adapt to new requirements.

You can very well adapt it to your own needs as well, remove or add features, and change the libraries.

## Disclaimer
This project and its documentation are the result of my personal learning process in the last 6 years
in trying to create the best possible template app with lots of real world examples.
Expand All @@ -139,13 +140,14 @@ I made what wish I had when I started getting seriously into web development.
The codebase is big and thus lots of subjective decisions had to be made that may not be the best
long-term solution for everybody.

The main focus throughout the development was to make the code as dependency free as possible
so that it's long living and can be adapted to different needs and preferences.
The main focus throughout the development was to make the code as long living as possible
with best practices and few dependencies so that it can be adapted to different needs and
preferences.

Basically, this is my take on what a modern and efficient web app could look like with today's
Basically, this is my take on what an efficient, extensible, and maintainable web app could look like with today's
tech.

I worked closely with the software architect
I worked closely with the software engineer and architect
[Daniel Opitz](https://odan.github.io/about.html), who also reviewed this project.
I learned a lot during
[our exchanges](https://github.com/samuelgfeller/slim-example-project/wiki/Sources-of-knowledge#discussions)
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"@add-migrations-to-git"
],
"add-migrations-to-git": "git add resources/migrations/* && git add resources/schema/*",
"seed:minimal": "php vendor/bin/phinx seed:run -c config/env/env.phinx.php -s ClientStatusSeeder -s UserRoleSeeder -s AdminUserSeeder",
"seed": "php vendor/bin/phinx seed:run -c config/env/env.phinx.php"
"seed": "php vendor/bin/phinx seed:run -c config/env/env.phinx.php -s ClientStatusSeeder -s UserRoleSeeder -s AdminUserSeeder",
"seed:extended": "php vendor/bin/phinx seed:run -c config/env/env.phinx.php"
}
}
2 changes: 1 addition & 1 deletion config/defaults.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
$settings['deployment'] = [
// Version string or null. If JsImportCacheBuster is enabled, `null` removes all query param versions from js
// imports.
'version' => '0.4.2',
'version' => '1.0.0',
// When true, JsImportCacheBuster is enabled and goes through all js files and changes the version number
// from the imports. Should be disabled in env.prod.php.
// https://github.com/samuelgfeller/slim-example-project/wiki/Template-rendering#js-import-cache-busting
Expand Down
2 changes: 1 addition & 1 deletion public/assets/authentication/login-main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {removeValidationErrorMessages} from "../general/ajax/ajax-util/fail-handler.js?v=0.4.2";
import {removeValidationErrorMessages} from "../general/ajax/ajax-util/fail-handler.js?v=1.0.0";

const passwordForgottenBtn = document.getElementById('password-forgotten-btn');
const passwordInputDiv = document.getElementById('password-input-div');
Expand Down
1 change: 1 addition & 0 deletions public/assets/authentication/login.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
background: linear-gradient(to bottom right, #1dc6fd 0%, #e589b7 90%);
padding: 0 10px;
/*background: linear-gradient(to top left, #2e3e50 20%, #ffffff 100%);*/
/*background: linear-gradient(to top left, #2e3e50 45%, #ffffff 45%);*/
}

h2 {
Expand Down
2 changes: 1 addition & 1 deletion public/assets/authentication/password-reset-main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {addPasswordStrengthCheck} from "./password-strength-checker.js?v=0.4.2";
import {addPasswordStrengthCheck} from "./password-strength-checker.js?v=1.0.0";

addPasswordStrengthCheck();

Expand Down
6 changes: 3 additions & 3 deletions public/assets/authentication/password-strength-checker.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {handleFail} from "../general/ajax/ajax-util/fail-handler.js?v=0.4.2";
import {fetchTranslations} from "../general/ajax/fetch-translation-data.js?v=0.4.2";
import {__} from "../general/general-js/functions.js?v=0.4.2";
import {handleFail} from "../general/ajax/ajax-util/fail-handler.js?v=1.0.0";
import {fetchTranslations} from "../general/ajax/fetch-translation-data.js?v=1.0.0";
import {__} from "../general/general-js/functions.js?v=1.0.0";

// Init vars
let password1Input, password2Inp;
Expand Down
14 changes: 7 additions & 7 deletions public/assets/client/create/client-create-main.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {displayClientCreateModal} from "./client-create-modal.html.js?v=0.4.2";
import {displayFlashMessage} from "../../general/page-component/flash-message/flash-message.js?v=0.4.2";
import {displayValidationErrorMessage} from "../../general/validation/form-validation.js?v=0.4.2";
import {fetchAndLoadClients} from "../list/client-list-loading.js?v=0.4.2";
import {__} from "../../general/general-js/functions.js?v=0.4.2";
import {fetchTranslations} from "../../general/ajax/fetch-translation-data.js?v=0.4.2";
import {submitModalForm} from "../../general/ajax/modal-submit-request.js?v=0.4.2";
import {displayClientCreateModal} from "./client-create-modal.html.js?v=1.0.0";
import {displayFlashMessage} from "../../general/page-component/flash-message/flash-message.js?v=1.0.0";
import {displayValidationErrorMessage} from "../../general/validation/form-validation.js?v=1.0.0";
import {fetchAndLoadClients} from "../list/client-list-loading.js?v=1.0.0";
import {__} from "../../general/general-js/functions.js?v=1.0.0";
import {fetchTranslations} from "../../general/ajax/fetch-translation-data.js?v=1.0.0";
import {submitModalForm} from "../../general/ajax/modal-submit-request.js?v=1.0.0";

// Init event listeners if button is present
document.getElementById('create-client-btn')?.addEventListener('click', displayClientCreateModal);
Expand Down
12 changes: 6 additions & 6 deletions public/assets/client/create/client-create-modal.html.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {createModal} from "../../general/page-component/modal/modal.js?v=0.4.2";
import {requestDropdownOptions} from "../../general/page-component/modal/dropdown-request.js?v=0.4.2";
import {getDropdownAsHtmlOptions, getRadioButtonsAsHtml} from "../../general/template/template-util.js?v=0.4.2";
import {displayFlashMessage} from "../../general/page-component/flash-message/flash-message.js?v=0.4.2";
import {__} from "../../general/general-js/functions.js?v=0.4.2";
import {fetchTranslations} from "../../general/ajax/fetch-translation-data.js?v=0.4.2";
import {createModal} from "../../general/page-component/modal/modal.js?v=1.0.0";
import {requestDropdownOptions} from "../../general/page-component/modal/dropdown-request.js?v=1.0.0";
import {getDropdownAsHtmlOptions, getRadioButtonsAsHtml} from "../../general/template/template-util.js?v=1.0.0";
import {displayFlashMessage} from "../../general/page-component/flash-message/flash-message.js?v=1.0.0";
import {__} from "../../general/general-js/functions.js?v=1.0.0";
import {fetchTranslations} from "../../general/ajax/fetch-translation-data.js?v=1.0.0";

// List of words that are used in modal box and need to be translated
let wordsToTranslate = [
Expand Down
12 changes: 6 additions & 6 deletions public/assets/client/list/client-list-loading.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import {getClientProfileCardHtml} from "./client-list-profile-card.html.js?v=0.4.2";
import {getClientProfileCardHtml} from "./client-list-profile-card.html.js?v=1.0.0";
import {
displayClientProfileCardSkeletonLoader,
removeClientCardSkeletonLoader
} from "./client-list-skeleton-loader.js?v=0.4.2";
import {fetchData} from "../../general/ajax/fetch-data.js?v=0.4.2";
} from "./client-list-skeleton-loader.js?v=1.0.0";
import {fetchData} from "../../general/ajax/fetch-data.js?v=1.0.0";
import {
disableMouseWheelClickScrolling,
openLinkOnHtmlElement
} from "../../general/event-handler/open-link-on-html-element.js?v=0.4.2";
} from "../../general/event-handler/open-link-on-html-element.js?v=1.0.0";
import {
triggerClickOnHtmlElementEnterKeypress
} from "../../general/event-handler/trigger-click-on-enter-keypress.js?v=0.4.2";
import {submitUpdate} from "../../general/ajax/submit-update-data.js?v=0.4.2";
} from "../../general/event-handler/trigger-click-on-enter-keypress.js?v=1.0.0";
import {submitUpdate} from "../../general/ajax/submit-update-data.js?v=1.0.0";

// When searching clients, a request is made on each keyup and only the final result should be shown to the user,
// not a response from a previous request.
Expand Down
4 changes: 2 additions & 2 deletions public/assets/client/list/client-list-main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {fetchAndLoadClients, fetchAndLoadClientsEventHandler} from "./client-list-loading.js?v=0.4.2";
import {initFilterChipEventListeners} from "../../general/page-component/filter-chip/filter-chip.js?v=0.4.2";
import {fetchAndLoadClients, fetchAndLoadClientsEventHandler} from "./client-list-loading.js?v=1.0.0";
import {initFilterChipEventListeners} from "../../general/page-component/filter-chip/filter-chip.js?v=1.0.0";

// Load clients at page startup
fetchAndLoadClients();
Expand Down
6 changes: 3 additions & 3 deletions public/assets/client/list/client-list-profile-card.html.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {getAvatarPath} from "../util/client-template-util.js?v=0.4.2";
import {html} from "../../general/general-js/functions.js?v=0.4.2";
import {getDropdownAsHtmlOptions} from "../../general/template/template-util.js?v=0.4.2";
import {getAvatarPath} from "../util/client-template-util.js?v=1.0.0";
import {html} from "../../general/general-js/functions.js?v=1.0.0";
import {getDropdownAsHtmlOptions} from "../../general/template/template-util.js?v=1.0.0";

/**
* HTML code for client profile card
Expand Down
2 changes: 1 addition & 1 deletion public/assets/client/list/client-list-skeleton-loader.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {getClientProfileCardSkeletonLoaderHtml} from "./client-list-profile-card.html.js?v=0.4.2";
import {getClientProfileCardSkeletonLoaderHtml} from "./client-list-profile-card.html.js?v=1.0.0";

/**
* Display client skeleton loaders
Expand Down
Loading

0 comments on commit 5ac7231

Please sign in to comment.