This project is no longer maintained. At this time, the repository has been archived, and is read-only. (c) Denis Puzik [email protected] |
![]() |
---|
- examples of
design and implementation of basic architectural solutions
thatimprove performance and security
:- built on the use of
triggers, functions, procedures and events in the MySql
database; - to
improve performance work with caching
at all levels: standard cache in Laminas Framework, cache in Doctrine, cache customers objects and data to lists inRedis
, which storesdata in RAM
; asynchronous thread processing potentially lengthy processes
tied to interaction with third-party services, usingApache Kafka
programmatic message broker and using a scheme to exchange information between the sender and by the recipient, when data sources send information flows, and recipients process them as needed;- logging in the NoSql
MongoDB
database and the ability to view logs through the web interface;
- built on the use of
program code
written according to the"clean code"
principle, according to the concepts ofSOLID
,DRY
,DDD
, with the implementation of the current recommendations adopted by thePSR
, written in Laminas Framework using the most commonDesign Patterns
;- using most of the
standard components
of the Laminas framework and third-party most effective and common components offering proven solutions:- for databases (relational MySql and NoSql types, MongoDB type) - a set of
Doctrine
components: DBAL, ORM, doctrine-orm-module, ODM, doctrine-mongo-odm-module, data-fixtures, migrations; - for complex unit and integration testing -
phpunit
component set: laminas-test, php-code-coverage;
- for databases (relational MySql and NoSql types, MongoDB type) - a set of
automatic check
ofstyle
and"purity"
,static analysis
of the writtencode
; executingPHP Unit and Integration tests
, providing the mostfull code coverage
with tests and checking various combinationsall possible test cases
; which can be executed in the console after each change to the code and be sure that all checks are successfully passed;automatic installation/updating/checking
in the project, by executing simplecomposer
commands in the console from thecomposer.json
file from thescripts
section:- a set of all dependent components and libraries;
- deleting the entire existing structure of the main database in MySql;
- creating an empty structure of the main database in MySql,
- generation of any volume, amount of data and filling them with tables of the main database in MySql;
Clean as Code
is an approach to code quality that eliminates many of the challenges that come with traditional approaches. As a developer, focus on maintaining high standards and taking responsibility specifically in the new code working on.SonarQube
gives the tools to set high standards and take pride in knowing that code meets those standards.optimal automated process for releasing software releases
use the principle ofCI / CD
inBitbucket Pipelines
use an integrated CI/CD service built into Bitbucket, which allows toautomatically build, test, and even deploy code
based on a configuration file in repository, inDocker containers in the Cloud
.- which
can guarantee
ahigh speed of release of new versions
of the software product,high quality of the code and the functionality
of the released software product, theabsence of bugs
and, as a result,customer satisfaction
andincrease in sales of the manufactured software product
and, accordingly, anincrease in profits
.
- Web HTTP Server (example: Apache 2.4 HTTP server with mod_rewrite module or Nginx HTTP server)
- PHP 7.4 or 8.0 with extensions gd, mbstring, xdebug, intl, pdo, mongodb, redis
- Laminas Framework, Doctrine ORM, ODM, DataFixtures, Migrations, PHPUnit and other
- DB MySql 8.0, or later (active use triggers in tables, functions and procedures, events)
- DB Redis 5.0 or later
- MongoDB 5.0 or later
- Apache Kafka
- Bitbucket Pipelines use the principle of CI / CD
- SonarQube
- In MySql create DB laminas_mvc_demo
CREATE DATABASE laminas_mvc_demo
CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci;
- In MySql create DB laminas_mvc_demo_integration
CREATE DATABASE laminas_mvc_demo_integration
CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci;
- In MySql create user laminas_mvc_demo for DB laminas_mvc_demo
CREATE USER 'laminas_mvc_demo'@'localhost' identified with mysql_native_password by 'laminas_mvc_demo123';
GRANT ALL PRIVILEGES ON laminas_mvc_demo.* TO laminas_mvc_demo@localhost;
- In MySql create user laminas_mvc_demo_integration for DB laminas_mvc_demo_integration
CREATE USER 'laminas_mvc_demo_integration'@'localhost' identified with mysql_native_password by 'laminas_mvc_demo_integration123';
GRANT ALL PRIVILEGES ON laminas_mvc_demo_integration.* TO laminas_mvc_demo_integration@localhost;
- In MySql, if necessary, set a parameter to relax the checking of non-deterministic functions.
mysql -u root -p
SET GLOBAL log_bin_trust_function_creators = 1;
- Clone a project code from the repository
git clone https://github.com/scorpion3dd/laminas_mvc_demo.git
Execute the actions of the items 7.-13. - automatically by executing the
executable file project_init.sh
, after giving it permission to execute:
sudo chmod +x ./project_init.sh
./project_init.sh
sudo chmod -R 777 ./data/logs
Or execute the actions of the items 7.-13. individually manually.
- Composer install the dependencies (Laminas Framework components and Doctrine)
composer install
or
composer install --ignore-platform-reqs
- In the file /config/autoload/global.php, if necessary, change the parameters
- Copy config files from distribute version to worked, if necessary, change the parameters (example set database password parameter)
cp ./config/autoload/local.php.dist ./config/autoload/local.php
cp ./config/autoload/module.doctrine-mongo-odm.local.php.dist ./config/autoload/module.doctrine-mongo-odm.local.php
cp ./config/autoload_test/local.php.dist ./config/autoload_test/local.php
cp ./config/autoload_test/module.doctrine-mongo-odm.local.php.dist ./config/autoload_test/module.doctrine-mongo-odm.local.php
cp ./config/autoload/laminas-developer-tools.local.php.dist ./config/autoload/laminas-developer-tools.local.php
cp ./config/development.config.php.dist ./config/development.config.php
cp ./public/.htaccess.dist ./public/.htaccess
- Enable development mode: The Laminas Framework ships with zf-development-mode by default, and provides three aliases for consuming the script it ships with:
composer development-enable # enable development mode
composer development-disable # disable development mode
composer development-status # whether or not development mode is enabled
You may provide development-only modules and bootstrap-level configuration in
config/development.config.php.dist
, and development-only application
configuration in config/autoload/development.local.php.dist
. Enabling
development mode will copy these files to versions removing the .dist
suffix,
while disabling development mode will remove those copies.
Development mode is automatically enabled as part of the skeleton installation process.
After making changes to one of the above-mentioned .dist
configuration files you will
either need to disable then enable development mode for the changes to take effect,
or manually make matching updates to the .dist
-less copies of those files.
- Give write permissions to directories:
- /data/cache
- /data/cache_test
- /data/logs
- /data/DoctrineModule/cache
- /data/DoctrineMongoODMModule
- /public/img/captcha
Adjust permissions for data
directory:
sudo chown -R www-data:www-data ./data/cache
sudo chown -R www-data:www-data ./data/cache_test
sudo chown -R www-data:www-data ./data/logs
sudo chown -R www-data:www-data ./data/DoctrineModule/cache
Adjust permissions for next directories:
sudo chmod -R 777 ./data/cache
sudo chmod -R 777 ./data/cache_test
sudo chmod -R 777 ./data/logs
sudo chmod -R 777 ./data/DoctrineModule/cache
sudo chmod -R 777 ./data/DoctrineMongoODMModule
sudo chmod -R 777 ./public/img/captcha
- In MySql create empty structure for database laminas_mvc_demo (tables, triggers, functions, procedures, events) and generate fixtures data by executing the SQL script, run next command:
composer project-init
- In MySql create empty structure for database laminas_mvc_demo_integration (tables, triggers, functions, procedures) and generate fixtures data by executing the SQL script, run next command:
composer project-init-integration
- Create virtual host in you web server
To setup apache, setup a virtual host to point to the public/ directory of the project and you should be ready to go! It should look something like below:
<VirtualHost *:80>
ServerName laminas-mvc.demo.vms
ServerAlias laminas-mvc.demo.vms
DocumentRoot /path/to/laminas-mvc/public
<Directory /path/to/laminas-mvc/public/>
DirectoryIndex index.php
AllowOverride All
Order allow,deny
Allow from all
<IfModule mod_authz_core.c>
Require all granted
</IfModule>
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error_laminas_mvc_demo.log
CustomLog ${APACHE_LOG_DIR}/access_laminas_mvc_demo.log combined
</VirtualHost>
To setup nginx, open your /path/to/nginx/nginx.conf
and add an
include directive below
into http
block if it does not already exist:
http {
# ...
include sites-enabled/*.conf;
}
Create a virtual host configuration file for your project under /path/to/nginx/sites-enabled/zfapp.localhost.conf
it should look something like below:
server {
listen 80;
server_name laminas-mvc.demo.vms;
root /path/to/laminas-mvc-demo/public;
location / {
index index.php;
try_files $uri $uri/ @php;
}
location @php {
# Pass the PHP requests to FastCGI server (php-fpm) on 127.0.0.1:9000
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME /path/to/laminas-mvc-demo/public/index.php;
include fastcgi_params;
}
}
Restart the Apache or Nginx, now you should be ready to go!
- Reload Web Server (example Apache)
sudo systemctl restart apache2
- Reload Web Server (example Nginx)
sudo systemctl restart nginx
- Run all PHP automatic checks (code style checker, code static checker, Unit and Integration tests):
composer project-check-all
-
Now you should be able to see the
Simple Web Demo Free Lottery Management Application
website by visiting the link "http://laminas-mvc.demo.vms/". -
If you want to test the site performance on any amount of data, you can:
- set value to parameter
app.count_users
the required number of entries for new users - in the file/config/autoload/local.php
for the website and in the file/config/autoload_test/local.php
for integration tests, and save; - automatically completely recreate all data sets for the website and for integration tests, i.e. delete all data and structures of MySql databases, create a new empty database structure, generate dummy datasets, perform all automatic checks - to do this, execute just one command:
composer project-refresh-all
This Simple Web Demo Free Lottery Management Application
.
The Free Lottery application
performs user management.
Users with the "Administrator" role in manual mode
, after
authentication in the application, with next credentials:
- email (login): [email protected]
- password: admin123
Through the admin menu can:
- create, edit, delete records with user data;
- can change the status of users from active to inactive;
- can give other users access to a very valuable resource.
When the Administrator changes the user's data, for example, changes the
Status or the User's Access - after saving the changes in the database,
the user is sent a notification letter to his email
.
Since the sending of emails affects external systems
, this process may take
some time. In order to quickly release (not delay the process of sending letters)
the web interface to the Administrator for its further work, Apache Kafka
is used,
which is a message broker and provides uninterrupted and convenient data exchange
in messages during asynchronous communication between the Producer and the Consumer
.
Thus, the Producer
script writes the necessary information in a specific data structure,
which is serialized into a string and transmitted as a message to Apache Kafka and returns
control back to the Administrator, without delay
.
And after some short period of time in the Consumer
script, all messages from Apache Kafka
are read in a stream and the text of each message is parsed in a certain way and
deserialized into a certain data structure, followed by specific processing
(sending a letter
from the Administrator to the user with a specific message text).
And also in automatic mode
for random users, the application can perform
a "Free Lottery", that is, change the status of users from active to
inactive and can give other active users the opportunity to access a
very valuable resource. This is possible through active use in DB MySql
triggers in tables, functions and procedures, events
.
Another application "Free Lottery" manages roles and user access privileges. Users with the "Administrator" role in manual mode, after authentication in the application, through the admin menu can:
- create, edit, delete user roles;
- create, edit, remove user access privileges;
- make user roles hierarchical;
- assign access privileges to user roles;
- change user roles;
The "Free Lottery" application on the main page, freely available, without user authentication, allows you to view a list of active users with open access to a very valuable resource at a given time.
It shows how to:
- Implement roles and permissions
- Organize roles in database into an hierarchy
- Use Laminas\Permissions\Rbac component to implement role-based access control
- Use dynamic assertions to implement complex access control rules
The web part of this project consists of a public part and an admin panel, which can only be entered after passing authentication, having entered the email and password correctly.
Select different languages
in the user interface and all services texts
in pages translator to selected language
.
For great performance application use DB Redis
, which save data to RAM and
operations write and read from Redis running very quickly.
The "Free Lottery" application during operation writes logs
to a text file
,
in the MongoDB database
and in the MySql database
.
In order to view the logs from the mongo database, you need to go to the "Logs" page,
on which you can view a list of logs, you can click on a specific log and view detailed data about the log,
you can edit or delete a specific log, you can manually add a new entry for a new log.
This is a skeleton application using the Laminas Framework:
- MVC layer and module systems.
- Security.
- Performance.
- Standard Design Patterns.
- Main Components.
- PHP Standards Recommendations (PSR).
- Principles of Clean Code (SOLID, DRY) and Clean Architecture in PHP.
- Develop websites
much faster
with Laminas Framework, because Laminas Framework providesmany standards and loosely coupled components
. What giveseasier interaction with team members
. - Using the
concept of modules
Laminas Framework makes iteasy to scale
the website. - The
Model-View-Controller
(MVC) pattern used in Laminas Framework allows to implementDomain Driven Design
(DDD) separate the business logic from the presentation layer, makingthe code structure more consistent and manageable
. - Instead of interacting directly with the database through SQL queries,
using
Doctrine Object-Relational Mapping
(ORM, ODM) allows you tomanage the structure and relationships of data
by accessing the database in anobject-oriented style
. - The use of components such as
filters
andform validators
, HTML outputescapers
andcrypto algorithms
,human check
(Captcha) andCross-Site Request Forgery
(CSRF) form elements allow to createthe most secure websites
.
- The
input script
(index.php) - is the only PHP file available to web visitors. All other PHP scripts are outside the document root directory of the Apache web server. This is much safer than giving all visitors access to any of the PHP scripts. Request Routing
(Routing) - allows to setstrict rules
for how an acceptable web page URL should look like. If the user enters an invalid URL into the browser's navigation bar, they are automatically directed to an error page.Access control lists
(ACL) andRole-Based Access Control
(RBAC) - allow to setrules to allow
ordeny access
to specific resources on website.- Web form
validators
andfilters
- allow you to be sure that harmful data entered by the user will not pass through the web form.Filters
, for example, allow you to trim the input string or remove HTML tags from it.Validators
are used to make sure that the data submitted through a web form meet certain rules. Captcha
andCross-Site Request Forgery
(CSRF) form elements - used to prevent hacker attacks.- Laminas component
Escaper
- allows you to strip unwanted HTML tags from data output to a web page. - Support for
cryptography
- allows you to store important data, such as passwords, encrypted with strong cryptographic algorithms, which are difficult to crack.
Lazy class autoloading
- classes are loaded only when needed.Efficient loading of services and plugins
in Laminas Framework - business logic classes are instantiated only when really needed. This is achieved through theservice manager
, the central container for all of the application's services.Caching support
- PHP has several caching extensions (such as Memcached) that can be used to speed up sites built with Laminas Framework.
- The
Model-View-Controller
pattern is used in all modern PHP frameworks. In an MVC application, you separate your code into three categories:models
(your business logic),views
(presentation), andcontrollers
(code responsible for user interaction). With MVC, you can reuse the components of this triad in other projects. It is also easy to replace any part of the triad. For example, you can easily replace a view with another view without changing the business logic. Domain Driven Design
(DDD) in Laminas Framework, you will be dividing the model layer even further into:entities
- classes that work with database tables,repositories
- classes that allow you to get entities from the database,value objects
- model classes, without an identifier, andservices
- that is, classes responsible for business logic. Additionally, you will have webforms
- model classes responsible for user input,form helpers
in the form ofvalidators
andfilters
. You will have a view rendering strategy that determines what how the page will be rendered. By default, to get an HTML page, the.phtml view template
is rendered using thePhpRenderer
class, which lives in the Laminas\View\Renderer namespace. This strategy works well 99% of the time. But sometimes you may need to render something other than the HTML page, for example, response in JSON format or a news feed (RSS feed). View helpers, reusable plugins designed to display different content on a web page, and probably other types of models.Aspect Oriented Design template
- everything in Laminas Framework is based on events. When a user requests a web page, an event is fired. An observer can respond to an event.Observers
can be divided into listeners (listener) andsubscribers
(subscriber). This allows you to expand the capabilities of the framework. For example, the Laminas\Router component parses the URL and determines which controller to call.- The
Strategy
template - is just a class that encapsulates an algorithm. And you can use different algorithms if certain conditions are triggered. For example, a renderer has several strategies for rendering a web page (for example, it can generate an HTML page, a JSON array, or an RSS feed based on the HTTP headers request). Adapter
pattern - allows you to tailor a general purpose class to a specific use case. For example, the Laminas\Db component provides access to a database regardless of the type of DBMS. Internally, it uses adapters for each supported DBMS (SQLite, MySQL, PostgreSQL, etc.)Factory
pattern - you can create an instance of a class using the new operator. Or can create it with a factory. A factory is just a class that creates other objects. Factories are useful because they makedependency injection
easier. It also makes iteasier to test models and controllers
.- The
Service Manager
template - is a centralized repository of all the services available in the application. Extract services from the service manager not anywhere in the code, but inside the factory (factory). When you create an object, extract the services it depends on and pass those services (dependencies) to the object's constructor. This is also calleddependency injection
. Singleton
pattern - each service in the centralized repository of all services available in the application exists in only one instance.
Laminas\EventManager
- allows you to create events (events) and register event handlers.Laminas\ModuleManager
- In Laminas Framework based sites everything is made up of modules and this component allows you to load modules.Laminas\ServiceManager
- This is the central repository for all services available in the application. Services contain business application logic.Laminas\Http
- Provides a simple interface for working with Hypertext Transfer Protocol (HTTP) requests.Laminas\Mvc
- Support for the Model-View-Controller (Model-View-Controller) pattern.Laminas\View
- Provides a system of helpers (view helpers) and output escapers. Used in the presentation (view) layer.Laminas\Form
- Helps to collect data entered by the user, as well as filter it, validate it, and display forms on a web page.Laminas\InputFilter
- Allows you to set filtering and validation rules for data entered by the user in a web form.Laminas\Filter
- Provides a set of commonly used filters such as string trimmer.Laminas\Validator
- Provides a set of commonly used validators.Laminas\Mvc\I18n
- Provides a simple localize view templates, view helpers, forms, validator messages, services.Laminas\Log\Logger
- Provides a simple logger to save records to file and MongoDB.Doctrine\ORM
- Provides allows to manage the structure and relationships of data by accessing the database in an object-oriented style.Doctrine\Common\DataFixtures
- Provides a simple generate data fixtures to tables in DB.Laminas\Test\PHPUnit
- Provides a simple PHP unit tests all code in controllers, services, repositories, entities.
PSR-1 - Basic Coding Standard
- used in all codes in Laminas Framework.PSR-3 - Logger Interface
- used inlaminas-log
component in Laminas Framework.PSR-4 - Autoloading Standard
- in Laminas Framework, the recommendeddirectory structure
follows this standard and used inautoload
all components, libraries, packages in Laminas Framework by composer.PSR-6 - Caching Interface
- used inlaminas-cache
component in Laminas Framework.PSR-7 - HTTP Message Interface
- used inLaminas\Stdlib\Message
,Laminas\Http\Request
,Laminas\Http\Response
components in Laminas Framework.PSR-11 - Container Interface
- used inInterop\Container\ContainerInterface
,Laminas\ServiceManager\Factory\FactoryInterface
,Laminas\ServiceManager\ServiceManager
components in Laminas Framework.PSR-12 - Extended Coding Style Guide
- used in all codes in Laminas Framework.PSR-13 - Hypermedia Links
- used inLaminas\View\Helper\Url
,Laminas\Uri\Http
components in Laminas Framework.PSR-14 - Event Dispatcher
- used inEventManagerInterface
,Laminas\Mvc\MvcEvent
,Doctrine\Common\EventManager
,Doctrine\DBAL\Events
component in Laminas Framework.
Single Responsibility Principle
(SRP)Open/Closed Principle
(OCP)Liskov Substitution Principle
(LSP)Interface Segregation Principle
(ISP)Dependency Inversion Principle
(DIP)
- Need completely get rid of duplicate code.
Composer is a dependency manager
for the PHP programming language.
An additional feature of Composer is that it offers utilities for
hooking packages to PHP autoload
by PSR-4.
Custom scripts
that do not fit one of the predefined event name above,
can either run them with run-script or also run them as native Composer commands
.
The handler for automatic code style checking can be executed by running:
composer cs-check
The handler for automatic code style fixing errors can be executed by running:
composer cs-fix
The handler for automatic code static checking can be executed by running:
composer stan-check
The handler for automatic checking all tests in module application can be executed by running:
composer test-application
The handler for automatic checking unit tests in module application can be executed by running:
composer test-application-unit
The handler for automatic checking integration tests in module application can be executed by running:
composer test-application-integration
The handler for automatic checking all tests in module user can be executed by running:
composer test-user
The handler for automatic checking unit tests in module user can be executed by running:
composer test-user-unit
The handler for automatic checking integration tests in module user can be executed by running:
composer test-user-integration
The handler for automatic checking unit tests in all modules can be executed by running:
composer test-unit
The handler for automatic checking integration tests in all modules can be executed by running:
composer test-integration
The handler for automatic checking all, unit and integration tests in all modules can be executed by running:
composer test-all
The handler for automatic checking all, unit and integration tests in all modules with coverage can be executed by running:
composer test-all-coverage
The handler for automatic drop all Databases can be executed by running:
composer db-drop
The handler for automatic drop all Databases for integration tests can be executed by running:
composer db-drop-integration
The handler for automatic create all Databases can be executed by running:
composer db-create
The handler for automatic create all Databases for integration tests can be executed by running:
composer db-create-integration
The handler for automatic update Databases by Doctrine Migrations from file with SQL scripts updating can be executed by running:
composer doctrine-migrations-generate
composer doctrine-migrations-migrate
composer doctrine-migrations-status
The handler for automatic loading fixtures to all Databases can be executed by running:
composer db-loading-fixtures
The handler for automatic loading fixtures to all Databases for integration tests can be executed by running:
composer db-loading-fixtures-integration
The handler for automatic create all Databases and loading fixtures to all Databases can be executed by running:
composer project-init
The handler for automatic create all Databases and loading fixtures to all Databases for integration tests can be executed by running:
composer project-init-integration
The handler for automatic checking code style, code static, unit tests in all modules can be executed by running:
composer project-check-unit
The handler for automatic checking code style, code static, integration tests in all modules can be executed by running:
composer project-check-integration
The handler for automatic checking code style, code static, all unit and integration tests in all modules can be executed by running:
composer project-check-all
The handler for automatic drop all Databases, create all Databases and loading fixtures to all Databases, checking code style, code static, unit tests in all modules can be executed by running:
composer project-refresh-unit
The handler for automatic drop all Databases, create all Databases and loading fixtures to all Databases, checking code style, code static, integration tests in all modules can be executed by running:
composer project-refresh-integration
The handler for automatic drop all Databases, create all Databases and loading fixtures to all Databases, checking code style, code static, all unit and integration tests in all modules can be executed by running:
composer project-refresh-all
Start SonarQube (and don't close):
composer sonar-start
Run scanner SonarQube:
composer sonar-scanner
The handler for automatic checking code style, code static, all unit and integration tests in all modules, run scanner SonarQube - can be executed by running:
composer project-check-sonar
The handler for automatic drop all Databases, create all Databases and loading fixtures to all Databases, checking code style, code static, all unit and integration tests in all modules, run scanner SonarQube - can be executed by running:
composer project-refresh-sonar
Continuous Integration, Delivery, and Deployment (CI/CD) - is at the heart of the success of DevOps practices.
The principle of CI / CD is focused on creating an optimal automated process for releasing software releases.
Teams that put CI/CD into practice receive constant feedback, delivering software to end users as quickly as possible, by studying user experience and embodying their ideas in the next releases.
Bitbucket Pipelines runs all builds in Docker containers using an image that specify at the beginning of configuration file. Can easily use PHP with Bitbucket Pipelines by using one of the official PHP Docker images on Docker Hub.
Bitbucket Pipelines is an integrated CI/CD service built into Bitbucket. It allows to automatically build, test, and even deploy code based on a configuration file in repository. Essentially, create Docker containers in the cloud.
Each time a pull request is created, a build is started in an empty, reference environment of the Docker container, with all the advantages of a fresh system, customized and configured in which install all necessary services, extensions for PHP are installed, all dependencies of libraries, components and packages are installed, and then all checks are performed.
Then inside these containers, run commands (like might on a local machine) with all checking: check code style, check static code (stan check), check all PHP unit and integration tests - automation of verification of absolutely almost all test cases.
Which can guarantee a high speed of release of new versions of the software product, high quality of the code and the functionality of the released software product, the absence of bugs and, as a result, customer satisfaction and increase in sales of the manufactured software product and, accordingly, an increase in profits.
DB MySql - it is the main relational database that stores all application data in the appropriate tables.
The Database diagram
, table structure, relationships between tables is
shown below:
Some tables have triggers that automatically perform auxiliary operations,
such as logging all performed data write/modify/delete operations.
Example table user
has next triggers:
user_AFTER_INSERT
with SQL code:
create trigger user_AFTER_INSERT after insert on user for each row
BEGIN
DECLARE v_user_id INT DEFAULT 0;
IF (@SESSION.user_id IS NOT NULL ) THEN
SET v_user_id = @SESSION.user_id;
END IF;
INSERT INTO `user_log`
(`user_id`, `action_user_id`, `action`, `changed`, `date_action`)
VALUES (NEW.`id`, v_user_id, 1, '', NOW());
END;
user_AFTER_UPDATE
with SQL code:
create trigger user_AFTER_UPDATE after update on user for each row
BEGIN
DECLARE v_user_id INT DEFAULT 0;
DECLARE v_changed LONGTEXT DEFAULT '';
IF (NEW.`email` <> OLD.`email` or
NEW.`full_name` <> OLD.`full_name` or
NEW.`description` <> OLD.`description` or
NEW.`password` <> OLD.`password` or
NEW.`status` <> OLD.`status` or
NEW.`access` <> OLD.`access` or
NEW.`gender` <> OLD.`gender` or
NEW.`date_birthday` <> OLD.`date_birthday` or
NEW.`date_created` <> OLD.`date_created` or
NEW.`pwd_reset_token` <> OLD.`pwd_reset_token` or
NEW.`pwd_reset_token_creation_date` <> OLD.`pwd_reset_token_creation_date`)
THEN
IF (NEW.`email` <> OLD.`email`) THEN
SET v_changed = CONCAT(v_changed, 'email = ', NEW.`email`, '; ');
END IF;
IF (NEW.`full_name` <> OLD.`full_name`) THEN
SET v_changed = CONCAT(v_changed, 'full_name = ', NEW.`full_name`, '; ');
END IF;
IF (NEW.`description` <> OLD.`description`) THEN
SET v_changed = CONCAT(v_changed, 'description = ', NEW.`description`, '; ');
END IF;
IF (NEW.`status` <> OLD.`status`) THEN
SET v_changed = CONCAT(v_changed, 'status = ', NEW.`status`, '; ');
END IF;
IF (NEW.`access` <> OLD.`access`) THEN
SET v_changed = CONCAT(v_changed, 'access = ', NEW.`access`, '; ');
END IF;
IF (NEW.`gender` <> OLD.`gender`) THEN
SET v_changed = CONCAT(v_changed, 'gender = ', NEW.`gender`, '; ');
END IF;
IF (NEW.`date_birthday` <> OLD.`date_birthday`) THEN
SET v_changed = CONCAT(v_changed, 'date_birthday = ', NEW.`date_birthday`, '; ');
END IF;
IF (NEW.`pwd_reset_token` <> OLD.`pwd_reset_token`) THEN
SET v_changed = CONCAT(v_changed, 'pwd_reset_token = ', NEW.`pwd_reset_token`, '; ');
END IF;
IF (NEW.`pwd_reset_token_creation_date` <> OLD.`pwd_reset_token_creation_date`) THEN
SET v_changed = CONCAT(v_changed, 'pwd_reset_token_creation_date = ', NEW.`pwd_reset_token_creation_date`, '; ');
END IF;
IF (@SESSION.user_id IS NOT NULL ) THEN
SET v_user_id = @SESSION.user_id;
END IF;
INSERT INTO `user_log`
(`user_id`, `action_user_id`, `action`, `changed`, `date_action`)
VALUES (OLD.`id`, v_user_id, 2, v_changed, NOW());
END IF;
END;
user_BEFORE_DELETE
with SQL code:
create trigger user_BEFORE_DELETE before delete on user for each row
BEGIN
DECLARE v_user_id INT DEFAULT 0;
DECLARE v_archive INT DEFAULT 3;
IF (@SESSION.user_id IS NOT NULL) THEN
SET v_user_id = @SESSION.user_id;
END IF;
IF (@SESSION.archive IS NOT NULL) THEN
SET v_archive = @SESSION.archive;
END IF;
INSERT INTO `user_log`
(`user_id`, `action_user_id`, `action`, `changed`, `date_action`)
VALUES (OLD.`id`, v_user_id, v_archive, '', NOW());
DELETE FROM `user_role` WHERE `user_id` = OLD.`id`;
END;
To simulate business processes the Database also uses basic procedures:
moveUsersArchives
with SQL code:
create procedure moveUsersArchives()
BEGIN
DECLARE v_user_id_archived INT DEFAULT 0;
DECLARE v_user_id INT DEFAULT 0;
DECLARE v_done integer DEFAULT 0;
DECLARE v_id decimal(20, 0) DEFAULT 0;
DECLARE v_email varchar(128) DEFAULT '';
DECLARE v_full_name varchar(256) DEFAULT '';
DECLARE v_description varchar(1024) DEFAULT '';
DECLARE v_password varchar(128) DEFAULT '';
DECLARE v_status integer DEFAULT 0;
DECLARE v_access integer DEFAULT 0;
DECLARE v_gender integer DEFAULT 0;
DECLARE v_date_birthday DATETIME;
DECLARE v_date_created DATETIME;
DECLARE v_date_updated DATETIME;
DECLARE v_pwd_reset_token varchar(32) DEFAULT '';
DECLARE v_pwd_reset_token_creation_date DATETIME;
DECLARE v_users_cursor CURSOR FOR
SELECT u.`id`, u.`email`, u.`full_name`, u.`description`, u.`password`, u.`status`,
u.`access`, u.`gender`, u.`date_birthday`, u.`date_created`, u.`date_updated`,
u.`pwd_reset_token`, u.`pwd_reset_token_creation_date`
FROM `user` u
INNER JOIN user_role ur on u.`id` = ur.`user_id`
INNER JOIN role r on r.`id` = ur.`role_id`
WHERE u.`status` = 2 AND r.`name` = 'Guest';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = 1;
IF (@SESSION.user_id IS NOT NULL ) THEN
SET v_user_id = @SESSION.user_id;
END IF;
OPEN v_users_cursor;
users_loop:
LOOP
FETCH v_users_cursor INTO v_id, v_email, v_full_name, v_description, v_password,
v_status, v_access, v_gender, v_date_birthday, v_date_created, v_date_updated,
v_pwd_reset_token, v_pwd_reset_token_creation_date;
IF v_done = 1 THEN
LEAVE users_loop;
END IF;
INSERT INTO `user_archives`
(`email`, `full_name`, `description`, `password`, `status`, `access`, `gender`,
`date_birthday`, `date_created`, `date_updated`, `pwd_reset_token`,
`pwd_reset_token_creation_date`, `date_archived`, `archived_user_id`)
VALUES (v_email, v_full_name, v_description, v_password, v_status, v_access, v_gender,
v_date_birthday, v_date_created, v_date_updated, v_pwd_reset_token,
v_pwd_reset_token_creation_date, NOW(), v_user_id);
SET v_user_id_archived = LAST_INSERT_ID();
UPDATE `user_role` SET `user_id` = 0, `user_archived_id` = v_user_id_archived WHERE `user_id` = v_id;
SET @SESSION.archive = 4;
DELETE FROM `user` WHERE `id` = v_id;
END LOOP users_loop;
CLOSE v_users_cursor;
END;
setUsersAccesses
with SQL code:
create procedure setUsersAccesses()
BEGIN
DECLARE v_max_id INT DEFAULT 0;
SELECT MAX(id) FROM `user` INTO v_max_id;
UPDATE `user` u
INNER JOIN user_role ur on u.`id` = ur.`user_id`
INNER JOIN role r on r.`id` = ur.`role_id`
SET u.`access` = 1, u.`date_updated` = NOW()
WHERE u.`status` = 1 AND r.`name` = 'Guest' AND u.`id` = randomInt(v_max_id);
END;
setUsersArchives
with SQL code:
create procedure setUsersArchives()
BEGIN
DECLARE v_max_id INT DEFAULT 0;
SELECT MAX(id) FROM `user` INTO v_max_id;
UPDATE `user` u
INNER JOIN user_role ur on u.`id` = ur.`user_id`
INNER JOIN role r on r.`id` = ur.`role_id`
SET u.`status` = 2, u.`date_updated` = NOW()
WHERE u.`status` = 1 AND r.`name` = 'Guest' AND u.`id` = randomInt(v_max_id);
END;
setUsersNotAccesses
with SQL code:
create procedure setUsersNotAccesses()
BEGIN
UPDATE `user` SET `access` = 2, `date_updated` = NOW() WHERE `access` = 1;
END;
The Database also uses events that run the main procedures on a given schedule.
moveArchives
with SQL code:
create event moveArchives on schedule
every '1' HOUR starts '2023-01-24 00:42:59' enable do
BEGIN
CALL moveUsersArchives();
END;
setAccesses
;setArchives
;setNotAccesses
.
The Database also uses helper function:
randomInt
with SQL code:
create function randomInt(count int) returns tinyint
BEGIN
DECLARE vResult INT DEFAULT 0;
SELECT FLOOR((RAND() * 100)) INTO vResult;
RETURN vResult;
END;
MongoDB - is an additional NoSqL documentary Database in which application
logs are written, it consists of one collection logs
.
Redis is an auxiliary database that stores data in RAM in the form
of key-value records role:
, lists roles
, sorted lists role:set
and speeds up the application by replacing heavier references to
the main relational DB.
Asynchronous thread processing potentially lengthy processes
tied
to interaction with third-party services, using Apache Kafka
programmatic message broker and using a scheme to exchange information
between the sender and by the recipient, when data sources send
information flows, and recipients process them as needed.
The handler for running zookeeper-server
can be executed by running:
.\bin\windows\zookeeper-server-start.bat .\config\zookeeper.properties
The handler for running Kafka
can be executed by running:
.\bin\windows\kafka-server-start.bat .\config\server.properties
The handler for viewing the list of topics in Kafka
can be
executed by running:
.\bin\windows\kafka-topics.bat --list --bootstrap-server localhost:9092
The handler for viewing the list of messages in topic user_notification
in Kafka
can be executed by running:
.\bin\windows\kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic user_notification
- in file
logfile.log
, example in console run next commands:
cd /data/logs/logfile.log
tail -n 100 -f /data/logs/logfile.log
- in MongoDB
laminas_mvc_demo
collectionlogs
, example run next query:
db.getCollection('logs').find({priority:6, timestamp:{$gte:ISODate("2023-01-24"),$lt:ISODate("2023-02-24")}});
- in MySql DB
z3.demo
tablesuser_log
anduser_role_log
This project has a QA tooling, with configuration for each of:
Provide aliases for each of these tools in the Composer configuration.
# Run CS checks:
composer cs-check
# Fix CS errors:
composer cs-fix
# Run Stan check:
composer stan-check
phpstan analyse --level=7 --memory-limit=1024M --xdebug
# Or run all checks automatic:
composer project-check-unit
For a successful, cyclical, smooth and error-free release of each version
of the software product testers must write a test plan
, that is, make a
very large number
(from several dozen, up to several hundred) test cases
to cover absolutely all possible use cases users of the functionality
of
the software product (for example, each route), for absolutely all business processes
.
And then, before the release of each version, testers must manually execute all previously written test plan
, that is, they must check all
hundreds of test cases. Such a very large number of test cases for manual
verification, makes the work of the tester routine and introduces the
concept of "human factor"
, which increases the likelihood of them making
an error
during the check.
And with subsequent releases of versions of the software product, there
may be a need to perform integration testing
, that is, checking not only
the changes in the latest version, but also the entire functionality,
which means that there will already be several thousand test cases for manual verification
.
Therefore, once writing all the unit and integration tests for each
test case, even if for each route there will be several dozen of them -
you can almost completely automate
all the routine, manual work of
testers and eliminate the human factor in the work of testers almost
completely.
Thus, it is possible to automate up to 90% of all manual work
of testers.
The remaining 10%
, something that cannot be automated, such as
intellectual, creative, research test cases, tests to identify new ways
to use existing functionality, to search for new ones business processes
and, as a result, new offers to users - can remain testers for manual
execution by them.
Automation of verification of absolutely almost all test cases
, once
writing all the unit and integration tests, allows you to check everything
at any time, repeatedly in a fully automatic mode, for example, at each
code changes, with each merge to the base branch, with each release of a
new version, periodically the entire working system.
Which can guarantee
a high speed of release of new versions of the software product
, high quality of the code and the functionality of the released software product
, the absence of bugs
and, as a result, customer
satisfaction error-free and trouble-free operation of the system they
use, and as a result, an increase in sales of the manufactured software product
and, accordingly, an increase in profits
.
All Unit tests running in total isolation
, without connecting
to any external services, such as databases, message brokers, etc.
Which provides very high execution speed
and allows developers
to constantly run the entire unit test suite after each code
change and before each merge to the base branch.
All calls to any external services are mute
.
PHP Unit tests writing with full coverage for all test cases
.
This project has a complete PHP Unit tests with full coverage code
for all methods in:
- Controllers;
- Services;
- Repositories;
- Entities;
Running all PHP Unit Tests:
composer test-unit
or by module Application:
composer test-application-unit
or by module User:
composer test-user-unit
All Integration tests running with real connecting to all external services
, such as databases, message brokers, etc.
PHP Integration tests writing with full coverage for all test cases
.
This project has a complete PHP Integration tests for all methods in:
- Controllers;
Running all PHP Integration Tests:
composer test-integration
or by module Application:
composer test-application-integration
or by module User:
composer test-user-integration
composer test-all
With the most complete coverage of the source code on PHP.
In all modules:
In module Application:
In module User:
SonarQube is a self-managed, automatic code review tool that systematically helps deliver clean code. As a core element of Sonar solution, SonarQube integrates into existing workflow and detects issues in code to help perform continuous code inspections of projects. The tool analyses programming languages and integrates into CI pipeline and DevOps platform to ensure that code meets high-quality standards.
Writing clean code
is essential to maintaining a healthy codebase.
We define clean code as code that meets a certain defined standard,
i.e. code that is reliable, secure, maintainable, readable, and modular,
in addition to having other key attributes. This applies to all code:
source code, test code, infrastructure as code, glue code, scripts, etc.
Sonar's Clean as Code
approach eliminates many of the pitfalls that arise from
reviewing code at a late stage in the development process.
The Clean as Code
approach uses quality gate to alert/inform when there’s
something to fix or review in new code (code that has been added or changed),
allowing to maintain high standards and focus on code quality.
The Sonar solution performs checks at every stage of the development process:
- SonarLint provides immediate feedback in IDE as write code so you can find and fix issues before a commit.
- SonarQube’s PR analysis fits into CI/CD workflows with SonarQube’s PR analysis and use of quality gates.
- Quality gates keep code with issues from being released to production, a key tool in helping incorporate the Clean as Code methodology.
- The Clean as Code approach helps focus on submitting new, clean code for production, knowing that existing code will be improved over time.
With Clean as Code, your focus is always on New code
(code that has been added or
changed according to new code definition) and making sure the code write today is clean
and safe.
The New code definition can be set at different levels (global, project, and, starting
in Developer Edition, at the branch level).
Depending on the level at which your new code definition is set, you can change the
starting point to fit your situation.
Organizations start off with a default set of rules and metrics called the Sonar way
quality profile
. This can be customized per project to satisfy different technical
requirements. Issues raised in the analysis are compared against the conditions defined
in the quality profile to establish quality gate.
A quality gate
is an indicator of code quality that can be configured to give a go/no-go
signal on the current release-worthiness of the code.
It indicates whether your code is clean and can move forward:
- A passing (green) quality gate means the code meets standard and is ready to be merged.
- A failing (red) quality gate means there are issues to address.
With the Clean as You Code approach, your Quality gate should:
- Focus on
New code metrics
– When quality gate is set to focus on new code metrics (like the built-in Sonar way quality gate), new features will be delivered cleanly. As long as your quality gate is green, releases will continue to improve. - Set and enforce
high standards
– When standards are set and enforced on new code, you aren't worried about having to meet those standards in old code and having to clean up someone else's code. You can take pride in meeting high standards in your code. If a project doesn't meet these high standards, it won't pass the quality gate, and is therefore not ready to be released.
You can use pull request analysis
and pull request decoration
to make sure that code meets
standards before merging. Pull request analysis lets you see your pull request's quality
gate in the SonarQube UI. You can then decorate your pull requests with SonarQube issues
directly in your DevOps platform's interface.
SonarQube provides feedback
through its UI, email, and in decorations on pull or merge
requests to notify team that there are issues to address.
Feedback can also be obtained in SonarLint supported IDEs when running in connected mode.
SonarQube also provides in-depth guidance on the issues telling why each issue is a problem and how to fix it, adding a valuable layer of education for developers of all experience levels. Developers can then address issues effectively, so code is only promoted when the code is clean and passes the quality gate.
# Run start SonarQube (and don't close):
composer sonar-start
# Run scanner SonarQube:
composer sonar-scanner
This code is provided under the BSD-like license.
You are free to use, modify and distribute the content for non-commercial purposes. Just mention the original author and provide a link to this repo.