Introduction 09 Jun 2023
last update of "Introduction"

Hi from Arshavin. I started working on this framework since 2018. I've used it on many presentation websites, improving it continuously.

In 2022 Arshwell moved from random .zips to a GitHub repo 🎉 And one year after that it started having releases available from Composer.

Installation & Setup

  1. From terminal, in the root of your project, run composer require arshwell/monolith:0.*
    • it adds the framework files in vendor/ folder;
    • it adds the framework name in composer.json and composer.lock.
  2. After that run sh vendor/arshwell/monolith/bin/install-arshwell-example.sh
    • it copies the example project files;
    • so you have already a functional draft website.
  3. Replace, in entire project, MyTeam\MyProject, with your desired namespace
    • your desired namespace should be present also in composer.json file.
  4. Create the .env.local file
    • here should be defined env vars with specific values for every developer;
    • ex: database credentials, or even website url.
  5. Done 📢 run your website!
    • your draft website is incredible;
    • use the below steps to make it even cooler.
you're 20% done reading...

Upgrade version 09 Jun 2023
last update of "Upgrade version"

Because v0.x is in Beta, so far we don't have documentation for versions older than v0.4 🙏

We just hope you don't use a version smaller than that.

Documentation 09 Jun 2023
last update of "Documentation"

We're happy you came across these docs 🙏 Go through this chapter and you will master Arshwell framework.

Enjoy these journey by implementing in your project in the same time we're teaching you.

The Basics

Let's start from simple, right?!

Understanding tool functionality in the real world builds confidence, including in application development. Knowing how your development tools work boosts comfort and confidence.

This document gives a brief overview of the Arshwell framework to demystify it and increase your confidence in building applications. Don't worry if you don't understand all the terms right away. Focus on grasping the basics, and your knowledge will grow as you explore the rest of the documentation.

Request lifecicle

  1. The entry point for all requests to an Arshwell application is the index.php file. All requests are directed to this php file by your .htaccess configuration file.

    The index.php file serves as a minimal code base and acts as the initial entry point for loading the entire framework.
  2. It reads the data from config/ folder.
  3. It connects to database.
  4. It matches request url with one from config/forks/. So we know what page is about.
  5. It runs php files from gates/ folder.
  6. For our page, it includes the outcomes/**/backend.php file.
  7. For our page, it includes the layouts/**/layout.php file.
  8. For our page, it includes the outcomes/**/frontend.php file.
  9. The entire result (ex: HTML) is displayed to browser.

Configuration

The default structure of Arshwell websites includes configuration files stored in the config/ directory:

your-project/
│ config/
│ ├─ forks/
│ ├─ databases.json
│ ├─ development.json
│ ├─ filestorages.json
│ ├─ services.json
│ └─ web.json

  • The config/forks/ folder defines the urls of your pages.
  • The config/databases.json defines the credentials to your database(s).
  • The config/development.json defines if the possible errors are displayed to page and who can see them.
  • The config/filestorages.json defines the location for static and uploaded files.
  • The config/services.json is in BETA.
    in v1.x it'll come with awesome features.
  • The config/web.json defines the base url of your website.

Some of their values are volatile. They are different on your dev website compared to the live website (the official one).
Like database credentials and website url.

That's why you will include env vars in these config/ files, so the values can be changed anytime.
And you can define their value in your .env file.

Routing

Routes can be found in config/forks/ folder. They represent all urls the website has.

When your application receives a request, it includes outcomes/**/backend.php and outcomes/**/frontend.php files to display the HTML.
With other words, the routing configuration defines which outcomes/ php files to be included for each incoming URL.

It also provides other useful features, like generating SEO-friendly URLs (ex: /article/2/how-to-cook-chicken, instead of article.php?id=2).

For the inserting page links in your HTML, you can check Utilities > Web::class anytime you need.

Pages

A page represents any route with GET method. That's because POST requests should not have a page.

So any page is a GET request which displays a HTML code to browser.

To create a page easily you need:

  • a route
    in config/forks/ folder
  • a layout
    in layouts/ folder
  • an outcome
    in outcomes/ folder
  • a piece (optional)
    in pieces/ folder

This is the actual flow for the framework:

  1. The route specifies the url and the outcome to be used.
  2. The framework includes outcomes/**/backend.php.
  3. The outcome specifies the layout to be used.
  4. The framework includes outcomes/**/frontend.php inside the layout.
  5. Optional: the outcome includes a piece in frontend.
    in case you have a HTML code you use in many pages.

Note: most often the layout contains the header and the footer of the pages.

Modules

Because the administration area of the website most often has repetitive functionality, the Modules helps you generate sections easily for every table you need to manipulate from admin zone.

So you will define sections where there will be:

  1. listings of database table rows;
  2. forms for inserting new data;
  3. forms for updating existing data;
  4. options to delete, hide, reorder data.

you're 35% done reading...

Advanced Topics

Let's go deeper. What do you think?!

The Basics chapter presents to you how you can create static pages and how to display pages to user.

In this chapter we really take the advantage of Arshwell framework 👻

Database

The connection to database is defined in config/databases.json and can be overwritten by you from your .env.local file.
If you miss something about that, you can check anytime the The Basics > Configuration section.

In order to manipulate a table from database you just need to create a PHP class which extends the Arshwell Table class:

<?php

// in app/Table/Blog/Article.php

namespace MyNamespace\Table\Blog;

use Arshwell\Monolith\Table;

final class Article extends Table
{
    const TABLE       = 'articles';
    const PRIMARY_KEY = 'id_article';
}

You can check Utilities > Table::class anytime you need.

Sessions

You should know what sessions are. They are from PHP.

Arshwell just helps you with encapsulating them. What do we mean by that? That if you have more websites on the same domain, one website won't affect the sessions of the others.

You can check Utilities > Session::class anytime you need.

Security and Validation

Whenever is about logging in a user or validating a form data, not ommiting a strong validation is very important.
Let's not forget also about uploading forbidden files.

We have the best tool for you: Arshwell TableValidation class. Validation of every field is just too simple. It also covers default security validation.

You can check Utilities > TableValidation::class anytime you need.

Users

Validating user credentials and keeping his data in session should not be a struggle.

Arshwell Table\TableAuth class does all of that for you.
You can check more about it anytime at Utilities > Table\TableAuth::class.

This class provides all default Table features and also the user related features.
It will take care also of storing user data on session and retrieving it when you need that.

File uploads

The management of storing uploaded files, linking them to tables and updating them is boring.

Arshwell Table\TableFiles class has awesome architecture just for that.
You can check more about it anytime at Utilities > Table\TableFiles::class.

Uploads location is defined in config/filestorages.json and files are linked to the certain table rows without a struggle.

Let's say we need an image for our article. This is all we need to do:

app/Table/Blog/Article.php
<?php

namespace MyNamespace\Table\Blog;

use Arshwell\Monolith\Table;

final class Article extends Table
{
    const TABLE       = 'articles';
    const PRIMARY_KEY = 'id_article';

    const FILES = [
        'banner' => [
            'sizes' => [
                'big' => [
                    'width' => 1000,
                    'height' => 800
                ],
            ],
        ],
    ];
}

That's it. And your Article object will be able to store banner image for every DB article row.
The "big" keyword is just a shortcut name you decide to use.

The other details from Utilities chapter will show you the PHP class methods you can use for:

  • uploading files;
  • editing files;
  • getting the url for any certain file.

DevPanel

Do you need a technical overview about your project? We got you.

From DevPanel, you can do the following and more:

  • See what scss/js files every page uses;
  • Recompile the scss/js in one single file;
  • Empty PHP session;
  • Activate maintenance for the website;
  • See PHP log errors;
  • and many more...

Find out more from Utilities > DevPanel anytime you need.

you're 45% done reading...

Utilities 09 Jun 2023
last update of "Utilities"

All Arshwell classes which will save your time.

They are the core of the framework.

Web::class

You create your page links in config/forks/ files.
But you shouldn't use these plain text links in your html.

In this way, whenever you want to edit a page link, you have one single place to change it with: config/forks/.

  • Web::url() receives your route key and generates the url:
    <a href="<?= Web::url('site.blog') ?>">
        Blog
    </a>
    
    If you change the blog page link, or if you change the website domain, you don't have to edit them in the entire website, but only in config :)

Table::class

For every DB table, you just create, in your project, a class which extends this Arshwell Table::class.
The rest is magic. You will automatically have static methods for SELECT, INSERT, UPDATE, DELETE, and many more.

The SELECT method will return an object containing all wanted columns from database :D

See a very straight forward example:
1. app/Table/Blog/Article.php
<?php

namespace MyNamespace\Table\Blog;

use Arshwell\Monolith\Table;

final class Article extends Table
{
    const TABLE       = 'articles';
    const PRIMARY_KEY = 'id_article';
}
2. outcomes/site/blog/backend.php
<?php

use MyNamespace\Table\Blog\Article;

/* update in database to make invisible the articles older than 2019 */
Article::update([
    'set' => "visible = 0",
    'where' => "inserted_at < 2019-01-01",
]);

/* select from database only the articles with "visible" equals 1 */
$articles = Article::select([
    'columns' => "title, description",
    'where' => "visible = 1",
]);
3. outcomes/site/blog/frontend.php
<?php
foreach ($articles as $article) { ?>
    <a href="<?= Web::url('site.article', ['id' => $article->id()]) ?>">
        <?= $article->title() ?>
    </a>
<?php } ?>
                                            
As you can see, the articles are PHP objects. So the ::select() method did the hard job. We just enjoying it.
Note: Web::url() uses a second parameter to define the article id. Of course, the id will be added in the url.

Session::class

You will rarely use the Session class. It's a core class used the most by Arshwell. But why not to understand the benefits of it.

Managing the session data can be difficult. Especially if there are many websites in the same domain.

Here are its superpowers:

  • It encapsulates the session. So more websites on the same domain won't affect each other.
    Use $_SESSION global variable without any concern.
  • It takes care of saving user data after login. No need to do it by yourself.
    Ofc, it deletes it to logout.
  • Session::form() gives you the validation messages from a POST request.
    When the submit redirects the user back to the form, you will have access to the validation made by the POST route.

Table\TableValidation::class

For every language your site has, you create in your project a class which extends this Arshwell TableValidation::class.
Any form filled by user will be validated wonderful.

See a very straight forward example:
1. app/Validation/SiteValidation.php
<?php

namespace MyNamespace\Validation;

use Arshwell\Monolith\Table\TableValidation;

use MyNamespace\Language\LangSite;

class SiteValidation extends TableValidation {
    const TABLE         = 'validations_site';
    const PRIMARY_KEY   = NULL;

    const TRANSLATOR    = LangSite::class;
}
2. outcomes/site/contact/backend.php
<?php

use Arshwell\Monolith\Session;

/* if exists, get validation from the route which made it */
$submitResponse = Session::form('site.validation.contact')
3. outcomes/site/contact/frontend.php
<form action="<?= Web::url('site.validation.contact') ?>" method="POST">
    <input type="text" name="name" />
    <?php
    if (null != $submitResponse->error('name')) { ?>
        <span><?= $submitResponse->error('name') ?></span>
    <?php } ?>

    <input type="text" name="email" />
    <?php
    if (null != $submitResponse->error('email')) { ?>
        <span><?= $submitResponse->error('email') ?></span>
    <?php } ?>

    <textarea name="message"></textarea>
    <?php
    if (null != $submitResponse->error('message')) { ?>
        <span><?= $submitResponse->error('message') ?></span>
    <?php } ?>

    <button type="submit">Send</button>
</form>
4. outcomes/site/validation/contact.php
<?php

use Arshwell\Monolith\Web;

use MyNamespace\Table\Contact;
use MyNamespace\Validation\SiteValidation;

// validate these fields sent by html form
$response = SiteValidation::run($_POST, [
    'name' => [
        "required",
        function ($value) {
            return trim($value);
        },
        "minLength:3"
    ],
    'email' => [
        function ($value) {
            return trim($value);
        },
        "email"
    ],
    'message' => [
        function ($value) {
            return trim($value);
        },
        "maxLength:300"
    ]
]);

if ($response->valid()) {
    // save data in database contact table
    Contact::insert(
        "name, email, message",
        "?, ?, ?",
        $response->values(['name', 'email', 'message'])
    );

    /* validation won't be stored to session,
    because the data was valid */
    $response->forget();
}
else {
    /* validation will be stored to session,
    so the frontend will have access to it */
    $response->remember(true);
}

// go back to contact page
Web::goBack('site.contact');
As you can see, when a submit is made to 4. outcomes/site/validation/contact.php, if the data is invalid, validation is saved in session and displayed in 3. outcomes/site/contact/frontend.php, under every html field.
you're 70% done reading...

FAQs 09 Jun 2023
last update of "FAQs"

Before any worries, let us answer the most frequently asked questions.

Is Arshwell a good solution?

This framework is made for novice developers. It doesn't use complex concepts like MVC and dependency injection.
In this way, anybody can learn it and use very fast.

What skills should I have before using this framework?

Arshwell helps you creating web platforms. Minimum of PHP, HTML, CSS are very important. For a good fit, Javascript and SCSS are useful.
If you're in the process of learning web development, join our very low-priced online workshops.

Can I improve Arshwell?

Yes, of course. You can anytime make a Pull Request on GitHub project with your improvement.
Contributing steps can be found on GitHub Arshwell README section.

For running the changes also in the Arshwell example project, you need to copy your changes in its own vendor/arshwell/monolith.
For every modification, run sh vendor/arshwell/monolith/bin/cp-arshwell-to-example.sh in the root.
It'll copy /vendor/arshwell/monolith/ to /vendor/arshwell/monolith/example/vendor/arshwell/monolith/.

you're 80% done reading...

Coding standards 09 Jun 2023
last update of "Coding standards"

Follow these standards for a more professional coding way.

  • In PHP, for arrays, use brackets [], instead of array().
  • In PHP, for classes and methods, put the starting brace { at the next line.
  • In HTML, when you echo something, use the shorter syntax: <?= $var ?>
you're 90% done reading...

Deploy website 09 Jun 2023
last update of "Deploy website"

The live website needs another configuration than the dev one.

In order to easily deploy your project to live, use GitHub Actions workflow.
With just a GitHub .yml small file inside your project, GitHub will deploy your website, via FTP, directly to live.

The rest is miraculous. For every PR merged with the main branch, all modifications are instantly uploaded on the live web server.

For having another .env.local file on live, GitHub Workflow will let you define it easily.

you're 100% done reading