Step-by-Step Guide
This Step-by-Step Guide
is designed to help you get started with the DotApp PHP Framework
. It walks you through the core concepts, setup, and creation of your first modular application. DotApp is built with a modular philosophy, prioritizing flexibility and scalability. Follow these steps to understand its workflow and build a simple application from scratch.
Philosophy
The DotApp PHP Framework
is built with modularity at its core. From the ground up, DotApp is designed to provide a robust and scalable foundation for modern web applications, prioritizing modular architecture to ensure flexibility, maintainability, and efficiency.
Why Modular Design?
Modularity is the heart of DotApp’s philosophy. By structuring applications as a collection of independent, reusable modules, DotApp enables developers to:
- Build scalable applications with clear separation of concerns.
- Reuse components across projects, reducing development time.
- Maintain and update specific parts of an application without affecting the whole system.
- Integrate new features or third-party tools seamlessly.
This approach ensures that your projects remain organized and adaptable, whether you're building a small prototype or a large-scale enterprise application.
Robust Foundation, Recommended Practices
DotApp provides a solid foundation with tools and conventions tailored for modular development. In this guide, we focus on the recommended practices that align with DotApp’s design goals:
- Module-Centric Workflow: Organize your application into self-contained modules for clarity and scalability.
- Consistent Structure: Follow DotApp’s conventions for controllers, templates, and configurations to streamline collaboration.
- Best Practices: Leverage built-in tools for routing, templating, and module management to avoid common pitfalls.
- Future-Proofing: Build with modularity to make future expansions or refactoring effortless.
While DotApp is flexible enough to support alternative approaches, this guide emphasizes the methods that best utilize its modular architecture. We aim to teach techniques that maximize the framework’s strengths and help you avoid inefficient or error-prone patterns.
What’s Next?
Ready to start building with DotApp? Head to the Installation section to set up the framework and begin your modular journey. For a deeper dive into creating your first module, check out the First Module & Setup section.
Proudly made in Slovakia 🇸🇰
Installation
Installing the DotApp PHP Framework
is quick and flexible. Choose one of the three methods below to set up your project. Each method results in the same modular project structure, ready for development.
Option 1: Git Clone
If you have Git
installed, you can clone the DotApp repository directly. Run the following command in your terminal:
git clone https://github.com/dotsystems-sk/dotapp.git ./
This creates a DotApp project in your current directory. Don’t have Git? No problem—try one of the other methods.
Option 2: DotApper CLI
Download the dotapper.php
CLI tool and use it to install DotApp. Follow these steps:
- Download the file: dotapper.php.
- Save it to your project directory.
- Run the installation command:
php dotapper.php --install
This sets up DotApp with all necessary dependencies.
Option 3: ZIP Download
Prefer a manual approach? Download the DotApp ZIP file and extract it:
- Download the ZIP: DotApp main.zip.
- Extract the contents to your project directory.
Once extracted, your project is ready to use.
Project Structure
After installation, your project directory will have the following modular structure:
├───app
│ ├───custom.classes
│ │ └───phpmailer
│ ├───modules
│ ├───parts
│ │ ├───Controllers
│ │ ├───Middleware
│ │ ├───Models
│ │ └───views
│ ├───runtime
│ │ ├───cache
│ │ ├───generator
│ │ ├───logs
│ │ └───routercache
│ └───vendor
│ ├───bin
│ └───composer
└───assets
├───dotapp
└───modules
This structure is designed for modularity, with the modules
folder as the core of your application. You’ll notice the parts
directory contains folders like Controllers
, Middleware
, Models
, and views
. These exist to support alternative programming approaches that DotApp allows. However, this guide focuses on the recommended modular workflow, using the modules
directory to keep your application scalable and maintainable. We won’t cover non-modular techniques, as our goal is to teach the best practices for DotApp development.
What’s Next?
With DotApp installed, you’re ready to create your first module. Head to the First Module & Setup section to start building your modular application.
First Module & Setup
With the DotApp PHP Framework
installed, you’re ready to create your first module. Modules are the core of DotApp’s modular architecture, allowing you to organize your application into reusable, self-contained components. In this section, we’ll create a HelloWorld
module and configure it to handle the homepage route.
Creating the Module
Use the DotApper CLI
to generate a new module. Run the following command in your project directory:
php dotapper.php --create-module=HelloWorld
You’ll see the output:
Module successfully created in: ./app/modules/HelloWorld
This creates a new HelloWorld
module in the app/modules
directory.
Module Structure
The HelloWorld
module has the following structure:
├───modules
│ │ .gitkeep
│ │
│ └───HelloWorld
│ │ module.init.php
│ │ module.listeners.php
│ │
│ ├───Api
│ │ Api.php
│ │
│ ├───assets
│ │ howtouse.txt
│ │
│ ├───Controllers
│ │ Controller.php
│ │
│ ├───Libraries
│ ├───Middleware
│ ├───Models
│ ├───translations
│ └───views
│ │ clean.view.php
│ │
│ └───layouts
│ example.layout.php
Here’s what each file and directory is for:
module.init.php
: Defines the module’s routes and initialization conditions, controlling when and how the module is loaded.module.listeners.php
: Registers event listeners for the module, allowing it to respond to framework events like module loading.Api/Api.php
: A sample API controller for building API endpoints (can be deleted or ignored).assets/
: Stores module-specific assets like CSS, JavaScript, or images. Contains ahowtouse.txt
guide for beginners.Controllers/Controller.php
: A sample controller (can be deleted or ignored).Libraries/
: Holds custom PHP libraries or classes specific to the module.Middleware/
: Contains middleware classes for request processing, such as authentication or validation.Models/
: Stores model classes for database interactions or business logic.translations/
: Manages language files for internationalization.views/
: Contains view templates, includingclean.view.php
(a sample view) andlayouts/example.layout.php
(a sample layout), both of which can be deleted or ignored.
The sample files (Api.php
, Controller.php
, clean.view.php
, example.layout.php
) are included as examples for beginners. In this guide, we’ll create our own controller and views, so you can safely delete or ignore these files.
Configuring the Module
Let’s configure the HelloWorld
module to handle the homepage route if no other module claims it.
Step 1: Set Up Event Listeners
Open app/modules/HelloWorld/module.listeners.php
and modify the register
function to redirect the homepage (/
) to /helloworld/
if no other module defines a default route:
public function register($dotApp) {
$dotApp->on("dotapp.modules.loaded", function($moduleObj) use ($dotApp) {
if (!$dotApp->router->hasRoute("get", "/")) {
// No default route is defined, so set this module's route as the default
$dotApp->router->get("/", function() {
header("Location: /helloworld/", true, 301);
exit();
});
}
});
}
This code listens for the dotapp.modules.loaded
event, which fires after all modules are loaded. If no module has claimed the /
route, we set a redirect to /helloworld/
, making our module the default homepage.
DotApp supports several module-specific events:
dotapp.module.HelloWorld.init.start
: Fired when module initialization begins.dotapp.module.HelloWorld.init.loading
: Fired when the module’s main functions (e.g., routes) start loading, if initialization conditions are met.dotapp.module.HelloWorld.init.loaded
: Fired after the module’s routes and functions are loaded.dotapp.module.HelloWorld.init.end
: Fired when module initialization ends, regardless of whether conditions were met.
For this example, dotapp.modules.loaded
is all we need.
Step 2: Configure Module Initialization
Open app/modules/HelloWorld/module.init.php
to define when the module should activate. Modify the initializeRoutes
function to specify that the module activates for routes starting with /helloworld
:
public function initializeRoutes() {
$routes = [];
$routes[] = '/helloworld*';
return $routes;
}
This ensures the module only activates for URLs starting with /helloworld
(e.g., /helloworld
, /helloworld/
, /helloworld/sekcia
). Using ['*']
(activating for all URLs) is less efficient and not recommended for large projects, so we optimize by specifying our route prefix.
Next, configure the initializeCondition
function to determine if the module should initialize based on the route match. By default, set it to:
public function initializeCondition($routeMatch) {
return $routeMatch;
}
This activates the module whenever a route from initializeRoutes
matches (e.g., /helloworld*
). You can add custom logic to control initialization. For example, to only activate the module in 2025:
public function initializeCondition($routeMatch) {
if ($routeMatch === true) {
if (date("Y") == 2025) return true;
}
return false;
}
This checks if the route matches and the current year is 2025. For this guide, we’ll keep the default behavior (return $routeMatch;
) to activate the module whenever the route matches.
Step 3: Define Initial Routes
In the same module.init.php
file, update the initialize
function to define static routes for the module:
public function initialize($dotApp) {
// Static routes
Router::get(['/helloworld','/helloworld/'], "HelloWorld:Pages@index", Router::STATIC_ROUTE);
}
This sets up static routes for /helloworld
and /helloworld/
, pointing to the index
method of the Pages
controller in the HelloWorld
module. Specifying Router::STATIC_ROUTE
optimizes performance by avoiding dynamic route matching (unlike the default Router::DYNAMIC_ROUTE
).
What’s Next?
Your HelloWorld
module is now created and configured. Next, we’ll create the Pages
controller to handle the /helloworld
route. Head to the First Controller section to continue.
First Controller
With your HelloWorld
module configured, it’s time to create a controller to handle the /helloworld
route. In the DotApp PHP Framework
, controllers manage the logic for specific routes within a module. In this section, we’ll create the Pages
controller to prepare for our first "Hello World" output.
Creating the Controller
Use the DotApper CLI
to generate the Pages
controller for the HelloWorld
module. Run the following command in your project directory:
php dotapper.php --module=HelloWorld --create-controller=Pages
You’ll see the output:
Controller 'Pages' successfully created!
This creates a new controller file at app/modules/HelloWorld/Controllers/Pages.php
.
Setting Up the Controller
Open app/modules/HelloWorld/Controllers/Pages.php
and add the index
method to handle the /helloworld
route we defined in the module.init.php
file. Replace the file’s controller class contents with the following code:
public static function index($request)
{
return "<h1>Hello World !</h1>";
}
This code does the following:
- Defines the
Pages
controller in theDotApp\Modules\HelloWorld\Controllers
namespace. - Adds a static
index
method that takes a$request
parameter and returns a simple HTML string:<h1>Hello World !</h1>
.
The index
method is linked to the /helloworld
and /helloworld/
routes via the Router::get
call in module.init.php
from the previous section. When these routes are accessed, this method will execute and output the "Hello World" message.
What’s Next?
Your Pages
controller is now set up to handle the /helloworld
route. In the next section, we’ll test the application to see the "Hello World" output in action. Head to the Hello World section to complete the setup and view your first DotApp page.
Hello World
Your HelloWorld
module and Pages
controller are now set up in the DotApp PHP Framework
. In this section, we’ll test the application to see your first "Hello World" page in action, confirming that everything works as expected.
Testing Your Application
To see your "Hello World" output, you need a web server running with PHP. If you haven’t set one up yet, you can use PHP’s built-in development server for testing. Run the following command in your project directory:
php -S 127.0.0.1:8000
This starts a server on http://127.0.0.1:8000
. Alternatively, use your preferred server setup (e.g., Apache, Nginx) with the project directory as the document root.
Viewing the Hello World Page
Open your browser and navigate to http://127.0.0.1:8000/
(or your server’s address). You’ll be redirected to http://127.0.0.1:8000/helloworld/
, where you’ll see:
<h1>Hello World !</h1>
This output comes from the index
method in app/modules/HelloWorld/Controllers/Pages.php
, which we set up in the First Controller section. The redirect from /
to /helloworld/
is handled by the event listener in module.listeners.php
, configured in the First Module & Setup section.
Understanding the Flow
Here’s how it all comes together:
- The
HelloWorld
module is activated for routes starting with/helloworld
, as defined inmodule.init.php
. - If no other module claims the homepage (
/
), the event listener inmodule.listeners.php
redirects to/helloworld/
. - The
/helloworld/
route is mapped to thePages
controller’sindex
method via the static route inmodule.init.php
. - The
index
method returns the HTML stringHello World !
which is displayed in the browser.
This modular workflow showcases DotApp’s simplicity and power, allowing you to build scalable applications with clear, reusable components.
Congratulations
You’ve built and tested your first DotApp application. Next, explore the template system to create dynamic views. Head to the Introduction to Template System section to learn how to enhance your application with templates.
Introduction to Template System
The DotApp PHP Framework
includes a powerful templating system that simplifies creating dynamic, reusable views for your modular applications. In this section, we’ll explore the basics of DotApp’s templating system, including views, layouts, and variables, to prepare you for building dynamic pages.
What is the Templating System?
DotApp’s templating system allows you to separate presentation logic from business logic, making your application easier to maintain and scale. It consists of:
- Views: PHP files (e.g.,
helloworld.view.php
) that contain HTML, dynamic content, and multiple layouts, rendered for specific routes. - Layouts: Reusable templates (e.g.,
h1-test.layout.php
) included within views, providing modular components like headers, footers, or sections. - Variables: Data passed from controllers to views/layouts using the
Renderer
class, accessible via{{ var: $variableName }}
. - Form Handling: Built-in tools like
{{ formName(name) }}
and{{ CSRF }}
for secure form processing.
Views and layouts are stored in the views
directory of a module (e.g., app/modules/HelloWorld/views
), with layouts often organized in a layouts
subfolder for clarity.
Key Features
The templating system is designed for flexibility and security:
- Dynamic Rendering: Use the
Renderer
class to load views, set variables, and render output. - Multiple Layout Inclusion: A single view can include multiple layouts using
{{ layout: layoutName }}
, with support for subfolders (e.g.,{{ layout: subfolder/layoutName }}
). - Secure Forms: Use
{{ formName(name) }}
to name and secure forms, enhancing CSRF protection. - Modular Design: Templates are module-specific, keeping your application organized and reusable.
What’s Next?
In the next section, we’ll extend our HelloWorld
module to use the templating system, adding a dynamic form and rendering it with a view and layout. Head to the Hello World in Template System section to see it in action.
Hello World in Template System
Let’s enhance our HelloWorld
module to use the DotApp PHP Framework
templating system. We’ll add a new route, create a view and layout, and update the controller to render a dynamic form. This example demonstrates how to combine views, layouts, and secure form handling.
Step 1: Add a New Route
Open app/modules/HelloWorld/module.init.php
and add a dynamic route for /helloworld2
. Append the following line to the initialize
function:
Router::match(['get','post'],"/helloworld2(?:/)?","HelloWorld:Pages@index2");
This dynamic route handles both GET and POST requests for /helloworld2
or /helloworld2/
, pointing to the index2
method of the Pages
controller. Dynamic routes (the default) use regular expressions for flexibility, unlike the static routes used previously.
Step 2: Create the View
Create a new file named helloworld.view.php
in app/modules/HelloWorld/views/
. Add the following code:
{{ layout:h1-test }}
<br>
<br>
<h2>Form test:</h2>
<br>
<form class="search-form" method="POST">
<input type="text" placeholder="Enter text to display" name="displaytext">
{{ formName(testFormName) }}
<!--
Using only {{ CSRF }} is not recommended, but it is your choice.
I suggest using formName, for example formName(testFormName), which provides much stronger protection against attacks than a regular CSRF.
On the processing side, you then verify $request->form(['POST'],"testFormName"...
This function is used to distinguish forms by name, but it adds strong security,
so even if you don't need to differentiate forms by name, use it to secure the form.
-->
<button type="submit" class="btn search-btn">{{ var: $btnText }}</button>
</form>
<!--
$_GET, $_POST, etc. are already protected against XSS, code injection, and similar attacks.
To remove protection: DotApp::DotApp()->unprotect($displayText); // Recursively unprotects the variable (supports arrays, references, etc.)
Do NOT assign the result! The function modifies the variable by reference.
-->
{{ var: $displayText }}
{{ var: $securityData }}
This view includes:
{{ layout:h1-test }}
: Loads theh1-test
layout.- A form with a text input, a secure form name (
{{ formName(testFormName) }}
), and a submit button using a variable ({{ var: $btnText }}
). - Variables (
{{ var: $displayText }}
,{{ var: $securityData }}
) to display form output.
Step 3: Create the Layout
Create a new file named h1-test.layout.php
in app/modules/HelloWorld/views/layouts/
. Add the following code:
<h1>{{ var: $testVar }}</h1>
This layout displays a variable ({{ var: $testVar }}
) as an h1
heading. Layouts can be organized in subfolders (e.g., {{ layout:subfolder/h1-test }}
loads views/subfolder/h1-test.layout.php
).
Step 4: Update the Controller
Open app/modules/HelloWorld/Controllers/Pages.php
and add the index2
method below the existing index
method:
public static function index2($request, Renderer $renderer) {
/*
Request::form() facade for $request->form() (use Dotsystems\App\Parts\Request;)
$request->form(string "testFormName", success_callback, error_callback)
$request->form(array "method", string "testFormName", success_callback, error_callback)
success_callback - main logic
error_callback - data manipulation detected
*/
$displayText = "";
$securityData = "";
// Verify the form's origin by its name (since we only process the form for POST, specify the POST method)
$request->form(['POST'], "testFormName", function($request) use (&$displayText, &$securityData) {
$displayText = '<h3>'.$request->data()['displaytext']."</h3>";
$securityData = '<hr>Your data was secured using: <pre>'.print_r($request->data(), true)."</pre>";
});
$testVar = "Hello World";
$btnText = "Send";
// $renderer is obtained via dependency injection Renderer $renderer
$rendered1 = $renderer->module(self::moduleName()) // Set to use views and layouts from the current module
->setView("helloworld") // Select the view (/app/modules/HelloWorld/views/helloworld.view.php)
->setViewVar("testVar", $testVar) // Create variable $testVar available in the view and all nested layouts
->setViewVar("btnText", $btnText) // Create variable $btnText available in the view and all nested layouts
->setViewVar("displayText", $displayText) // Create variable $displayText available in the view and all nested layouts
->setViewVar("securityData", $securityData) // Create variable $securityData available in the view and all nested layouts
->renderView();
return($rendered1);
}
This method:
- Processes the form using
$request->form
, validating the form name (testFormName
) and POST method. - Sets variables (
$testVar
,$btnText
,$displayText
,$securityData
) for the view. - Uses the
Renderer
to load thehelloworld
view, assign variables, and render the output.
Testing the Template System
Ensure your server is running (e.g., php -S 127.0.0.1:8000
). Open http://127.0.0.1:8000/helloworld2
in your browser. You’ll see a form with a "Hello World" heading (from the layout). Enter text, submit the form, and the page will display the submitted text and security data below the form, rendered securely.
Great !
You’ve now built a dynamic page using DotApp’s templating system, complete with a secure form and modular structure. To explore more features, check out the full DotApp Documentation or experiment with additional views, layouts, and modules in your HelloWorld
project.
Try It Live
You’ve built the HelloWorld
module and explored the DotApp PHP Framework
templating system. Now, you can see the results in action without setting up a local server! The HelloWorld
module from this guide is deployed and active on our demo server. Try it out to experience the framework’s modular design firsthand.
Test the Hello World Page
Visit the following URL to see the basic "Hello World" output from the Hello World section:
https://dotapp.dev/helloworld
Click here to visit https://dotapp.dev/helloworld
This page displays <h1>Hello World !</h1>
, served by the Pages
controller’s index
method.
Test the Templated Form
To explore the dynamic form from the Hello World in Template System section, visit:
https://dotapp.dev/helloworld2
Click here to visit https://dotapp.dev/helloworld2
This page renders a form using the helloworld.view.php
view and h1-test.layout.php
layout. Enter text, submit the form, and see the secure output, powered by DotApp’s templating system and form handling.
Why Try It Live?
Testing the live demo helps you:
- Verify the module’s functionality without local setup.
- Understand how DotApp’s modular architecture works in a real environment.
- Experiment with the form to see secure data processing in action.
What’s Next?
Now that you’ve seen the HelloWorld
module live, dive deeper into the DotApp PHP Framework
by exploring advanced features, creating new modules, or customizing templates. Visit the full DotApp Documentation for more guides and examples to continue your journey.