From 5e3cca8a6eecfa5c4b606a39d9b44b2a73db64fe Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Thu, 11 Apr 2024 19:11:32 +0100 Subject: [PATCH 01/14] Update docs to v4 Signed-off-by: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> --- installation.md | 117 +++++++++++++------------ php-coding-guidelines.md | 182 ++++++++++++++++++++++++++------------- upgrade-guide.md | 161 +++++++++++++++++++++------------- 3 files changed, 283 insertions(+), 177 deletions(-) diff --git a/installation.md b/installation.md index e61ed31..9b89450 100644 --- a/installation.md +++ b/installation.md @@ -4,38 +4,73 @@ section: "getting-started" sortOrder: 10 --- -Before you proceed with installing TastyIgniter, you should check that your server meets the minimum system -requirements. +As of Version 4, TastyIgniter can be installed as a stand-alone application, or as a package inside an existing Laravel +application. -## Minimum Requirements +## Stand-alone Installation -These are the requirements for your web hosting to run TastyIgniter: +### Requirements + +These are the requirements to run TastyIgniter: - **Apache** (with mod_rewrite enabled) or **Nginx** -- **MySQL 5.7+** or **MariaDB 10.0.5+** or **PostgreSQL 9.6** -- **PHP 8.0+** with the following extensions: pdo_mysql, curl, openssl, dom, gd, mbstring, json, tokenizer, zip +- **PHP 8.2+** with the following extensions: bcmath, pdo_mysql, ctype, curl, openssl, dom, gd, exif, mbstring, json, + tokenizer, zip, xml +- **MySQL 5.7+** or **MariaDB 10.3+** or **PostgreSQL 10.0** - **Composer 2.0** or **higher** (for installing dependencies) -## Installing TastyIgniter +### Installing TastyIgniter -TastyIgniter manages its dependencies and extensions using composer. To install the platform, use the `create-project` command in the terminal to create a project. The command below creates a new project in the directory `mytasty`. +TastyIgniter manages its dependencies and extensions using +composer. To install the platform, use the `create-project` command in the terminal to create a project. The command +below creates a new project in the directory `mytasty`. ```bash composer create-project tastyigniter/tastyigniter mytasty ``` -After running the above command, run the installation command and follow the instructions to complete installation +From here, you can move on to the [Setting up TastyIgniter](#setting-up-tastyigniter) step. + +## Package Installation + +### Requirements + +These are the requirements to run TastyIgniter: + +- **Laravel 10+** +- **MySQL 5.7+** or **MariaDB 10.3+** or **PostgreSQL 10.0** +- **Composer 2.0** or **higher** (for installing dependencies) + +### Installing TastyIgniter + +To install TastyIgniter as a package from your command line, run the following command in your Laravel project +directory: + +```bash +composer require tastyigniter/core +``` + +From here, you can move on to the [Setting up TastyIgniter](#setting-up-tastyigniter) step. + +## Setting up TastyIgniter + +TastyIgniter comes packaged with a command-line setup utility that will get you up and running in a few minutes. It will +attempt to automatically configure TastyIgniter and create an admin user account. + +In the TastyIgniter installation's root directory, run the following command: ```bash php artisan igniter:install ``` -The installation command will guide you through the process of setting up TastyIgniter for the first time. It will ask +The setup command will guide you through the process of setting up TastyIgniter for the first time. It will ask for the database configuration, application URL and administrator details. -**Command-line unattended installation** +> You can safely run the command multiple times if needed. -Some installations require an unattended mode so that the application can easily be built into automated infrastructure +**Command-line unattended setup** + +Some setup require an unattended mode so that the application can easily be built into automated infrastructure pipelines and build tools, e.g. Docker. To run this, its similar to the above command, just instead we provide all of the option values up-front within the @@ -45,30 +80,10 @@ projects ```bash php artisan igniter:install --no-interaction ``` -### Wizard Installation - -1. [Download](https://github.com/tastyigniter/setup/archive/master.zip) and unzip the TastyIgniter setup wizard into an - empty directory on your server. -2. Create a MySQL user database for TastyIgniter on your database server. -3. Upload the TastyIgniter folders and files to your server. Normally the setup.php file will be at the web root - directory. -4. Grant write permissions on the setup directory, its subdirectories and files. -4. Run the TastyIgniter setup script by accessing setup.php in your web browser. Example, http://example.com/setup.php - or http://example.com/folder/setup.php -5. Follow all onscreen instructions and make sure all installation requirements are checked. - -TastyIgniter setup wizard screenshot ## Post-installation steps -For security reasons, if you used the [Quick Installation Setup Wizard](#quick-installation), you should delete the -setup files. TastyIgniter will never automatically delete files from your system, so these files and directories should -be deleted manually: - -```yaml -setup/ <== Setup directory -setup.php <== Setup script -``` +There are some things you may need to set up after the installation is complete. ### Setting up the task scheduler @@ -83,7 +98,8 @@ Be sure to replace `/path/to/artisan` with the absolute path to the artisan file This Cron will call the command scheduler every minute. When executing the `schedule:run` command, TastyIgniter will assess your scheduled tasks and run the tasks that are due. -> Task Scheduling is how scheduling time-based tasks are managed in TastyIgniter. Several core features of TastyIgniter, such as checking for updates, use the scheduler. +> Task Scheduling is how scheduling time-based tasks are managed in TastyIgniter. Several core features of TastyIgniter, +> such as checking for updates, use the scheduler. ### Setting up the queue daemon @@ -144,22 +160,22 @@ As an example, your site conf file should look something like: ```html server { - listen 80; +listen 80; - root /path/to/tastyigniter; - index index.php; +root /path/to/tastyigniter; +index index.php; - server_name mytastysite.com; +server_name mytastysite.com; - gzip on; - gzip_proxied expired no-cache no-store private auth; - gzip_types text/plain text/css application/x-javascript application/json application/javascript image/x-icon image/png image/gif image/jpeg image/svg+xml; +gzip on; +gzip_proxied expired no-cache no-store private auth; +gzip_types text/plain text/css application/x-javascript application/json application/javascript image/x-icon image/png image/gif image/jpeg image/svg+xml; - charset utf-8; +charset utf-8; - access_log off; +access_log off; - include /path/to/tastyigniter/.nginx.conf; +include /path/to/tastyigniter/.nginx.conf; } ``` @@ -187,19 +203,6 @@ token is used to check that the authenticated user is the one who actually makes Although CSRF security is enabled by default, you can disable it in the `config/system.php` configuration file using the `enableCsrfProtection` parameter. -### Bleeding edge updates - -TastyIgniter core and some marketplace extensions will introduce changes in two stages to ensure overall stability and -integrity of the codebase. This means that besides the regular stable versions, they do have a test version. - -Replace the default TastyIgniter requirements in your `composer.json` file with the following to receive updates from -the develop branch directly. - -```json -"tastyigniter/flame": "dev-develop as 1.0", -"laravel/framework": "6.0.*@dev", -``` - ## Getting Started You can access the administrator panel from `/admin` with your username and password asked during the setup process. diff --git a/php-coding-guidelines.md b/php-coding-guidelines.md index 6c6b4fd..062d987 100644 --- a/php-coding-guidelines.md +++ b/php-coding-guidelines.md @@ -6,11 +6,14 @@ sortOrder: 360 **Consistency is key** -Coding Standards are critical for achieving high code quality. We can produce a homogeneous code that is easy to read and maintain by using a consistent visual style, naming conventions, and other technical settings. +Coding Standards are critical for achieving high code quality. We can produce a homogeneous code that is easy to read +and maintain by using a consistent visual style, naming conventions, and other technical settings. ## General PHP Rules -Code style must follow [PSR-1](http://www.php-fig.org/psr/psr-1/), [PSR-2](http://www.php-fig.org/psr/psr-2/) and [PSR-12](https://www.php-fig.org/psr/psr-12/). Generally speaking, everything string-like (except Model attributes) should use camelCase. Detailed examples on these are spread throughout the guide in their relevant sections. +Code style must follow [PSR-1](http://www.php-fig.org/psr/psr-1/), [PSR-2](http://www.php-fig.org/psr/psr-2/) +and [PSR-12](https://www.php-fig.org/psr/psr-12/). Generally speaking, everything string-like (except Model attributes) +should use camelCase. Detailed examples on these are spread throughout the guide in their relevant sections. #### Class defaults @@ -32,35 +35,84 @@ public ?string $variable; public string|null $variable; ``` +#### Void return types + +If a method returns nothing, it should be indicated with void. This makes it more clear to the users of your code what +your intention was when writing it. + +```php +// in a Laravel model +public function scopeArchived(Builder $query): void +{ + $query-> + ... +} +``` + +#### Typed properties + +You should type a property whenever possible. Don't use a docblock. + +```php +class Foo +{ + public string $bar; +} +``` + +```php +class Foo +{ + /** @var string */ + public $bar; +} +``` + +#### Enums + +Values in enums should use PascalCase. + +```php +enum Suit { + case Clubs; + case Diamonds; + case Hearts; + case Spades; +} + +Suit::Diamonds; +``` + ## Naming Convention -Naming things is often seen as one of the harder things in programming. That's why we've established some high level guidelines for naming classes. +Naming things is often seen as one of the harder things in programming. That's why we've established some high level +guidelines for naming classes. Also, follow naming conventions accepted by Laravel community: -| What | How | Good | Bad -|-------|-------|--------|----------------- -**Controller** | plural | `ArticlesController` | `ArticleController` -**Route** | plural | `articles/1` | `article/1` -**Model** | singular | `User` | `Users` -**Table** | plural | `article_comments` | `article_comment, articleComments` -**Pivot table** | singular model names | `article_user` | `articles_users` -**Table column** | snake_case without model name | `meta_title` | `MetaTitle, article_meta_title` -**Foreign key** | singular model name with _id suffix | `article_id` | `ArticleId, id_article, articles_id` -**Primary key** | - | `id` | `custom_id` -**Migration** | - | `2017_01_01_000000_create_articles_table` | `2017_01_01_000000_articles` -**Method** | camelCase | `getAll` | `get_all` -**Function** | snake_case | `abort_if` | `abortIf` -**Method in test class** | camelCase | `testGuestCannotSeeArticle` | `test_guest_cannot_see_article` -**Model property** | snake_case | `$model->model_property` | `$model->modelProperty` -**Variable** | camelCase | `$anyOtherVariable` | `$any_other_variable` -**Collection** | descriptive, plural | `$activeUsers = User::active()->get()` | `$active, $data` -**Object** | descriptive, singular | `$activeUser = User::active()->first()` | `$users, $obj` -**Config and language files index** | snake_case | `articles_enabled` | `ArticlesEnabled, articles-enabled` -**View file name** | kebab-case | `show-filtered.blade.php` | `showFiltered.blade.php, show_filtered.blade.php` -**Config file name** | kebab-case | `google-calendar.php` | `googleCalendar.php, google_calendar.php` -**Contract (interface)** | adjective or noun | `Authenticatable` | `AuthenticationInterface, IAuthentication` -**Trait** | adjective | `Notifiable` | `NotificationTrait` +| What | How | Good | Bad +|-------------------------------------|-------------------------------------|-------------------------------------------|--------------------------------------------------- + **Controller** | plural | `ArticlesController` | `ArticleController` + **Route** | plural | `articles/1` | `article/1` + **Model** | singular | `User` | `Users` + **Table** | plural | `article_comments` | `article_comment, articleComments` + **Pivot table** | singular model names | `article_user` | `articles_users` + **Table column** | snake_case without model name | `meta_title` | `MetaTitle, article_meta_title` + **Foreign key** | singular model name with _id suffix | `article_id` | `ArticleId, id_article, articles_id` + **Primary key** | - | `id` | `custom_id` + **Migration** | - | `2017_01_01_000000_create_articles_table` | `2017_01_01_000000_articles` + **Method** | camelCase | `getAll` | `get_all` + **Function** | snake_case | `abort_if` | `abortIf` + **Method in test class** | camelCase | `testGuestCannotSeeArticle` | `test_guest_cannot_see_article` + **Model property** | snake_case | `$model->model_property` | `$model->modelProperty` + **Variable** | camelCase | `$anyOtherVariable` | `$any_other_variable` + **Collection** | descriptive, plural | `$activeUsers = User::active()->get()` | `$active, $data` + **Object** | descriptive, singular | `$activeUser = User::active()->first()` | `$users, $obj` + **Config and language files index** | snake_case | `articles_enabled` | `ArticlesEnabled, articles-enabled` + **View file name** | kebab-case | `show-filtered.blade.php` | `showFiltered.blade.php, show_filtered.blade.php` + **Config file name** | kebab-case | `google-calendar.php` | `googleCalendar.php, google_calendar.php` + **Contract (interface)** | adjective or noun | `Authenticatable` | `AuthenticationInterface, IAuthentication` + **Trait** | adjective | `Notifiable` | `NotificationTrait` ### Jobs @@ -102,30 +154,31 @@ $request->input('name'); Consider using helpers instead of facades. They can clean up your code. -Common syntax | Shorter and more readable syntax ----------------|------------------------------------ -`Session::get('foo')` | `session('foo')` -`$request->session()->get('foo')` | `session('foo')` -`Session::put('foo', $data)` | `session(['foo' => $data])` -`$request->input('name'),Request::get('name')` | `$request->name,request('name')` -`return Redirect::back()` | `return redirect()->back()` -`is_null($object->relation) ? $object->relation->id : null;` | `optional($object->relation)->id` -`return view('index')->with('title', $title)->with('client', $client)` | `return view('index', compact('title', 'client'))` -`$request->has('value') ? $request->value : 'default';` | `$request->get('value','default')` -`Carbon::now(), Carbon::today()` | `now(), today()` -`App::make('Class')` | `app('Class')` -`->where('column', '=', 1)` | `->where('column', 1)` -`->orderBy('created_at', 'desc')` | `->latest()` -`->orderBy('age', 'desc')` | `->latest('age')` -`->orderBy('created_at', 'asc')` | `->oldest()` -`->select('id', 'name')->get()` | `->get(['id', 'name'])` -`->first()->name` | `->value('name')` + Common syntax | Shorter and more readable syntax +------------------------------------------------------------------------|---------------------------------------------------- + `Session::get('foo')` | `session('foo')` + `$request->session()->get('foo')` | `session('foo')` + `Session::put('foo', $data)` | `session(['foo' => $data])` + `$request->input('name'),Request::get('name')` | `$request->name,request('name')` + `return Redirect::back()` | `return redirect()->back()` + `is_null($object->relation) ? $object->relation->id : null;` | `optional($object->relation)->id` + `return view('index')->with('title', $title)->with('client', $client)` | `return view('index', compact('title', 'client'))` + `$request->has('value') ? $request->value : 'default';` | `$request->get('value','default')` + `Carbon::now(), Carbon::today()` | `now(), today()` + `App::make('Class')` | `app('Class')` + `->where('column', '=', 1)` | `->where('column', 1)` + `->orderBy('created_at', 'desc')` | `->latest()` + `->orderBy('age', 'desc')` | `->latest('age')` + `->orderBy('created_at', 'asc')` | `->oldest()` + `->select('id', 'name')->get()` | `->get(['id', 'name'])` + `->first()->name` | `->value('name')` ## Docblocks Don't use docblocks for methods that can be fully type hinted (unless you need a description). -Only add a description when it provides more context than the method signature itself. Use full sentences for descriptions, including a period at the end. +Only add a description when it provides more context than the method signature itself. Use full sentences for +descriptions, including a period at the end. **Good:** @@ -181,7 +234,8 @@ Always use fully qualified class names in docblocks. */ ``` -Using multiple lines for a docblock, might draw too much attention to it. When possible, docblocks should be written on one line. +Using multiple lines for a docblock, might draw too much attention to it. When possible, docblocks should be written on +one line. **Good:** @@ -212,7 +266,8 @@ If a variable has multiple types, the most common occurring type should be first ## Comments -Comments should be avoided as much as possible by writing expressive code. If you do need to use a comment, format it like this: +Comments should be avoided as much as possible by writing expressive code. If you do need to use a comment, format it +like this: ```php // There should be a space before a single line comment. @@ -254,7 +309,8 @@ if (count((array) $builder->getQuery()->joins) > 0) ## Whitespace -Statements should be allowed to breathe. In general always add blank lines between statements, unless they're a sequence of single-line equivalent operations. This isn't something enforceable, it's a matter of what looks best in its context. +Statements should be allowed to breathe. In general always add blank lines between statements, unless they're a sequence +of single-line equivalent operations. This isn't something enforceable, it's a matter of what looks best in its context. **Good:** @@ -424,7 +480,8 @@ use Config; ## Traits -Each applied trait should go on its own line, and the `use` keyword should be used for each of them. This will result in clean diffs when traits are added or removed. +Each applied trait should go on its own line, and the `use` keyword should be used for each of them. This will result in +clean diffs when traits are added or removed. **Good:** @@ -489,7 +546,8 @@ if ($condition) ### Happy path -Generally a function should have its unhappy path first and its happy path last. In most cases this will cause the happy path being in an unindented part of the function which makes it more readable. +Generally a function should have its unhappy path first and its happy path last. In most cases this will cause the happy +path being in an unindented part of the function which makes it more readable. **Good:** @@ -513,7 +571,8 @@ throw new Exception; ### Avoid else -In general, `else` should be avoided because it makes code less readable. In most cases it can be refactored using early returns. This will also cause the happy path to go last, which is desirable. +In general, `else` should be avoided because it makes code less readable. In most cases it can be refactored using early +returns. This will also cause the happy path to go last, which is desirable. **Good:** @@ -601,7 +660,7 @@ Configuration files must use kebab-case. ```html config/ - pdf-generator.php +pdf-generator.php ``` Configuration keys must use snake_case. @@ -613,7 +672,8 @@ return [ ]; ``` -Avoid using the `env` helper outside of configuration files. Create a configuration value from the `env` variable like above. +Avoid using the `env` helper outside of configuration files. Create a configuration value from the `env` variable like +above. **Good:** @@ -663,7 +723,8 @@ php artisan delete-old-records php artisan deleteOldRecords ``` -A command should always give some feedback on what the result is. Minimally you should let the `handle` method spit out a comment at the end indicating that all went well. +A command should always give some feedback on what the result is. Minimally you should let the `handle` method spit out +a comment at the end indicating that all went well. ```php // in a Command @@ -675,7 +736,9 @@ public function handle() } ``` -When the main function of a result is processing items, consider adding output inside of the loop, so progress can be tracked. Put the output before the actual process. If something goes wrong, this makes it easy to know which item caused the error. +When the main function of a result is processing items, consider adding output inside of the loop, so progress can be +tracked. Put the output before the actual process. If something goes wrong, this makes it easy to know which item caused +the error. At the end of the command, provide a summary on how much processing was done. @@ -717,7 +780,8 @@ Minimize usage of vanilla PHP in Blade templates. ## Validation -When using multiple rules for one field in a form request, avoid using |, always use array notation. Using an array notation will make it easier to apply custom rule classes to a field. +When using multiple rules for one field in a form request, avoid using |, always use array notation. Using an array +notation will make it easier to apply custom rule classes to a field. **Good:** @@ -771,7 +835,8 @@ $request->validate([ ## Eloquent over raw SQL queries -Eloquent is preferred over Query Builder and raw SQL queries. Eloquent allows you to write code that is both readable and maintainable. Eloquent has great built-in tools like soft deletes, events, scopes etc. +Eloquent is preferred over Query Builder and raw SQL queries. Eloquent allows you to write code that is both readable +and maintainable. Eloquent has great built-in tools like soft deletes, events, scopes etc. **Good:** @@ -843,6 +908,5 @@ $users = User::with('profile')->get(); $users = User::all() ``` - ___ -The above are sections taken from the [Spatie PHP Code Guidelines](https://spatie.be/guidelines/laravel-php). \ No newline at end of file +The above are sections taken from the [Spatie PHP Code Guidelines](https://spatie.be/guidelines/laravel-php). diff --git a/upgrade-guide.md b/upgrade-guide.md index 3bcc767..32333a2 100644 --- a/upgrade-guide.md +++ b/upgrade-guide.md @@ -1,104 +1,143 @@ --- -title: "Upgrade Guide" +title: "Upgrade from v3.x" section: "getting-started" sortOrder: 30 --- -> As of TastyIgniter 2.0 or later, When a new version of TastyIgniter is available you will receive an update message in your TastyIgniter Admin Panel. All you have to do to update TastyIgniter is to click the **Update** notification button at the right top. After that you will be redirected to the **Update Center** page. +The following is an instructional guide on how to upgrade your v3.x TastyIgniter installation to the latest version v4.x -There are two methods for updating - the easiest is through the **Update Center**, which will work in most cases. -If it doesn't work, or you just prefer to be more hands-on, you can follow the manual update process. +TastyIgniter has been rewritten as an installable Laravel package. This is a huge change that affects almost +every part of the codebase. -## Upgrading TastyIgniter v2.1.x to v3.x.x +## Backing Up The Database -This is a huge release. It contains a massive change in the codebase from CodeIgniter to Laravel with some new features -and plenty bug fixes. +Use this command to backup your MySQL database. For example, if the username is `root` and the database is called +`database_name`. You will then be prompted to enter the password. -Listing all the improvements in v3 would be great but its a lot I lost track. So straight to upgrade! +```bash +mysqldump -u root -p database_name > tastyigniter_backup.sql +``` -1. Follow the back up TastyIgniter steps below to back up your files and database. -2. Delete all your existing v2+ files -3. Follow the [quick installation](installation#quick-installation) instructions to install a fresh instance of v3.x.x -4. Make sure you enter the credentials for the database where your v2 data are stored, to upgrade the data structure. -5. Access your newly upgraded website. +To restore the backup, you can use this command. +```bash +mysql -u root -p database_name < tastyigniter_backup.sql +``` +## New requirements -## Upgrading TastyIgniter v2.0.x to v2.1.x +- **PHP 8.2+** with the following extensions: bcmath, pdo_mysql, ctype, curl, openssl, dom, gd, exif, mbstring, json, + tokenizer, zip, xml +- **MySQL 5.7+** or **MariaDB 10.3+** or **PostgreSQL 10.0** -{{alerts.callout_info}}After UPDATE make sure your layout modules are displaying on the storefront. You can use the new layout modules drag and drop under Design > Layouts.{{alerts.end}} +## Upgrading from v3.x -## Back up TastyIgniter +> Before you get started, it's a good idea to back up your website. This means if there are any issues you can restore +> your website. -Before you get started, it's a good idea to back up your website. This means if there are any issues you can restore your website. +Install TastyIgniter 4.0 in a new directory -### Backing Up Your Database -Visit your TastyIgniter admin page at /admin. Go to `Maintenance` under `System -> Tools` and `Select tables to backup` then click the `Backup` button. On the next page, make sure `Add DROP TABLE statement` is `No`, click the `Backup` button again and your backed up database file will appear under the `Exisiting Backups` Tab. You can download and keep the file on your computer. +```bash +composer create-project tastyigniter/tastyigniter mytasty-new +``` -### Backing Up Your TastyIgniter Site -Backup your files using FTP clients or cPanel file manager to copy or create a zip of all the existing TastyIgniter files and folders. +To make the configuration process run smoothly, you can copy your old configuration to the new website. This step is +optional -{{alerts.warning}}The upgrade process will affect all files and folders included in the TastyIgniter installation. This includes all the core files used to run TastyIgniter. If you have made any modifications to those files, your changes will be lost.{{alerts.end}} +```bash +cp mytasty/.env mytasty-new/ +``` -### Restoring Your Database From Backup -Visit your TastyIgniter admin maintenance page. Under `Exisiting Backups` tab click the `Restore` button next to the database backup you wish to restore. +To avoid broken media, you can either copy or move the `assets/media` directory to the storage directory on the new +installation. -## Manual Update +```bash +cp assets/media storage/ +``` -If the one-click upgrade doesn't work for you, don't panic! Just try a manual update. +If you have custom extensions and themes you have developed yourself, you can copy them to the new installation after +upgrade is complete. -### **Step 1:** Replace TastyIgniter files -1. Get the [latest TastyIgniter](https://tastyigniter.com/download) zip file -2. Unpack the downloaded zip file -3. Open the unpacked folder `TastyIgniter-2.x.x` -4. Locate and `delete` the `database.php` file in `system/tastyigniter/config/` folder -5. Using your FTP client, upload all the files and folders inside the `TastyIgniter-2.x.x` folder to your web host. Uploading all the files might take a few minutes on the FTP client. -6. Do NOT replace/overwrite your existing `system/tastyigniter/config/database.php` file. +Proceed through the installation and database migration. Change directory to the new installation and running the +installation command. -### **Step 2:** Update your installation -After uploading the files of the new version to your web host, visit the setup page at "/setup" like: www.myrestaurant.com/setup. Following the instructions on the setup page will update your database to be compatible with the latest code. +```bash +cd mytasty-new +php artisan igniter:install +``` -{{alerts.warning}}Warning: DO NOT proceed if you see the Database page asking you to enter your database details, this means your old database.php file has changed. Fix this by restoring your old database.php file then return to Step 1{{alerts.end}} +Finally, complete the upgrade, replace the old installation directory with the new installation. +```bash +cd .. +mv mytasty mytasty-old +mv mytasty-new mytasty +``` -### **Step 3:** Do something nice for yourself -Clear your site (if enabled) and browser cache at this point so the changes will go live immediately. Otherwise, visitors to your site (including you) will continue to see the old version (until the cache updates). +### High impact changes -Your TastyIgniter installation is successfully updated.. +#### TastyIgniter As A Package -{{alerts.warning}}If you experience any issue, you should restore your most recent database & file backup and try again{{alerts.end}} +TastyIgniter can now be included in an existing Laravel application as a package. +See [Package Installation](/installation#package-installation) for more details. -{{alerts.note}}THIS IS FOR UPGRADE ON EXISTING INSTALLS ONLY! IF INSTALLING NEW, BE SURE TO READ THE README.md FILE INSTEAD{{alerts.end}} +#### Code Structure +The codebase has been refactored and restructured to follow Laravel conventions which enhance maintainability and +extensibility. This includes updated namespaces, relocated controllers, improved models, and form requests. -## Upgrading TastyIgniter v1.4.x to 2.0.x +- Classes under `Admin\\`, `Main\\`, `System\\` have moved to `Igniter\\Admin\\`, `Igniter\\Main\\`, `Igniter\\System\\` + respectively. -1. BACKUP YOUR EXISTING STORE FILES AND DATABASE!! - - Backup your database via your store `Admin->Tools->Maintenance->Backup` - - Backup your files using FTP file copy or use cPanel filemanager to create a zip of all the existing tastyigniter files and folders +#### Admin Login with Email -2. Download the latest version of TastyIgniter and upload ALL new files on top of your current install EXCEPT your `system/tastyigniter/config/database.php`. - - Make sure your `system/tastyigniter/config/database.php` old file was not overwritten. +The admin login process now uses email addresses instead of usernames, providing a more convenient and familiar login +experience for administrators. -3. Go to http://myrestaurant.com/ Replacing myrestaurant.com with your actual site (and subdirectory if applicable). +#### Mailable Integration -4. You should see the TastyIgniter Setup script. +Sending registered mail templates now uses Laravel's Mailable classes instead of custom logic. This provides a more +standardized and maintainable approach to sending emails. -5. Click **Continue**. After a few seconds you should see the installation success page. - - If you see the database configuration and/or site settings TastyIgniter Setup page, then that means you have replaced your old `system/tastyigniter/config/database.php` file. Restore them from your backup first. Then try again. +#### Mail Template Namespaces -6. Clear any cookies in your browser +Mail template namespaces have been renamed for consistency. `admin::` is +now `igniter.admin::`, `main::` is now `igntier.main::`, and `system::` is now `igniter.system::`. -7. Go to the administrator panel and login as the main administrator. Press Ctrl+F5 3x times to refresh your browser cache. That will prevent oddly shifted elements due to stylesheet changes. - - If you see any errors, report them immediately in the forum before continuing. +#### Translation String Keys -9. Go to `Admin->System` Settings - - Update any blank fields and click save. - - Even if you do not see any new fields, click save anyway to update the database with any new field names. +Translation string keys have been updated to follow a consistent naming +convention. `admin::lang.` is now `igniter::admin.`, `main::lang.` is now `igntier::main.`, and `system::lang.` is +now `igniter::system.`. +#### The Singleton Trait -## Troubleshooting +Singletons have been dropped, you can resolve Manager classes through service containter. This allows for better code +organization and easier unit testing. `ExtensionManager::instance()` is now `resolve(ExtensionManager::class)`. -If you have any upgrade script errors, post them in the forum -You should always visit the forum immediately after a fresh upgrade to see if there are any immediate bug fixes -If nobody has reported your bug, then please report it. \ No newline at end of file +#### Blade Directives + +New Blade directives have been introduced to simplify theme development. The `@themeContent` directive +allows rendering of content template files, while `@themePage` replaces `@page` used for rendering page contents. +Additionally, +`@componentPartial` and `@themePartial` directives replace the previous `@component` and `@partial` directives. + +### Medium impact changes + +#### Extension Configuration + +Extension configuration files are no longer merged automatically. Developers must use Laravel's +mergeConfigFrom() method to merge configuration files from extension class `register` method. + +#### Database Changes + +Several database changes have been made, including merging `staffs` and `users` records into the `admin_users` table, +renaming `staff_groups` to `user_groups`, prefixing user-related tables with `admin_`, dropping conflicting tables, and +increasing the length of varchar to 255 on existing columns. + +### Low impact changes + +#### Admin Controller Actions + +New base view files have been introduced for common admin controller actions such as index, edit, create, and preview. +This eliminates the need to create these view files for your custom controller action. From eeebc318c2d9f0220be43479eb84393ee54e8b61 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Fri, 12 Apr 2024 13:47:48 +0100 Subject: [PATCH 02/14] wip Signed-off-by: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> --- installation.md | 88 ++++++++++++++++++++++++++++-------------------- upgrade-guide.md | 17 +++++----- 2 files changed, 59 insertions(+), 46 deletions(-) diff --git a/installation.md b/installation.md index 9b89450..e104cd6 100644 --- a/installation.md +++ b/installation.md @@ -11,7 +11,7 @@ application. ### Requirements -These are the requirements to run TastyIgniter: +These are the requirements to run TastyIgniter as a stand-alone application: - **Apache** (with mod_rewrite enabled) or **Nginx** - **PHP 8.2+** with the following extensions: bcmath, pdo_mysql, ctype, curl, openssl, dom, gd, exif, mbstring, json, @@ -35,7 +35,7 @@ From here, you can move on to the [Setting up TastyIgniter](#setting-up-tastyign ### Requirements -These are the requirements to run TastyIgniter: +These are the requirements to run TastyIgniter as a package in a Laravel application: - **Laravel 10+** - **MySQL 5.7+** or **MariaDB 10.3+** or **PostgreSQL 10.0** @@ -54,8 +54,8 @@ From here, you can move on to the [Setting up TastyIgniter](#setting-up-tastyign ## Setting up TastyIgniter -TastyIgniter comes packaged with a command-line setup utility that will get you up and running in a few minutes. It will -attempt to automatically configure TastyIgniter and create an admin user account. +TastyIgniter includes a command-line setup tool that will get you up and running in a few minutes. It will attempt to +set up TastyIgniter and create an admin user account. In the TastyIgniter installation's root directory, run the following command: @@ -85,6 +85,16 @@ php artisan igniter:install --no-interaction There are some things you may need to set up after the installation is complete. +### Directory permissions + +Once TastyIgniter is installed, you must grant the non-root user the necessary permissions so that TastyIgniter and Laravel can write to the required system directories. + +```bash +sudo chmod -R 755 /path/to/tastyigniter +sudo chown -R www-data:www-data /path/to/tastyigniter +``` +> You should never set any folder or file to permission level **777**, as this permission level allows anyone to access the content of the folder and file regardless of user or group. + ### Setting up the task scheduler You should add the following Cron entry to your server for scheduled tasks to function properly. Crontab editing is @@ -99,14 +109,15 @@ This Cron will call the command scheduler every minute. When executing the `sche assess your scheduled tasks and run the tasks that are due. > Task Scheduling is how scheduling time-based tasks are managed in TastyIgniter. Several core features of TastyIgniter, -> such as checking for updates, use the scheduler. +> such as assigning orders and checking for updates, use the scheduler. ### Setting up the queue daemon By default, the queue in TastyIgniter is synchronous and will attempt to run tasks such as sending emails in real time. -This behaviour can be set to an asynchronous method by changing the `default` parameter in the `config/queue.php`. +This behaviour can be set to an asynchronous method by updating the `QUEUE_CONNECTION` variable in your application's +`.env` file. -If you are using the `database` queue, it is a good idea to run the queue process as a daemon service. Use the following +It is a good idea to run the queue process as a daemon service. Use the following command: ```bash @@ -126,12 +137,18 @@ can be found below. ### Apache configuration -There are some extra system requirements if your webserver is running Apache, `mod_rewrite` should be installed and -enabled and the `AllowOverride` option should be switched on. - TastyIgniter includes a `.htaccess` file - make sure it's been uploaded correctly. +**There are some extra system requirements if your webserver is running Apache, `mod_rewrite` should be installed and +enabled and the `AllowOverride` option should be switched on.** + +```apache + + AllowOverride All + +``` -You will need to uncomment this line in the `.htaccess` file in some cases: +You will need to uncomment this line in +the [`.htaccess`](https://github.com/tastyigniter/TastyIgniter/blob/master/public/.htaccess) file in some cases: ```html ## !IMPORTANT! You may need to uncomment the following line for some hosting environments, @@ -140,7 +157,7 @@ You will need to uncomment this line in the `.htaccess` file in some cases: # RewriteBase / ``` -If you've created a subdirectory, you can add the subdirectory name as well: +If you've created a subdirectory, you can specify the subdirectory name as well: ```html RewriteBase /mysubdirectory/ @@ -148,7 +165,8 @@ RewriteBase /mysubdirectory/ ### Nginx configuration -Make sure that `.nginx.conf` file included with TastyIgniter has been uploaded correctly. Then, assuming you have Nginx +Make sure that [`.nginx.conf`](https://github.com/tastyigniter/TastyIgniter/blob/v4/.nginx.conf) file included with +TastyIgniter has been uploaded correctly. Then, assuming you have Nginx setup, add the following to your server's configuration block: ```html @@ -159,24 +177,22 @@ As an example, your site conf file should look something like: ```html server { - -listen 80; - -root /path/to/tastyigniter; -index index.php; - -server_name mytastysite.com; - -gzip on; -gzip_proxied expired no-cache no-store private auth; -gzip_types text/plain text/css application/x-javascript application/json application/javascript image/x-icon image/png image/gif image/jpeg image/svg+xml; - -charset utf-8; - -access_log off; - -include /path/to/tastyigniter/.nginx.conf; - + listen 80; + + root /path/to/tastyigniter; + index index.php; + + server_name mytastysite.com; + + gzip on; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css application/x-javascript application/json application/javascript image/x-icon image/png image/gif image/jpeg image/svg+xml; + + charset utf-8; + + access_log off; + + include /path/to/tastyigniter/.nginx.conf; } ``` @@ -184,14 +200,13 @@ include /path/to/tastyigniter/.nginx.conf; ### Debug mode -The debug setting is found in the `config/app.php` configuration file with the `debug` parameter, and is disabled by -default. +The debug setting is found in the `config/app.php` configuration file with the `debug` parameter, and is disabled by default. When enabled, this setting will display detailed error messages when they occur along with other debugging functions. Debug mode should always be disabled in a live production site. This prevents the display of potentially sensitive information to the end user. -> Important: Always set the `APP_DEBUG` setting to false in production environments. +> **Important:** Always set the `APP_DEBUG` setting to false in production environments. ### CSRF protection @@ -200,8 +215,7 @@ TastyIgniter offers a simple method to protect your application from cross-site For every active user session managed by the application, TastyIgniter automatically generates a CSRF "token." This token is used to check that the authenticated user is the one who actually makes the client requests. -Although CSRF security is enabled by default, you can disable it in the `config/system.php` configuration file using -the `enableCsrfProtection` parameter. +Although CSRF security is enabled by default, you can disable it by updating the `ENABLE_CSRF` variable in your application's `.env` file. ## Getting Started @@ -230,4 +244,4 @@ After you've logged in you'll be able to access the administration panel to conf 3. **Setup successful but storefront links are not working:** Check that the theme's required extensions are all installed. -> **Note:** A detailed installation log can be found in the `setup/setup.log` file. +> **Note:** A detailed log can be found in the `storage/logs/laravel.log` file. diff --git a/upgrade-guide.md b/upgrade-guide.md index 32333a2..2de628c 100644 --- a/upgrade-guide.md +++ b/upgrade-guide.md @@ -94,11 +94,6 @@ extensibility. This includes updated namespaces, relocated controllers, improved The admin login process now uses email addresses instead of usernames, providing a more convenient and familiar login experience for administrators. -#### Mailable Integration - -Sending registered mail templates now uses Laravel's Mailable classes instead of custom logic. This provides a more -standardized and maintainable approach to sending emails. - #### Mail Template Namespaces Mail template namespaces have been renamed for consistency. `admin::` is @@ -107,17 +102,17 @@ now `igniter.admin::`, `main::` is now `igntier.main::`, and `system::` is now ` #### Translation String Keys Translation string keys have been updated to follow a consistent naming -convention. `admin::lang.` is now `igniter::admin.`, `main::lang.` is now `igntier::main.`, and `system::lang.` is +convention. `admin::lang.` is now `igniter::admin.`, `main::lang.` is now `igniter::main.`, and `system::lang.` is now `igniter::system.`. #### The Singleton Trait -Singletons have been dropped, you can resolve Manager classes through service containter. This allows for better code +Singletons have been dropped, you can resolve all 'Manager' classes through the service container. This allows for better code organization and easier unit testing. `ExtensionManager::instance()` is now `resolve(ExtensionManager::class)`. #### Blade Directives -New Blade directives have been introduced to simplify theme development. The `@themeContent` directive +New Blade directives have been introduced to simplify theme development and avoid conflicts. The `@themeContent` directive allows rendering of content template files, while `@themePage` replaces `@page` used for rendering page contents. Additionally, `@componentPartial` and `@themePartial` directives replace the previous `@component` and `@partial` directives. @@ -138,6 +133,10 @@ increasing the length of varchar to 255 on existing columns. ### Low impact changes #### Admin Controller Actions - New base view files have been introduced for common admin controller actions such as index, edit, create, and preview. This eliminates the need to create these view files for your custom controller action. + +#### Mailable Integration +Sending registered mail templates now uses Laravel's Mailable classes instead of custom logic. This provides a more +standardized and maintainable approach to sending emails. + From 953cf84275d6f26c6813782fe31decd897cd7895 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Thu, 25 Apr 2024 01:13:35 +0100 Subject: [PATCH 03/14] Complete docs --- advanced/ajax-request.md | 450 +++++- advanced/localization.md | 236 ++-- advanced/mail.md | 232 ++- advanced/routing.md | 8 - advanced/scheduling-tasks.md | 63 +- .../{testing-tastyigniter.md => testing.md} | 4 +- advanced/validation.md | 282 ++++ customize/components.md | 567 +++++++- customize/layouts.md | 177 ++- customize/markup-guide.md | 233 ++-- customize/media-files.md | 26 - customize/media-manager.md | 142 ++ customize/pages.md | 150 +- customize/partials.md | 50 +- customize/permissions.md | 84 -- customize/themes.md | 257 ++-- extend/building-components.md | 257 ---- extend/controllers.md | 233 +++- extend/extensions.md | 458 +++--- extend/form-requests.md | 31 - extend/forms.md | 1238 +++++++++++++++++ extend/lists.md | 692 +++++++++ extend/permissions.md | 109 ++ extend/widgets.md | 338 ++++- installation.md | 48 +- .../code-of-conduct.md | 2 - .../contribution-guide.md | 78 +- .../js-coding-guidelines.md | 0 .../php-coding-guidelines.md | 82 +- upgrade-guide.md | 7 +- 30 files changed, 5353 insertions(+), 1181 deletions(-) delete mode 100644 advanced/routing.md rename advanced/{testing-tastyigniter.md => testing.md} (66%) create mode 100644 advanced/validation.md delete mode 100644 customize/media-files.md create mode 100644 customize/media-manager.md delete mode 100644 customize/permissions.md delete mode 100644 extend/building-components.md delete mode 100644 extend/form-requests.md create mode 100644 extend/forms.md create mode 100644 extend/lists.md create mode 100644 extend/permissions.md rename code-of-conduct.md => resources/code-of-conduct.md (99%) rename contribution-guide.md => resources/contribution-guide.md (66%) rename js-coding-guidelines.md => resources/js-coding-guidelines.md (100%) rename php-coding-guidelines.md => resources/php-coding-guidelines.md (72%) diff --git a/advanced/ajax-request.md b/advanced/ajax-request.md index 41220ac..ec0db2f 100644 --- a/advanced/ajax-request.md +++ b/advanced/ajax-request.md @@ -1,12 +1,456 @@ --- title: "Handling AJAX Requests" section: advanced -sortOrder: 320 -callout: This section is incomplete. Please help to improve it. +sortOrder: 300 --- ## Introduction +TastyIgniter provides a simple and easy way to make AJAX requests to the server using the `$.request` JavaScript object. This object is a wrapper around the jQuery AJAX function, providing a more convenient way to make AJAX requests. + +In this guide, you'll learn how to make AJAX requests using the `$.request` object, handle AJAX requests on the server, and customize AJAX requests using options. + +Alternatively, you can use [Livewire's Event Listeners](https://livewire.laravel.com/docs/actions#event-listeners) to make AJAX requests. + ## How AJAX requests work -## Usage \ No newline at end of file +The `$.request` object is a wrapper around the jQuery AJAX function, providing a more convenient way to make AJAX requests. It is used to send an HTTP request to the server and receive a response from the server without reloading the page. + +Here's an example of how to make an AJAX request using the `$.request` object: + +```javascript +$.request('onSave', { + data: { + var1: 'some string', + var2: 'another string' + }, + success: function(data) { + console.log(data); + } +}); +``` + +In this example, the `$.request` object is used to send an AJAX request to the server. The first argument is the name of the handler method on the server that will handle the request. The second argument is an object containing the request data and a callback function to handle the response. + +You can use data attributes to trigger AJAX requests by adding the `data-request` attribute to HTML elements. The value of the `data-request` attribute should be the name of the handler method on the server that will handle the request. + +```blade + +``` + +## Using AJAX handlers + +To handle an AJAX request on the server, you need to create a handler method in your controller that will process the request and return a response. The handler method should be named `on{HandlerName}`. + +Here's an example of a handler method: + +```php +public function onSave() +{ + $param1 = post('param1'); + $param2 = post('param2'); + + // Process the request data + + return ['result' => 'success']; +} +``` + +You can pass data to the server using the `data` option in the `$.request` object. The data should be an object containing key-value pairs of the request data. + +Here's an example of how to pass data to the server in an AJAX request: + +```javascript +$.request('onSave', { + data: { + param1: 'value1', + param2: 'value2' + }, + success: function(data) { + console.log(data); + } +}); +``` + +In this example, the `data` option is used to pass data to the server in the AJAX request. + +## Handling the response + +You can handle the response from the server using the `success` option in the `$.request` object. The `success` option should be a callback function that will be called when the server returns a response. Additionally, you can use the `done` promise method to handle errors. + +Here's an example of how to handle the response from the server in an AJAX request: + +```javascript +$.request('onSave', { + success: function(data) { + console.log(data); + } +}); +``` + +And here's how you can handle the response using the `done` promise method: + +```javascript +$.request('onSave').done(function(data) { + console.log(data); +}); +``` + +## Error handling + +You can handle errors that occur during the AJAX request using the `error` option in the `$.request` object. The `error` option should be a callback function that will be called when an error occurs during the request. Additionally, you can use the `fail` promise method to handle errors. + +Here's an example of how to handle errors in an AJAX request: + +```javascript +$.request('onSave', { + error: function(xhr, status, error) { + console.log('An error occurred: ' + error); + } +}); +``` + +And here's how you can handle errors using the `fail` promise method: + +```javascript +$.request('onSave').fail(function(xhr, status, error) { + console.log('An error occurred: ' + error); +}); +``` + +## Request options + +The `$.request` object supports additional options for customizing AJAX requests. These options can be defined either programmatically using JavaScript or through the data attributes API by adding data attributes to HTML elements. + +Some of the common options include: + +### `update` + +_(Object)_ Specifies a list of partials and page elements to be updated with the response data. The key is the partial name, and the value is the CSS selector of the target element to be updated. + +**JavaScript:** +```javascript +$.request('onSave', { + update: { + 'partial1': '#element1', + 'partial2': '#element2' + } +}); +``` +**Data attribute** +```html + +``` + +> You may prepend the CSS Selector with `@` to append contents to the element, `^` to prepend and `~` to replace with. + +### `confirm` + +_(string)_ Specifies a confirmation message that will be displayed to the user before sending the request. If the user confirms the request, the request will be sent; otherwise, the request will be canceled. + +**JavaScript:** +```javascript +$.request('onSave', { + confirm: 'Are you sure?' +}); +``` +**Data attribute:** +```html + +``` + +### `data` + +_(Object)_ Specifies the data to be sent with the request. The data should be an object containing key-value pairs of the request data. + +**JavaScript:** +```javascript +$.request('onSave', { + data: { + param1: 'value1', + param2: 'value2' + } +}); +``` +**Data attribute:** +```html + +``` + +### `redirect` + +_(string)_ Specifies the URL to redirect to after the request is completed. + +**JavaScript:** +```javascript +$.request('onSave', { + redirect: '/success' +}); +``` +**Data attribute:** +```html + +``` + +### `headers` + +_(Object)_ Specifies additional headers to be sent with the request. + +**JavaScript:** +```javascript +$.request('onSave', { + headers: { + 'X-CSRF-TOKEN': 'token' + } +}); +``` + +### `attach-loading` + +_(string)_ Specifies the CSS selector to add to the target element while the request is loading. The attribute value is optional, if not provided, the target element will be disabled. + +**Data attribute:** +```html + +``` + +### `replace-loading` + +_(string)_ Specifies the CSS selector to replace on the target element while the request is loading. + +**Data attribute:** +```html + +``` + +### `beforeUpdate` + +_(function)_ Specifies a callback function or Javascript code to be executed before updating the target element with the response. + +**JavaScript:** +```javascript +$.request('onSave', { + beforeUpdate: function(data) { + console.log('Before update'); + } +}); +``` +**Data attribute** +```html + +``` + +### `success` + +_(function)_ Specifies a callback function or Javascript code to be executed after the request is successful. + +**JavaScript:** +```javascript +$.request('onSave', { + success: function(data) { + console.log('Success'); + } +}); +``` +**Data attribute** +```html + +``` + +### `error` + +_(function)_ Specifies a callback function or Javascript code to be executed when an error occurs during the request. + +**JavaScript:** +```javascript +$.request('onSave', { + error: function(xhr, status, error) { + console.log('An error occurred: ' + error); + } +}); +``` +**Data attribute** +```html + +``` + +### `complete` + +_(function)_ Specifies a callback function or Javascript code to be executed after the request is completed. + +**JavaScript:** +```javascript +$.request('onSave', { + complete: function(xhr, status) { + console.log('Request completed'); + } +}); +``` +**Data attribute** +```html + +``` + +### `submit` + +When set to `true`, the form will be submitted using the default form submission method. + +**JavaScript:** +```javascript +$.request('onSave', { + submit: true +}); +``` +**Data attribute** +```html + +``` + +### `form` + +_(CSS Selector)_ Specifies the form element to be submitted. Useful when the request is triggered by a button outside the form. + +**JavaScript:** +```javascript +$.request('onSave', { + form: '#myForm' +}); +``` +**Data attribute** +```html + +``` + +## Global AJAX events + +The AJAX framework triggers several events on the updated elements, the triggering element, form, and the window object. These events are triggered regardless of which API was used - the data attributes API or the JavaScript API. + +### `ajaxBeforeSend` + +Triggered on the window object before the AJAX request is sent. The handler receives the context object as an argument. + +```javascript +$(window).on('ajaxBeforeSend', function(context) { + console.log(context); +}); +``` + +### `ajaxBeforeUpdate` + +Triggered on the form element immediately after the request is completed but before updating the page. The event handler receives the `event` object, the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. + +```javascript +$('form').on('ajaxBeforeUpdate', function(event, context, data, status, jqXHR) { + console.log(event, context, data, status, jqXHR); +}); +``` + +### `ajaxUpdate` + +Triggered on the page element after updating the element with the response data. The event handler receives the `event` object, the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. + +```javascript +$('#element').on('ajaxUpdate', function(event, context, data, status, jqXHR) { + console.log(event, context, data, status, jqXHR); +}); +``` + +### `ajaxUpdateComplete` + +Triggered on the window object after all element are updated. The event handler receives the `event` object, the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. + +```javascript +$(window).on('ajaxUpdateComplete', function(event, context, data, status, jqXHR) { + console.log(event, context, data, status, jqXHR); +}); +``` + +### `ajaxSuccess` + +Triggered on the form element after the request is successful. The event handler receives the `event` object, the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. + +```javascript +$('form').on('ajaxSuccess', function(event, context, data, status, jqXHR) { + console.log(event, context, data, status, jqXHR); +}); +``` + +### `ajaxError` + +Triggered on the form element when an error occurs during the AJAX request. The event handler receives the `event` object, the `context` object, the `error` message, the `status` text string, and the `jqXHR` object as arguments. + +```javascript +$('form').on('ajaxError', function(event, context, error, status, jqXHR) { + console.log(event, context, data, status, jqXHR); +}); +``` + +### `ajaxErrorMessage` + +Triggered on the window object when an error occurs during the AJAX request. The event handler receives the `event` object and `error` message as an argument. + +```javascript +$(window).on('ajaxErrorMessage', function(event, error) { + console.log(event, error); +}); +``` + +### `ajaxConfirmMessage` + +Triggered on the window object when a `confirm` option is given. The event handler receives the event object and the confirmation message as arguments. + +```javascript +$(window).on('ajaxConfirmMessage', function(event, message) { + console.log(event, message); +}); +``` + +### `ajaxSetup` + +Triggered on the triggering element before the AJAX request is formed. The event handler receives the `context` object as an argument. + +```javascript +$('#element').on('ajaxSetup', function(context) { + console.log(context); +}); +``` + +### `ajaxPromise` + +Triggered on the triggering element before the AJAX request is sent. The event handler receives the `context` object as an argument. + +```javascript +$('#element').on('ajaxPromise', function(context) { + console.log(context); +}); +``` + +### `ajaxDone` + +Triggered on the triggering element when the AJAX request is successful. The event handler receives the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. + +```javascript +$('#element').on('ajaxDone', function(context, data, textStatus, jqXHR) { + console.log(data); +}); +``` + +### `ajaxFail` + +Triggered on the triggering element when the AJAX request fails. The event handler receives the `context` object, the `status` text string, and the `jqXHR` object as arguments. + +```javascript +$('#element').on('ajaxFail', function(context, textStatus, jqXHR) { + console.log(jqXHR, textStatus, errorThrown); +}); +``` + +### `ajaxAlways` + +Triggered on the triggering element when the AJAX request is completed. The event handler receives the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. + +```javascript +$('#element').on('ajaxAlways', function(context, dataOrXhr, textStatus, xhrOrError) { + console.log(jqXHR, textStatus); +}); +``` diff --git a/advanced/localization.md b/advanced/localization.md index 79569d9..1b5587a 100644 --- a/advanced/localization.md +++ b/advanced/localization.md @@ -1,159 +1,225 @@ --- title: "Localization" section: advanced -sortOrder: 300 +sortOrder: 310 --- ## Introduction -TastyIgniter has a powerful translation system that allows your site to support multilingual content. When developing your extension, you should consider using locale strings even if you do not intend to use it in more than one language. You never know: if you decide to make your extension available to users around the world, it can be handy later. +TastyIgniter features a robust translation system that leverages Laravel's localization features, providing a convenient method for retrieving strings in various languages, allowing you to easily support multiple languages in your TastyIgniter application. -We strongly recommend including a complete set of English resources with each extension, also if you decide to publish your extension in the TastyIgniter marketplace. - -Locale files are stored within the extension **/language** subdirectory. +Language directories and files are stored in PHP files within your application's **lang** directory. ## Directory structure -Here is an example of the extension `language` directory: +Here is an example of how the **lang** directory might be structured: ```yaml -extensions/ - igniter/ - demo/ <=== Extension directory - language/ <=== Localization directory - en/ <=== Language directory - default.php <=== Locale file - es/ - default.php + lang/ + en/ <=== Language directory + custom.php <=== Language file + es/ <=== Language directory + custom.php <=== Language file ``` -> Each language directory should be named using the ISO 639-1 code for the language it contains. +In this example, the language directory contains language files. Each language has its own subdirectory named using the [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) code (e.g., `en` for English, `es` for Spanish), and each subdirectory contains a `custom.php` language file with the translation strings for that language. -## Defining locale strings +## Defining language strings -All locale files return an array of keyed locale strings. For example: +All language files return an array of keyed language strings. For example: ```php 'This is a sample locale string.', - 'alert' => [ // Namespacing for alerts locale strings + 'sample_key' => 'This is a sample language string.', + 'alert' => [ // Namespacing for alerts language strings 'success' => 'This is a success alert' ] ]; ``` -## Accessing locale strings +## Accessing language strings -You can use the `lang` helper function to get strings from locale files. The method accepts the file and key of the locale string as its first argument. For example, let's the `sample_key` locale string from the locale file `extensions/igniter/demo/language/en/lang.php`: +You can use the `Lang` facade, `@lang` Blade directive, `__` helper function, or `lang` helper function to retrieve strings from language files. For instance, to retrieve the `sample_key` language string from the `lang/en/custom.php` language file, you can use any of these methods. ```php -@lang('igniter.demo::lang.sample_key') +// Using the `Lang` facade +echo Lang('custom.sample_key') + +// Using the `@lang` Blade directive +@lang('custom.sample_key') + +// Using the `lang` helper function +echo lang('custom.sample_key') + +// Using the `lang` helper function in a Blade template +{{ lang('custom.sample_key') }} -@lang('igniter.demo::lang.alert.success') +// Using the `__` helper function +echo __('custom.sample_key'); + +// Using the `__` helper function in a Blade template +{{ __('custom.sample_key') }} ``` -## Overriding locale strings +You can also retrieve nested language strings using dot notation. For example, to retrieve the `success` language string from the `alert` namespace in the `lang/en/custom.php` language file: -System users can override extension locale strings without altering the extension files to modify these strings. For -example, you should create the locale file `default.php` at the following location to override the locale -string `sample_key` within the `default.php` file of the `igniter/demo` extension: +```php +// Using the `Lang` facade +{{ __('custom.alert.success') }} +``` -> You can also easily edit core and/or extension locale strings from the admin interface on the **Localization > Languages > Translations** page +### Replacing parameters in translation strings -```yaml -language/ <=== Localization directory - en/ <=== Language directory - igniter/ - demo/ <=== Extension directory - default.php <=== Locale override file +If you wish, you can define placeholders in your language strings. All placeholders are prefixed with a `:`. For example, you can define a welcome message with a placeholder name like so: + +```php + 'Welcome, :name', +]; +``` + +To replace the placeholders when retrieving a language string, you may pass an array of replacements as the second argument to the `__` function: + +```php +{{ __('custom.welcome', ['name' => 'dayle']) }} ``` -You should only define the locale strings you want to override in this file. Any locale strings you do not override are still loaded from the original locale files of the extension. +If your placeholder contains all capital letters, or only has its first letter capitalized, the translated value will be capitalized accordingly: ```php 'This is an overidden locale string.', + 'welcome' => 'Welcome, :NAME', // Welcome, DAYLE + 'goodbye' => 'Goodbye, :Name', // Goodbye, Dayle ]; ``` -## Making your site multilingual +### Pluralization with language strings -In this section of the article, you will find a complete overview of the steps involved in the creation of a multilingual TastyIgniter site. +Pluralization can be a complex issue due to the various rules across different languages. However, Laravel provides a solution to translate strings differently based on your defined pluralization rules. You can distinguish between singular and plural forms of a string using the `|` character, like this: -### Manually download a Language Pack +``` +'apples' => 'There is one apple|There are many apples', +``` -Follow these steps to manually download a community translated language pack. +You can create even more complex pluralization rules, specifying translation strings for multiple value ranges: -- Join our translations Crowdin project page. -- Choose the language you wish to install. For example, let's choose **Spanish (ES)**. -- Download and unzip the language pack. To download, you need to click on the button at the top right of the Crowdin language page. -- The folder and file structure of the extracted language pack should look like this. +``` +'apples' => '{0} There are none|[1,19] There are some|[20,*] There are many', +``` +Once you've defined a translation string with pluralization options, you can use the `trans_choice` function to retrieve the line for a given "count". For example: +```php +{{ trans_choice('custom.apples', 10) }} +``` + +You can also define placeholder attributes in pluralization strings. These placeholders can be replaced by passing an array as the third argument to the `trans_choice` function: -```yaml -TastyIgniter (es)/ - master/ - es-ES/ <=== Language directory - master/ <=== Branch directory - app/ <=== Namespaced directory - admin/ - lang.php <=== Locale file - main/ - system/ - extensions/ <=== Namespaced directory - igniter/ - demo/ - default.php <=== Locale file ``` +'minutes_ago' => '{1} :value minute ago|[2,*] :value minutes ago', + +{{ trans_choice('custom.minutes_ago', 5, ['value' => 5]) }} // 5 minutes ago +``` + +If you want to display the integer value passed to the `trans_choice` function, you can use the built-in `:count` placeholder: + +``` +'apples' => '{0} There are none|{1} There is one|[2,*] There are :count', +{{ trans_choice('custom.minutes_ago', 5, ['value' => 5]) }} // There are 5 +``` + +## Overriding language strings +You can customize all application language strings from the **System > Languages > Edit > Translations** admin page. -- Copy the files and folders within the `Namespaced` directories into your TastyIgniter `language` directory, `see below`. If you don't have a `language` directory in your application root, create a new one. +Some TastyIgniter extensions, themes and Laravel packages come with their own language files. If you need to customize these strings without modifying the package's core files, you can override them by placing files in the `lang/vendor/{package}/{locale}` directory. - +For instance, if you want to modify the language string `override_key` in `custom.php` for an extension named `acme.helloworld`, you should create a language file `lang/vendor/acme-helloworld/en/custom.php` within the root of your TastyIgniter installation. ```yaml -language/ - es_ES/ <=== Language directory - admin/ - lang.php <=== Locale file - main/ - system/ - igniter/ - demo/ - default.php <=== Locale file +lang/ + vendor/ + acme-helloworld/ + en/ <=== Language directory + custom.php <=== Language override file +``` + +In this file, define only the language strings you want to change. Any strings you don't override will still be loaded from the original language file. + +```php + 'This is an overidden language string.', +]; +``` + +## Making your site multilingual + +In this section, we'll guide you through the steps required to make your TastyIgniter site multilingual. There are two main ways to install additional languages: directly from the **System > Languages** page in the admin interface, or manually downloading a language pack from the TastyIgniter translations Crowdin project page. + +### Installing a language pack + +TastyIgniter comes with a default language pack for the English language. You can install additional language packs from the **System > Languages** page of the admin interface. + +- Navigate to the **System > Languages** page in the admin interface. +- Using the searchbar at the top of the page, search for the language you wish to install. For example, let's search for **Spanish (ES)**. +- Click on the language you wish to install, then click the **Add Language** button. +- Once installed, you can enable the language by toggling the **Status** switch to `Enabled`. + +Run the following command from the application directory to install a **Spanish (ES)** language pack: + +```bash +php artisan igniter:language-install es ``` -> Notice the language directory name uses **underscore** instead of an hypen (e.g. “es_ES”). +### Manually download a language pack -### Installing a Language Pack +Follow these steps to manually download a community translated language pack. + +- Join our translations Crowdin project page. +- Choose the language you wish to install. For example, let's choose **Spanish (ES)**. +- Download and unzip the language pack. To download, you need to click on the button at the top right of the Crowdin language page. +- The extracted language pack should have a specific folder and file structure. Copy the files and folders within the `Namespaced` directories into your TastyIgniter `lang` directory, _see below_. If you don't have a `lang` directory in your application root, create a new one. -After downloading a language pack, you must create a new language in the admin interface to register the language into the system. +```yaml +lang/ + vendor/ + igniter/ + es_ES/ <=== Language directory + admin.php + main.php + system.php +``` -1. Create a new language from the **Localisation > Languages** page of the admin interface. -2. Fill in the form. The value of the `Locale Code` field must match the language directory name. Using the example above, the value will be `es_ES` -3. Lastly, toggle the **Status** switch to `Enabled` then save the form. +> Notice the language directory name uses underscore `_` instead of a hyphen `-` (e.g. "es_ES"). -### Setting the Default Language +### Configuring the default language -You may want to set the installed language pack as the default language for new users and visitors. You can do this on -the **System > Settings > General** page of the admin interface, under the **Site** tab select the language you want to -use as your default. +You may want to set the installed language pack as the default language for new users and visitors. You can do this on the **System > Languages** page of the admin interface, by clicking the **Set as Default** button next to the language you want to use as the default. ### Enabling language detection -TastyIgniter includes support for language negotiation out-the-box using a variety of methods without forcing the user to choose his or her language. The language is detected in the following sequence: +TastyIgniter comes with built-in support for language negotiation, offering various methods to automatically detect the user's language without requiring manual selection. The language detection process follows this sequence: -- Determine the language from the **request/session** parameter. -- Determine the language from the user browser's language settings. +- **On the Admin Interface** + - Determine the Admin Interface language from currently logged in admin user language settings. + - Determine the language from the user browser's language settings. + - Determine the language from the **default** language setting. +- **On the FrontEnd** + - Determine the frontend language from the **request/session** parameter. + - Using the locale picker provided within the [FrontEnd extension](..extensions/frontend#locale-picker). + - Determine the language from the **default** language setting. -## Third-Party Extensions +## Translating third-party extensions -While language packs downloaded from the **Browse Languages** page of the admin interface may usually provide translations for all recommended extensions bundled with TastyIgniter, as a rule, they will not cover any third party extensions that you may have installed. Developers are responsible for providing and maintaining translations of their extensions. +Language packs downloaded from the **System > Languages** page in the admin interface typically include translations for all TastyIgniter recommended extensions. However, it's important to note that they may be missing translations for other extensions you've installed. -So before you install a third-party extension, you should check to make sure it includes translations for each language pack you have installed. If you find that an extension doesn't support a language you need, please contact the developer directly and arrange to have the necessary translations added. +Developers of TastyIgniter extensions are responsible for providing and maintaining translations for their extensions. Before installing a third-party extension, ensure that it includes translations for each language pack you have installed. If you find that an extension doesn't support a language you need, please contact the developer directly to arrange for the necessary translations to be added. \ No newline at end of file diff --git a/advanced/mail.md b/advanced/mail.md index 61ec807..66ec2af 100644 --- a/advanced/mail.md +++ b/advanced/mail.md @@ -1,34 +1,246 @@ --- title: "Mail" section: advanced -sortOrder: 305 -callout: This section is incomplete. Please help to improve it. +sortOrder: 320 --- ## Introduction +TastyIgniter uses the Laravel Mail component to send emails. The Mail component provides a clean, simple API which allows you to send emails through a variety of drivers, including SMTP, Mailgun, Postmark, Amazon SES. + ### Driver prerequisites +Before using the Mailgun, SparkPost or SES drivers you will need to install [Drivers extension](https://tastyigniter.com/marketplace/item/igniter-drivers). + +## Configuration + +The mail configuration file is located at `config/mail.php`. In this file, you may configure the default mail driver, mail sending options, and mail "from" address. Next, verify that your `config/services.php` configuration file contains the required credentials for your mail service. + ## Writing mail -### Using mail templates +In TastyIgniter, you can send mail messages using either mail templates or mail views. Mail templates can be managed through the **Design > Mail templates** admin page. On the other hand, mail views supplied by the application or extension are stored in the `resources/views` directory within the extension's directory. + +Optionally, you can [register mail views in the Extension class](../advanced/mail#registering-mail-templates-layouts--partials) with the `registerMailTemplates` method. This enables automatic generation of mail templates for easy customization via the admin interface. + +> All mail messages support using Blade and Markdown syntax for markup. + +### Creating mail views + +Mail views are stored in the file system, and the _mail code_ is used to represent the path to the view file. For example, sending mail with the code `vendor.extension::mail.message` would use the content in the corresponding file at `vendor/extension/views/mail/message.blade.php`. + +The mail view file content can include up to 3 sections: **configuration**, **plain text**, and **HTML markup**. These sections are separated using the `==` sequence. For example: + +```blade +subject = "Your order has been placed" +== +Hello {{ $customer->first_name }}, + +Your order has been placed successfully. + +Thank you for your order. +== +

Hello {{ $customer->first_name }},

+ +

Your order has been placed successfully.

+ +

Thank you for your order.

+``` + +The **configuration** section sets the mail view parameters. The following configuration parameters are supported: + +| Parameter | Description | +|------------------|------------------| +| `subject` | the mail message subject, **required**. | +| `layout` | the mail layout code, **optional**. Default value is default. | + +The **plain text** section is optional, while the **configuration** and **HTML markup** sections are required. + +```blade +subject = "Your order has been placed" +== +

Hello {{ $customer->first_name }},

+ +

Your order has been placed successfully.

+ +

Thank you for your order.

+``` + +### Creating mail templates + +Mail templates are used to define the structure of the mail message. You can create mail templates in the admin interface by navigating to _Design > Mail templates_. The `code` specified in the template is a unique identifier and cannot be changed once created. + +Here is an example of a simple mail template: + +```blade +subject: Your order has been placed +== +

Hello {{ $customer->first_name }},

+ +

Your order has been placed successfully.

+ +

Thank you for your order.

+``` + +### Creating mail layouts + +Mail layouts can be created by navigating to _Design > Mail templates > Layouts_ in the admin interface. Mail layouts are used to define the structure of the mail message, including the header, footer, and other common elements. The `code` specified in the layout is a unique identifier and cannot be changed once created. + +By default, TastyIgniter comes with a `default` mail layout that can be used as a starting point for creating custom mail layouts. + +Here is an example of a simple mail layout: + +```blade + + + + + + + + +
+

{{ $subject }}

+
-### Using mail layouts +
+ {!! $body !!} +
-### Using mail partials + + + +``` + +In this example, the layout includes a header, main content, and footer sections. The `{{ $custom_css }}` variable is used to include custom CSS styles in the mail layout, and the `{{ $layout_css }}` variable is used to include the mail layout CSS styles defined in the admin interface. The `{{ $subject }}` and `{!! $body !!}` variables are used to include the mail message subject and content, respectively. + +### Creating mail partials + +Mail partials are reusable components that can be included in mail templates and layouts. You can create mail partials by navigating to _Design > Mail templates > Partials_ in the admin interface. The `code` specified in the partial is a unique identifier and cannot be changed once created. + +Here is an example of a simple mail partial: + +```blade +name = "Footer" +== +------------------- +{{ $slot }} +== +

{{ $slot }}

+``` + +You can include the mail partial in a mail template or layout using the `@partial` directive: + +```blade +@partial('footer') +

© {{ date('Y') }} TastyIgniter

+@endpartial +``` + +### Mail variables + +You may access all of the data passed to the mail view or template by using the `{{ $variable }}` syntax. For example, if you pass a `$customer_name` variable to the mail view, you can access it in the view like this: + +```blade +

Hello {{ $customer_name }},

+``` ### Attachments -### Inline attachments +You can attach files to your emails using the `attach` method on the `Mail` facade. The `attach` method accepts the full path to the file as its first argument: + +```php +use Illuminate\Support\Facades\Mail; + +Mail::send('vendor.extension::mail.message', $data, function($message) { + // ... + $message->attach('/path/to/file'); +}); +``` + +#### Inline Attachments + +To embed media in your emails, you can use the `embed` method on the `$message` variable: + +```html + + + +``` + +#### Embedding Raw Data + +To embed raw data in your emails, you can use the `embedData` method on the `$message` variable. This method accepts the raw data and the name of the file as its first and second arguments, respectively: + +```html + + + +``` ## Sending mail +To send a mail template in TastyIgniter, you can use the `sendTemplate` method on the `Mail` facade. This method accepts the code of the mail template, an array of data to pass to the view, and a closure that receives a message instance which allows you to customize the recipients, subject, and other aspects of the mail message: + +```php +use Illuminate\Support\Facades\Mail; + +$data = []; + +Mail::sendTemplate('vendor.extension::mail.message', $data, function($message) use ($customer) { + $message->to($customer->email, $customer->name); +}); +``` + ### Queueing mail -## Registering mail layouts & partials +To queue a mail message, you can use the `queueTemplate` method on the `Mail` facade. This method will automatically push the email onto the queue so it will be sent in the background by a queue worker. This can help to improve the response time of your application by offloading the sending of the email to a background process: + +```php +use Illuminate\Support\Facades\Mail; + +$data = []; + +Mail::queueTemplate('vendor.extension::mail.message', $data, function($message) use ($customer) { + $message->to($customer->email, $customer->name); +}); +``` + +## Registering mail templates, layouts & partials + +To register mail templates, layouts, and partials in the Extension class, you can use the [`registerMailTemplates`](../extend/extensions#extension-class-methods), [`registerMailLayouts`](../extend/extensions#extension-class-methods), and ](../extend/extensions#extension-class-methods)[`registerMailPartials`] methods, respectively. These methods allow you to define the mail templates, layouts, and partials that your extension provides, making them available for customization via the admin interface: + +```php +public function registerMailTemplates(): array +{ + return [ + 'vendor.extension::mail.message' => 'Registered mail template message', + ]; +} + +public function registerMailLayouts(): array +{ + return [ + 'vendor.extension::mail.layouts.default' => 'Default Layout', + ]; +} + +public function registerMailPartials(): array +{ + return [ + 'vendor.extension::mail.partials.footer' => 'Footer partial', + ]; +} +``` -## Registering mail templates +## Mail local development -## Mail Variables +When developing locally, you may want to catch all outgoing mail messages and display them in the browser instead of sending them. You can use the `log` mail driver to log all outgoing mail messages to the log file. To enable this driver, set the `MAIL_DRIVER` environment variable to `log` in your `.env` file: -## Mail & local development \ No newline at end of file +```bash +MAIL_DRIVER=log +``` diff --git a/advanced/routing.md b/advanced/routing.md deleted file mode 100644 index 564211d..0000000 --- a/advanced/routing.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Routing" -section: advanced -sortOrder: 310 ---- - -More information on routing can be found in the Laravel Routing docs. - diff --git a/advanced/scheduling-tasks.md b/advanced/scheduling-tasks.md index af5efb4..7aaf4f9 100644 --- a/advanced/scheduling-tasks.md +++ b/advanced/scheduling-tasks.md @@ -6,52 +6,75 @@ sortOrder: 330 ## Introduction -For each task you needed to schedule on your server, you may have generated a Cron entry in the past. This can quickly become a headache, because your schedule of tasks is no longer in source control and you must SSH into your server to add Cron entries. +TastyIgniter's task scheduler is a powerful feature that allows you to define your command schedule within the application itself. It is built on top of the Laravel's task scheduling system, providing a fluent and expressive interface for defining your schedule. -The command scheduler allows you to define your command schedule within the application itself fluently and expressively. Only one single Cron entry is required on your server when using the scheduler. +When using the scheduler, only a single Cron entry is needed on your server. This eliminates the need for multiple Cron entries and allows you to keep your schedule of tasks in source control. For more detailed information, you can refer to the [Laravel Task Scheduling documentation](https://laravel.com/docs/scheduling). -> **Note**: See the [installation guide](../installation) for instructions on how to set up the task scheduler. +> **Note**: See the [installation guide](../installation#setting-up-the-task-scheduler) for instructions on how to set up the task scheduler. -Task Scheduling is how scheduling time-based tasks are managed in TastyIgniter. Several core features of TastyIgniter, such as checking for updates, use the scheduler. +Task Scheduling in TastyIgniter is the mechanism used to manage time-based tasks. Many essential features, such as update checks and auto-assignment of orders to staff, rely on the scheduler to function. ## Defining Schedules -You may define all of your scheduled tasks by overriding the `registerSchedule` method within the [Extension registration class](../extend/extensions#registration). The method takes a single argument for `$schedule` and is used together with their frequency to define commands. +To define scheduled tasks in TastyIgniter, you can override the `registerSchedule` method within the `Extension` class. This method takes a single argument `$schedule`, which is used to define commands along with their frequency. -To get started, let's look at an example of how to schedule a task. In this example, we schedule to call a closure at midnight every day. We will execute a database query within the `Closure` to clear a table: +Here's an example of how to schedule a task: ```php -class Extension extends \System\Classes\BaseExtension -{ - [...] +// Inside your extension class - public function registerSchedule($schedule) - { - $schedule->call(function () { - \Db::table('recent_users')->delete(); - })->daily(); - } +public function registerSchedule($schedule) +{ + $schedule->call(function () { + // Your task logic here + })->daily(); } ``` -In addition to scheduling `Closure` calls, you may also schedule console commands and operating system commands. For example, to schedule a console command, you can use the `command` method: +In this example, a closure is scheduled to run at midnight every day. Inside the closure, you can define the logic for your task, such as executing a database query to clear a table. + +In addition to scheduling closure calls, you may also schedule [console commands](https://laravel.com/docs/artisan), [queued jobs](https://laravel.com/docs/queues) and operating system commands. For example, to schedule a console command, you can use the `command` method: ```php $schedule->command('cache:clear')->daily(); ``` +To schedule a queued job, you can use the `job` method: + +```php +$schedule->job(new MyJob)->daily(); +``` + The `exec` method may be used to issue a command to the operating system: ```php $schedule->exec('node /home/acme/script.js')->daily(); ``` -More information on task scheduling can be found on the Laravel Task Scheduling docs. +More information on task scheduling can be found on the [Laravel Task Scheduling docs](https://laravel.com/docs/scheduling). -## Creating commands +## Writing commands -TastyIgniter does not support generation of commands by `php artisan make:command`, instead use `php artisan create:command Vendor.Extension CommandName`. For example running `php artisan create:command Igniter.Cart ClearSessions` will create a command stub in the `extensions/igniter/cart/console` folder. +To create a new command, you may use the `make:command` Artisan command. -You should then register the command in your extension `register()` method to make it available to artisan, e.g. `$this->registerConsoleCommand('my.command', \Vendor\Extension\Console\MyCommand::class);` +```bash +php artisan create:command Vendor.Extension CommandName +``` + +This command will create a new command class in the `app/Console/Commands` directory. The generated command will include a `signature` and `description`, as well as a `handle` method where you may place your command's logic. +```php +namespace Vendor\Extension\Console; +class CommandName extends \Illuminate\Console\Command +{ + protected string $signature = 'extension:command {argument : Description} {--option : Description}'; + + protected string $description = 'Command description'; + + public function handle() + { + // Your command logic here + } +} +``` diff --git a/advanced/testing-tastyigniter.md b/advanced/testing.md similarity index 66% rename from advanced/testing-tastyigniter.md rename to advanced/testing.md index 7cd53d4..f4456b4 100644 --- a/advanced/testing-tastyigniter.md +++ b/advanced/testing.md @@ -1,6 +1,6 @@ --- -title: "Testing TastyIgniter" +title: "Testing" section: advanced -sortOrder: 340 +sortOrder: 390 callout: This section is incomplete. Please help to improve it. --- diff --git a/advanced/validation.md b/advanced/validation.md new file mode 100644 index 0000000..48652b4 --- /dev/null +++ b/advanced/validation.md @@ -0,0 +1,282 @@ +--- +title: "Validation" +section: extend +sortOrder: 370 +--- + +## Introduction + +Validation is an essential part of TastyIgniter. It ensures that the data entered by users is accurate and meets the required criteria. + +## Defining validation rules + +Validation rules are defined as an array of key-value pairs, where the key is the field name, and the value is an array containing one or more validation rules. + +```php +$rules = [ + 'name' => ['required', 'min:5'] + 'email' => ['required', 'email', 'unique:users'] +]; +``` + +## Available validation rules + +TastyIgniter leverages Laravel's robust validation system, which provides a variety of validation rules that you can use to validate user input. For a comprehensive list of available validation rules and their usage, please refer to the [Laravel Validation Documentation](https://laravel.com/docs/validation#available-validation-rules). + +## Conditional validation + +You can conditionally apply [validation rules](../advanced/validation#available-validation-rules) based on the value of another field. To do this, you can use the `required_if`, `required_unless`, `required_with`, `required_with_all`, `required_without`, and `required_without_all` rules. For example, to require a field only if another field is present: + +```php +$rules = [ + 'password' => 'required_with:password_confirmation' +]; +``` + +## Validating arrays + +To validate an array of form fields, you can use the `.*` wildcard character to validate each element in the array. For example, to validate an array of email addresses: + +```php +$rules = [ + 'emails.*' => 'required|email' +]; +``` + +Or, you can validate each element in the array: + +```php +$rules = [ + 'users.*.email' => 'required|email' +]; +``` + +Or, to validate an array of form fields with a specific index: + +```php +$rules = [ + 'users.0.email' => 'required|email' +]; +``` + +Or, if the incoming HTTP request contains a `records[name]` field, you may define rules like so: + +```php +$rules = [ + 'records.name' => ['required', 'min:5'] +]; +``` + +## Using the validator + +In typical scenarios within TastyIgniter, you should initially capture user input using the `post()` helper function. This input is then passed as the first argument to the `make` method, along with the validation rules as the second argument. Here’s how you can handle this in practice: + +```php +$validator = Validator::make($data, [ + 'name' => ['required', 'min:5'] // Array +]); +``` + +To validate multiple fields, simply add each field and its corresponding rules to the validation array. + +```php +$validator = Validator::make($data, [ + 'name' => 'required', + 'password' => ['required', 'min:8'], + 'email' => ['required', 'email', 'unique:users'] +]); +``` + +### Checking the validation results + +Once you've created a Validator instance, you can use the `fails` (or `passes`) method to execute the validation checks. + +```php +if ($validator->fails()) { + // The given data did not pass validation +} +``` + +If validation has failed, you may retrieve the error messages from the validator. + +```php +$messages = $validator->messages(); +``` + +You can also access an array of the failed validation rules, without their accompanying messages, by using the `failed` method. + +```php +$failed = $validator->failed(); +``` + +### Throwing validation exceptions + +You can also handle validation errors by throwing Laravel's `\Illuminate\Validation\ValidationException`. This exception automatically returns the appropriate HTTP response based on the type of request. + +For a traditional HTTP request, it triggers a redirect response to the previous URL, along with the validation errors. If the request is an AJAX request, it instead returns a JSON response that includes the validation errors. + +```php +$validator = Validator::make($data, $rules); + +if ($validator->fails()) { + throw new \Illuminate\Validation\ValidationException($validator); +} +``` + +As a shorter way to validate the form similar to the example above, you can use the `validate` method directly. + +```php +$data = Validator::validate($data, $rules); +``` + +### Customizing the error messages + +You can customize the error messages for each field by passing an array of custom messages as the third argument to the `make` method. + +```php +$validator = Validator::make($data, $rules, [ + 'name.required' => lang('author.extension::default.error_name') +]); +``` + +### Customizing the validation attributes + +You can customize the field names used in the validation error messages by passing an array of custom attributes as the fourth argument to the `make` method. + +```php +$validator = Validator::make($data, $rules, $messages, [ + 'name' => lang('author.extension::default.label_name') +]); +``` + +## Using the `Request` facade + +Another approach is to use the `Request` facade to validate all user inputs directly. This method simplifies the process by eliminating the need to manually supply the data; you only need to provide the validation rules as the first argument. The `validate` method then returns the filtered user data, including only the attributes and values that were successfully validated. + +```php +$data = Request::validate([ + 'name' => ['required', 'min:5'], + 'email' => ['required', 'email', 'unique:users'] +]); +``` + +In the example above, the `validate` method will return an array containing the validated data. If the validation fails, an exception will be thrown, and the user will be redirected back to the previous page with the validation errors. + +## Using form requests + +Form requests provide a convenient way to validate incoming HTTP requests in TastyIgniter. By defining validation rules and error messages in a single location, you can maintain and reuse the validation logic across multiple controller actions. This approach helps to keep your controller actions clean and readable by moving the validation logic out of the controller and into a separate class. + +Form Requests are typically stored in the extension's `src/Http/Requests` directory. + +### Creating a form request + +Form requests are custom request classes that extends the `Igniter\System\Classes\FormRequest` class, containing both validation and authorization logic. Here is an example of a simple form request class: + +```php +namespace Author\Extension\Http\Requests; + +class RecordRequest extends \Igniter\System\Classes\FormRequest +{ + public function rules(): array + { + return [ + 'name' => ['required', 'min:5'], + 'email' => ['required', 'email', 'unique:users'] + ]; + } +} +``` + +### Applying the form request + +To use the form request in your admin controller to validate form fields. You can add the form request class to the controller's `$formConfig` property along with the `FormController` action class. + +```php +namespace Author\Extension\Http\Controllers; + +class MyController extends \Igniter\Admin\Controllers\Controller +{ + public array $implement = [\Igniter\Admin\Http\Actions\FormController::class]; + + public $formConfig = [ + 'request' => \Author\Extension\Http\Requests\RecordRequest::class, + 'create' => [ + // ... + ], + ]; +} +``` + +### Performing additional validation + +After the initial validation, you may need to perform further validation. You can do this by calling the form request's `after` function. + +The `after` function should return an array of callables or closures that will be executed after validation is complete. The specified callables will receive an `Illuminate\Validation\Validator` object, allowing you to issue extra error messages as needed: + +```php +namespace Author\Extension\Http\Requests; + +use Illuminate\Validation\Validator; + +class RecordRequest extends \Igniter\System\Classes\FormRequest +{ + public function after(Validator $validator): array + { + return [ + new \Author\Extension\Validation\ValidateUserStatus, + function ($validator) { + if ($this->somethingElseIsInvalid()) { + $validator->errors()->add('field', 'Something is wrong with this field!'); + } + }, + ]; + } +} +``` + +### Stopping on the first validation failure + +By default, the form request will continue to validate all fields, even if one field fails validation. If you want to stop validation on the first failure, you can set the `stopOnFirstFailure` property to `true` in the form request class. + +```php +protected $stopOnFirstFailure = true; +``` + +### Customizing the redirect location + +By default, if validation fails, the user is redirected back to the previous page. However, you can customize this behavior in your form request class. To specify a different redirect location, you can override the `$redirect` property. Alternatively, if you prefer to redirect users to a specific named route, you can set the `$redirectRoute` property like so: + +```php +protected $redirect = '/custom-url'; // Redirects to a custom URL + +// Or + +protected $redirectRoute = 'route-name'; // Redirects to a named route +``` + +### Customizing the error messages + +You can customize the error messages for each field by overriding the `messages` method in the form request class. + +```php +public function messages(): array +{ + return [ + 'name.required' => lang('author.extension::default.error_name') + ]; +} +``` + +### Customizing the validation attributes + +You can customize the field names used in the validation error messages by overriding the `attributes` method in the form request class. + +```php +public function attributes(): array +{ + return [ + 'name' => lang('author.extension::default.label_name') + ]; +} +``` + diff --git a/customize/components.md b/customize/components.md index 47f957d..2dbfa1c 100644 --- a/customize/components.md +++ b/customize/components.md @@ -1,82 +1,573 @@ --- title: "Components" -section: customize +section: extend sortOrder: 140 --- ## Introduction -TastyIgniter Components implements content and features that extend your website. They can be added, removed, and rearranged from **Design > Themes > Editor** in the Administration Panel. +Components implements content and features that extend your TastyIgniter website. They can be added, removed, and rearranged from **Design > Themes > Editor** in the Administration Panel. -Other than displaying HTML markup on a page, components can implement the handling of [AJAX requests](../advanced/ajax-request), the handling of postbacks and the handling of the page execution life cycle, which enables pages to be injected. +Other than displaying HTML markup on a page, components can implement the handling of [AJAX requests](../advanced/ajax-request). -This article describes using components within themes and does not explain [building components](../extend/building-components) as part of extensions. +In this section, you'll learn the basics of building, registering and rendering both [Igniter](../customize/components#theme-component) and [Livewire](#livewire-component) components within a TastyIgniter application. Starting with version 4, Livewire components are not fully supported. You can register these using the `registerComponents` method and attach them into your site via the Admin Interface, just like the Theme components. -## Attaching components +## Livewire Component -Use the admin interface to attach components to pages and layouts. You can attach a component to a page or layout manually using a file editor by following the example below: +To create a Livewire component, extend the `\Livewire\Component` class, implement the `DefineComponent` interface, and register it to be displayed on your site and available from the Admin Interface. If you're new to Livewire component development, the [Components section of the Livewire documentation](https://livewire.laravel.com/docs/components) provides a good starting point. + +Livewire components are stored in the `/src/Livewire` subdirectory within an extension directory. Additionally, component partials should be placed in `resources/views/livewire` to align with Laravel package conventions. ```yaml ---- -title: My first page -permalink: "/page" +vendor/ + acme/ + helloworld/ <=== Extension directory + src/ <=== Extension source directory + Livewire/ <=== Livewire component subdirectory + HelloBlock.php <=== Component class file + resources/ <=== Extension resources directory + views/ <=== Extension views directory + livewire/ <=== Livewire blade views subdirectory + hello-block.blade.php <=== Component default blade view (optional) +``` -'[cartBox]': - showCartItemThumb: 1 ---- +### Defining the component + +To begin, you can either use your preferred file manager to create files and directory for the **HelloBlock** component. + +The component class file should extend the `\Livewire\Component` base class, implement `\Igniter\System\Contracts\SupportsLivewireComponent` interface and its methods, and define the properties of the component. The following is an example defines the `HelloBlock` component: + +```php +namespace Acme\HelloWorld\Livewire; + +class HelloBlock extends \Livewire\Component implements \Igniter\System\Contracts\SupportsLivewireComponent +{ + public int $maxItems = 5; + + public function alerts(): array + { + return ['Success Alert', 'Warning Alert', 'Danger Alert']; + } + + public function render() + { + return view('igniter.helloworld::livewire.default'); + } +} ``` -The **cartBox** component in the above example initializes the property **showCartItemThumb** with value **1**. +The component properties and methods will automatically be made available to the component's view. For example, you will be able to access its `alerts` method and `$maxItems` property from the `resources/views/livewire/hello-block.blade.php` blade view. For example: -When you attach a component, a page variable that matches the component name is automatically created (`$cartBox` in the previous example). Render components HTML markup on a page or layout as follows: +```blade +

Max alerts: {{ $maxItems }}

+@foreach ($this->alerts() as $message) +

{{ $message }}

+@endforeach +``` + +### Component registration + +Components must be registered by overriding the `registerComponents` method within the [Extension registration class](../extend/extensions#extension-class). This lets the app know about the component and so it can be attached through the Admin Interface. To register the `HelloBlock` component with the default alias name **hello-block**, you may override the `registerComponents` method: + +```php +public function registerComponents(): array +{ + return [ + \Acme\HelloWorld\Livewire\HelloBlock::class => [ + 'code' => 'hello-block', + 'name' => 'Name of the hello block component', + 'description' => 'Description of the hello block component', + ], + ]; +} +``` + +### Component properties + +Components can be configured using properties defined for each component using class properties. Let's define a **maxItems** property to limit the number of alerts allowed + +If you want to manage your component's properties through the Admin Interface, you can use `#[DefineProperty]` attribute. + +```php +namespace Acme\HelloWorld\Livewire; + +use Igniter\System\Attributes\DefineProperty; + +class HelloBlock extends \Livewire\Component implements \Igniter\System\Contracts\SupportsLivewireComponent +{ + #[DefineProperty(label: 'Max items', type: 'number', default: 5)] + public int $maxItems = 5; + + // ... +} +``` +| Key | Description | +| --------------- | ------------------------------------------------------------ | +| **label** | required, the property label, it is used by the component Selector in the Admin Interface. | +| **type** | optional, specifies the property type. The type defines the form field type. Currently supported types are **
text**, **number**, **checkbox**, **radio**, **select** and **selectlist**. Default value: **text**. | +| **default** | optional, the default property value. | +| **comment** | optional, the property description, it is used by the component Selector in the Admin Interface. | +| **placeholder** | optional placeholder for text and select properties. | +| **options** | optional array of options for checkbox, radio, select, selectlist properties. | + +The **options** property key can be static or dynamic. Using the `maxItems` property, let's define static options: + +```php +namespace Acme\HelloWorld\Livewire; + +class HelloBlock extends \Livewire\Component implements \Igniter\System\Contracts\SupportsLivewireComponent +{ + #[DefineProperty(label: 'Max items', type: 'select', options: [ + 20 => '20 Per page', + 50 => '50 Per page' + ])] + public int $maxItems = 20; + + // ... +} +``` + +Dynamically, the options can be fetched by omitting the `options` key from the property definition and defining a method that returns the list of options. The method name should be the studly cased name of the property. For example, `getPropertyOptions` where **Property** is the name of the property. In this example, we'll define a method for the `maxItems` property. + +```php +namespace Acme\HelloWorld\Livewire; + +class HelloBlock extends \Livewire\Component implements \Igniter\System\Contracts\SupportsLivewireComponent +{ + #[DefineProperty(label: 'Max items', type: 'select')] + public int $maxItems = 20; + + public function getMaxItemsOptions(): array + { + return [ + 20 => '20 Per page', + 50 => '50 Per page' + ]; + } +} +``` + +Reading the property value from within the **component class**: + +```php +$maxItems = $this->maxItems; +``` + +Accessing the property value from a **component partial**: + +```php +{{ $maxItems }} +``` + +For more information, reference the [Livewire Component Properties documentation](https://livewire.laravel.com/docs/properties). + +### Component actions + +Livewire actions are defined as class methods prefixed with `on` followed by the event name. These methods can be triggered by frontend activities such as clicking a button or filling out a form using the `wire:click` or `wire:submit` directives. For example, to handle an AJAX request with the event name `onAddItem`, define a method in the component class as follows: + +```php +public function onAddItem() +{ + $value1 = post('value1'); + $value2 = post('value2'); + $this->page['result'] = $value1 + $value2; +} +``` + +The action can be triggered from the blade view as follows: ```blade -@component('cartBox') + ``` -### Using multiple instances of the same component +For more information, reference the [Livewire Component Actions documentation](https://livewire.laravel.com/docs/actions). -If two components with the same name are assigned to a page and layout together, the page component overrides any properties of the layout component. +### Component lifecycle handlers + +Livewire includes a number of lifecycle hooks that allow you to run code at specific stages of a component's lifecycle. These hooks let you to conduct activities before or after specific events, including as component initialization, property updates, and template rendering. -You can attach components of the same name registered within two extensions by using its fully qualified class name and assigning it an *alias*: +| Hook Method | Description | +|------------------| ------------------------------------------------------------ | +| **mount()** | Called when a component is created | +| **hydrate** | Called when a component is re-hydrated at the beginning of a subsequent request | +| **boot** | Called at the beginning of every request. Both initial, and subsequent | +| **updating** | Called before updating a component property | +| **updated** | Called after updating a property | +| **rendering** | Called before render() is called | +| **rendered** | Called after render() is called | +| **dehydrate** | Called at the end of every component request | + +For more information, reference the [Livewire Component Livecycle Hooks documentation](https://livewire.laravel.com/docs/lifecycle-hooks). + +### Rendering the component + +Use the admin interface to display components on pages and layouts. You can also display a component on a page or layout manually using a file editor by following the example below: ```blade -'[Igniter\Cart\Components\CartBox cartBox]': - showCartItemThumb: 1 + +``` -'[Igniter\Local\Components\CartBox localCartBox]': - showCartItemThumb: 1 ---- -@component('cartBox') +The **acme.hello-world** prefix in the above example presents the code of the extension that registers the component. + +You can pass variables to components by defining them as attributes on the component tag. For example: -@component('localCartBox') +```blade + +``` + +If you need to pass dynamic values or variables to a component, you can write PHP expressions in component attributes by prefixing the attribute with a colon: + +```blade + ``` -Define multiple instances of a same component: +You can access variables within the component like any other markup variable: ```blade -'[cartBox cartBoxA]': - showCartItemThumb: 1 +
    + @foreach($pages as $page) +
  • {{ $page->name }}
  • + @endforeach +
+``` + +For more information, reference the [Rendering components section of the Livewire documentation](https://livewire.laravel.com/docs/components#rendering-components). + +### Inject page assets + +Use the `Assets::addCss` and `Assets::addJs` methods to add assets to the pages the components are attached to: + +```php +public function mount() +{ + Assets::addJs('acme.helloworld::/js/block.js', 'helloworld-block'); + Assets::addCss('acme.helloworld::/js/block.css', 'helloworld-block'); +} +``` + +## Theme Component + +To create a theme component, extend the `BaseComponent` class, implement its methods, and register it to be displayed on your site and available from the Admin Interface. + +Theme component classes live in the **/src/Components** subdirectory of an extension directory, while the component partials live in the **/resources/views/_components** subdirectory. + +```yaml +vendor/ + acme/ + helloworld/ <=== Extension directory + src/ <=== Extension source directory + Components/ <=== Components subdirectory + HelloBlock.php <=== Component class file + resources/ <=== Extension resources directory + views/ <=== Extension views directory + _components/ <=== Components subdirectory + helloBlock/ <=== Component subdirectory + default.blade.php <=== Component default partial (optional) +``` + +### Defining the component + +To begin, you can either use your preferred file manager to create files and directory for the **HelloBlock** component or simply call the following command from the application directory to generate a component with basic files and directories: + +```bash +php artisan make:igniter-component Acme.HelloWorld HelloBlock +``` + +The component class file should extend the `\Igniter\System\Classes\BaseExtension` base class and define the functionality and properties of the component. The following is an example defines the `HelloBlock` component: + +```php +namespace Acme\HelloWorld\Components; + +class HelloBlock extends \Igniter\System\Classes\BaseComponent +{ + public function defineProperties(): array + { + return []; + } + + public function alerts(): array + { + return ['Success Alert', 'Warning Alert', 'Danger Alert']; + } +} +``` + +The component properties and methods are available on the page or layout its attached through the component variable +which corresponds to the alias of the component. For example, if the `HelloBlock` component was defined on a page or +layout as `'[helloBlock]'`, you will be able to access its `alerts` through the `$helloBlock` variable: + +```blade +@foreach ($helloBlock->alerts() as $message) +

{{ $message }}

+@endforeach +``` + +### Component registration + +Components must be registered by overriding the `registerComponents` method within the [Extension registration class](../extend/extensions#extension-class). This lets the app know about the component and gives it an **alias name** for its use within themes. To register the `HelloBlock` component with the default alias name **helloBlock**, you may override the `registerComponents` method: + +```php +public function registerComponents(): array +{ + return [ + \Acme\HelloWorld\Components\HelloBlock::class => [ + 'code' => 'helloBlock', + 'name' => 'Name of the hello block component', + 'description' => 'Description of the hello block component', + ], + ]; +} +``` + +### Component properties + +Components can be configured using properties defined for each component by overriding the `defineProperties` method. Let's define a **maxItems** property to limit the number of alerts allowed -'[cartBox cartBoxB]': - showCartItemThumb: 1 +```php +public function defineProperties(): array +{ + return [ + 'maxItems' => [ + 'title' => 'Max items', + 'description' => 'The most number of alert items allowed', + 'default' => 10, + 'type' => 'text', + ] + ]; +} +``` + +The method should return an array with the property keys as indexes and the property parameters as values. The property keys are used to access the component property values within the component class. + +| Key | Description | +| --------------- | ------------------------------------------------------------ | +| **label** | required, the property label, it is used by the component Selector in the Admin Interface. | +| **type** | optional, specifies the property type. The type defines the form field type. Currently supported types are **
text**, **number**, **checkbox**, **radio**, **select** and **selectlist**. Default value: **text**. | +| **default** | optional, the default property value. | +| **comment** | optional, the property description, it is used by the component Selector in the Admin Interface. | +| **placeholder** | optional placeholder for text and select properties. | +| **options** | optional array of options for checkbox, radio, select, selectlist properties. | + + +The **options** property key can be static or dynamic. Using the `maxItems` property, let's define static options: + +```php +public function defineProperties(): array +{ + return [ + 'maxItems' => [ + ... + 'type' => 'select', + 'options' => [ + '20' => '20 Per page', + '50' => '50 Per page' + ] + ] + ]; +} +``` + +Dynamically, the options can be fetched by omitting the `options` key from the property definition and defining a method that returns the list of options. The method name should be the studly cased name of the property. For example, `getPropertyOptions` where **Property** is the name of the property. In this example, we'll define a method for the `maxItems` property. + +```php +public function defineProperties(): array +{ + return [ + 'maxItems' => [ + ... + 'type' => 'select', + ] + ]; +} + +public function getMaxItemsOptions(): array +{ + return [ + '20' => '20 Per page', + '50' => '50 Per page' + ]; +} +``` + +Reading the property value from within the **component class**: + +```php +// Get a single value +$maxItems = $this->property('maxItems'); + +// Get a value and return a default value if it doesn't exist +$maxItems = $this->property('maxItems', 8); + +// Get all properties as array +$properties = $this->getProperties(); +``` + +Accessing the property value from a **component partial**: + +```php +{{ $__SELF__->property('maxItems') }} +``` + +### Component class methods + +Sometimes you might want to handle some initialization logic before AJAX handlers and before the execution cycle of the page. You can override the `initialize` method in the component class to handle such initialization logic. + +The following methods are supported in the component class: + +| Method | Description | +|---------------------|------------------------------------------------------------------------------------------| +| **initialize()** | initialization method, called when the component is attached to a page or layout | +| **onRun()** | override to hook into the page's execution life cycle. | +| **onRender()** | override to handle specific logic before rendering the default partial of the component. | +| **renderPartial()** | render a specified component partial or shared partial. | + +### Component partials + +Besides the default partial, components can also provide additional partials which can be used within other template files or in the default partial itself. + +Components can share partial files by placing them in the **resources/views/_partials** subdirectory of the extension directory. + +```yaml +vendor/ + acme/ + helloworld/ + resources/ + views/ + _components/ <=== Components directory + helloBlock/ <=== Component partials directory + default.blade.php <=== Component default partial file + _partials/ <=== Component shared partials directory + shared.blade.php <=== Component shared partial file +``` + +Blade's `@themePartial` directive allows you to include the **helloBlock** component partial from within another component partial: + +```blade +@themePartial('helloBlock::shared') +``` + +Partials rendered from outside the component must use their fully qualified name. + +```blade +@themePartial('componentName::component-partial') +``` + +**Overriding component partials** + +All component partials can be overridden by creating theme partials. A component defined with alias **helloBlock** can have its **default.blade.php** partial overridden by creating a theme partial called **_partials/helloBlock/default.blade.php** + +### Component lifecycle handlers + +Every time the page loads, the `MainController` executes the `onRun` method of the attached components. Overriding the method in the component class allows components to hook into the page execution cycle. Let's inject some variables into the page: + +```php +public function onRun() +{ + $this->page['var'] = 'value'; +} +``` + +Handler functions can be defined in the layout and page [PHP code section](../customize/themes#php-code-section) and component classes. Here is an example of a page or layout PHP section with handler functions: + +```blade +--- +public function onStart() +{ + // +} +--- +

HTML markup

+``` + +These handlers are executed in the following sequence: + +- `onInit` layout function +- `onInit` page function +- `onStart` layout function +- `onRun` layout components function +- `onStart` page function +- `onRun` page components function +- `onEnd` page function +- `onEnd` layout function + +### Defining AJAX handlers + +Components class can define AJAX event handlers as methods prefixed with `on` followed by the event name. For example, to handle an AJAX request with the event name `onAddItem`, define a method in the component class as follows: + +```php +public function onAddItem() +{ + $value1 = post('value1'); + $value2 = post('value2'); + $this->page['result'] = $value1 + $value2; +} +``` + +If the alias for this component was `helloBlock` this handler can be accessed by `helloBlock::onAddItem`. + +> Please see the [Handling AJAX Requests](../advanced/ajax-request) article for more details. + +### Rendering the component + +Use the admin interface to attach components to pages and layouts. You can also attach a component to a page or layout manually using a file editor by following the example below: + +```yaml --- -@component('cartBoxA') +title: My first page +permalink: "/page" + +'[helloBlock]': + maxItems: 20 +--- +``` + +The **helloBlock** component in the above example initializes the property **maxItems** with value **20**. + +When you attach a component, a page variable that matches the component name is automatically created (`$helloBlock` in the previous example). + +Render components HTML markup on a page or layout as follows: + +```blade +@themeComponent('helloBlock') +``` + +**Component variables** + +The `@themeComponent('helloBlock')` tag accepts an array of variables as its second parameter. The specified variables will be available at the time of rendering and will explicitly override the component property values: -@component('cartBoxB') +```blade +@themeComponent('helloBlock', ['maxItems' => 100]) ``` -## Component variables +**Rendering multiple instances of the same component** + +If two components with the same name are assigned to a page and layout together, the page component overrides any properties of the layout component. -The `@component('cartBox')` tag accepts an array of variables as its second parameter. The specifed variables will be available at the time of rendering and will explicitly override the component property values: +You can render multiple instances of the same components by assigning it an *alias*: ```blade -@component('cartBox', ['showCartItemThumb' => 0]) +'[helloBlock helloBlockA]': + maxItems: 1 + +'[helloBlock helloBlockB]': + maxItems: 5 +--- +@themeComponent('helloBlockA') + +@themeComponent('helloBlockB') ``` -The **showCartItemThumb** property value of the component will be set to **0** when the component is being rendered. +### Inject page assets -## Overriding component partials +Use the `addCss` and `addJs` controller methods to add assets to the pages or layouts the components are attached to: -All component partials can be overridden by creating theme partials. A component defined with alias **cartBox** can have its **control.blade.php** partial overridden by creating a theme file called **_partials/cartBox/control.blade.php** +```php +public function onRun() +{ + // Assets path that begins with a slash (/) is relative to the website root directory + $this->addJs('acme.helloworld::/js/block.js', 'helloworld-block); + // Paths that does not begin with a slash is relative to the component directory + $this->addJs('js/block.js', 'helloworld-block); +} +``` diff --git a/customize/layouts.md b/customize/layouts.md index f7ffbe9..ad35a50 100644 --- a/customize/layouts.md +++ b/customize/layouts.md @@ -6,18 +6,20 @@ sortOrder: 120 ## Introduction -Layouts are templates that wrap around your content. They allow you to have your template source code in one place so that you don't have to repeat things like your header and footer on every page. +In TastyIgniter, a theme layout is a template that wraps around your content. It allows you to have your template source code in one place so that you don't have to repeat things like your header and footer on every page. -Layout files live in the **/_layouts** subdirectory of a theme directory. +Layout files live in the **resources/views/_layouts** subdirectory of a theme directory. For example: ```yaml -themes/ - your-theme/ <=== Theme directory - _layouts/ <=== Layouts subdirectory - default.blade.php <=== Layout template file +acme/ <=== Theme vendor directory + purple/ <=== Theme directory + resources/ + views/ + _layouts/ <=== Layouts subdirectory + default.blade.php <=== Layout template file ``` -The convention is to have a basic layout called `default.blade.php` and be used by other pages as required. Within the layout file, you should use the `@page` tag to display the content of the page. +The convention is to have a basic layout called `default.blade.php` and be used by other pages as required. Within the layout file, you should use the `@themePage` tag to display the content of the page. ```blade @@ -26,28 +28,23 @@ The convention is to have a basic layout called `default.blade.php` and be used - @page + @themePage ``` -Next you need to specify what layout to use in your page's front matter. +## Front matter section -```blade ---- -permalink: "/page" -layout: default ---- -

This is the content of my page

-``` +The front matter section is optional for layouts. The optional front matter parameter `description` is used in the Admin Interface. -## Layout front matter +| Variable | Description | +|----------------|---------------------------------------------------------------| +| `description` | Use this variable as the layout title or description or both. | -The front matter section is optional for layouts. The optional front matter parameters are `name` and `description` and are used in the Admin user interface. For example: +Here is an example of a layout file: ```blade --- -name: My First Layout description: My first layout example --- @@ -56,22 +53,124 @@ description: My first layout example - @page + @themePage ``` -You can set the front matter in layouts, the only difference is you use the layout object instead of the page. For example: +You can set the front matter in layouts, the only difference is you use the `$this->layout` object instead of the `$this->page`. For example: ```blade --- +description: My first layout example +--- +

{{ $this->layout->description }}

+ +@themePage +``` + +You can pass your own variables to the layout by defining them in the front matter section. For example: + +```blade +--- +description: My first layout example food: "Pizza" ---

{{ $this->layout->food }}

+``` + +## PHP code section + +The PHP code section and front matter are both optional, but the HTML markup section is required. For example: + +```blade +--- +description: My first layout example +--- + +--- +

{{ $this->layout->hello }}

+``` + +## Using layouts + +To use a layout, you need to specify the layout file in the front matter of your page. For example, if you have a layout file called `default.blade.php`, you would specify `default` as the layout in the front matter of your page. For example: + +```blade +--- +permalink: "/page" +layout: default +--- +

This is the content of my page

+``` + +## Including partials + +[Partials](../customize/partials) are reusable Blade markup blocks that can be used in layouts, pages and other partials. Here, we'll cover the basics of rendering partials within a layout. + +You can render a partial in a layout using Blade's `@include` directive. For example: + +```blade + + + + + + + @include('acme.purple::includes.header') + + @themePage + + +``` + +> `acme.purple` is the theme code specified in the [theme manifest file](../customize/themes#theme-manifest) and `includes.header` is the partial located in `resources/views/includes/header.blade.php`. + +You can pass variables to partials by defining them in the `@include` directive after the partial name. For example: + +```blade +@include('acme.purple::includes.header', ['pages' => $pages]) +``` + +You can access variables within the partial like any other template variable: + +```blade +
    + @foreach($pages as $page) +
  • {{ $page->name }}
  • + @endforeach +
+``` + +## Rendering components + +[Components](components.md) are reusable Blade markup blocks combining state and behavior that serve as building blocks in layouts or pages. Here, we'll cover the basics of rendering [Livewire components](components.md#livewire-component) within a layout. + +Livewire component consists of two files. The first is the component class `src/Livewire/HelloBlock.php` and the second is the component template file `resources/views/livewire/hello-block.blade.php`. + +You can render a Livewire component in a layout using the `` syntax. For example: + +```blade + + + + + + + @themePage -@page + + + ``` +For more on components, see the [Components](components.md) documentation. + ## Execution life cycle Specific functions can be defined in the layouts PHP code section for handling the page execution life cycle: `onInit`, `onStart` and `onEnd`. @@ -92,3 +191,37 @@ function onStart() ---

{{ $this->layout->hello }}

``` + +In this example, the `onStart` function is executed at the start of the execution of the page and sets a variable `hello` that is then used in the layout and can be used in the page content. + +## Inject page assets + +The controller's `addCss` and `addJs` methods allow you to inject assets files (CSS and JavaScript) to layouts. This can be done in the `onStart` function defined in a layout template PHP section. + +```php +--- +addCss('assets/css/my-style.css'); + $this->addJs('assets/js/my-script.js'); +} +?> +--- +``` + +In order to output the injected assets on pages and layouts use the `@themeStyles` and `@themeScripts` tags. Example: + +```blade + + ... + @themeStyles + + + ... + @themeScripts + +``` + +> The page output in the above example will also include all assets files registered within the `resources/meta/assets.json` manifest file. + diff --git a/customize/markup-guide.md b/customize/markup-guide.md index ba623bf..102f7f4 100644 --- a/customize/markup-guide.md +++ b/customize/markup-guide.md @@ -1,156 +1,158 @@ --- title: "Markup Guide" section: customize -sortOrder: 170 +sortOrder: 150 --- ## Introduction -TastyIgniter adds a number of directives and variables to the -Blade template engine. +TastyIgniter uses the [Blade template engine](https://laravel.com/docs/blade) to render views. Blade is a simple, yet powerful templating engine provided with Laravel. Unlike other popular PHP templating engines, Blade does not restrict you from using plain PHP code in your views. All Blade views are compiled into plain PHP code and cached until they are modified, meaning Blade adds essentially zero overhead to your application. + +Blade views are typically stored in the `resources/views` directory of your theme or extension. The Blade file extension is `.blade.php`. ## Variables -| | -| --------------- | -| `$this->page` | -| `$this->layout` | -| `$this->theme` | -| `$this->param` | +The following variables are available in all layout and page templates: + +- `$this->page` - The current page object. +- `$this->layout` - The current layout object. +- `$this->theme` - The current theme object. +- `$this->param` - The current request parameters. + +Use these variables to access the properties of the current page, layout, theme, or request parameters. For example, to access the title of the current page, use `$this->page->title`. + +You may display variables in your templates using the `{{ $variable }}` syntax. For example, to display the title of the current page, use `{{ $this->page->title }}`. ## Directives -Directives are a unique feature to Laravel Blade and are wrapped with `{{ }}` characters or prefixed with `@` character. +Directives are a unique feature to Laravel Blade and are prefixed with `@` character. TastyIgniter extends the [Blade template engine](https://laravel.com/docs/blade) by adding a number of directives and variables. -### @page +> **Note:** The Blade directives provided by TastyIgniter are not the same as the Laravel Blade directives. The Blade directives provided by TastyIgniter are specific to TastyIgniter and are not compatible with Laravel. -The `@page` tag renders the contents of a page into a layout template. +### @themePage + +The `@themePage` tag renders the contents of a page into a layout template. The directive has no parameters. ```blade -@page +@themePage ``` -### @partial +### @themePartial -```blade -@partial('footer') -``` +The `@themePartial` directive renders a partial template file located under the `_partials` subdirectory of a theme. If you are rendering blade views from the other subdirectory of a theme, use Blade's `@include` directive instead. -### @component +The directive has a single required parameter - the name of the partial file without the `.blade.php` extension. You can specify the name of the subdirectory if you refer a partial from a subdirectory `@partial('directory.partial-name')`. ```blade -@component('cartBox') +@themePartial('partial-name') ``` +The directive also accepts a second parameter - an optional array of data to pass to the partial. For example: + ```blade -@component('cartBox', ['checkStockCheckout' => TRUE]) +@themePartial('partial-name', ['status' => 'complete']) ``` +If you need to render a partial only if it exists, you can use the `@themePartialIf` directives. + ```blade -@partial('cart::cartBox') +@themePartialIf('partial-name', ['status' => 'complete']) ``` -### @content +If you need to render a partial only if a boolean condition evaluates to `true` or `false`, you can use the `@themePartialWhen` and `@themePartialUnless` directives. ```blade -@content('welcome.htm') +@themePartialWhen($expression, 'partial-name', ['status' => 'complete']) + +@themePartialUnless($expression, 'partial-name', ['status' => 'complete']) ``` -### @partialIf +If you need to render the first partial that exists from a given array of partials, you can use the `@themePartialFirst` directive. ```blade -@partialIf('cartBox') +@themePartialFirst(['custom.partial-name', 'partial-name'], ['status' => 'complete']) ``` -### @hasComponent +### @themeComponent -```blade -@hasSection('navigation') -
- @yield('navigation') -
+The `@themeComponent` directive renders a Theme component. The directive has a single required parameter - the name of the component. To render a Livewire component, use the `@livewire` directive instead. -
-@endif +```blade +@themeComponent('componentName') ``` -### @stack +The directive also accepts a second parameter - an optional array of data to pass to the component. For example: ```blade -@push('sidebar') - Add this content to the sidebar -@endpush +@themeComponent('componentName', ['status' => 'complete']) ``` +If you need to render a component only if it exists, you can use the `@themeComponentIf` directives. + ```blade -@stack('sidebar') +@themeComponentIf('componentName', ['status' => 'complete']) ``` -```blade -@push('scripts') - This will be second... -@endpush +If you need to render a component only if a boolean condition evaluates to `true` or `false`, you can use the `@themeComponentWhen` and `@themeComponentUnless` directives. -// Later... +```blade +@themeComponentWhen($expression, 'componentName', ['status' => 'complete']) -@prepend('scripts') - This will be first... -@endprepend +@themeComponentUnless($expression, 'componentName', ['status' => 'complete']) ``` -### @styles +If you need to render the first component that exists from a given array of components, you can use the `@themeComponentFirst` directive. ```blade -@styles +@themeComponentFirst(['componentNameExtended', 'componentName'], ['status' => 'complete']) ``` -```php -function onStart() -{ - $this->addCss('assets/css/style.css'); -} -``` +### @themeContent -```blade -@push('styles') - -@endpush -``` +The `@themeContent` directive renders the contents of a static template file located under the `_content` subdirectory of a theme. If you are rendering blade views from the other subdirectory of a theme, use Blade's `@include` directive instead. + +The directive has a single required parameter - the name of the content template file without the `.htm` extension. You can specify the name of the subdirectory if you refer a content from a subdirectory `@themeContent('directory.content-name')`. -### @scripts ```blade -@scripts +@themeContent('content-name') ``` -```php -function onStart() -{ - $this->addJs('assets/js/script.js'); -} -``` +### @themeStyles + +The `@themeStyles` directive renders all stylesheets that are defined during the rendering of the page. This includes all `.css` files registered within the `resources/meta/assets.json` manifest file, as well as stylesheets injected using the controller's `addCss` method. The directive has no parameters. ```blade -@push('scripts') - -@endpush + + ... + @themeStyles + + + ... + ``` -### @verbatim +### @themeScripts -```blade -Hello, @{{ name }}. -``` +The `@themeScripts` directive renders all scripts that are defined during the rendering of the page. This includes all `.js` files registered within the `resources/meta/assets.json` manifest file, as well as scripts injected using the controller's `addJs` method. The directive has no parameters. ```blade -@verbatim -
- Hello, {{ name }}. -
-@endverbatim + + ... + + + ... + @themeScripts + ``` -### @if +## Blade directives + +Blade also provides a variety of directives for working with control structures, such as loops and conditional statements. + +### If statements + +You can construct if statements using the Blade directives `@if`, `@elseif`, `@else`, and `@endif`. ```blade @if (count($categories) === 1) @@ -160,29 +162,42 @@ Hello, @{{ name }}. @else I don't have any categories! @endif -``` - -### @auth -```blade -@auth - // The user is authenticated... -@endauth +@unless (Cart::content()) + Cart is empty. +@endunless -@guest - // The user is not authenticated... -@endguest +@isset($categories) + // $categories is defined and is not null... +@endisset + +@empty($categories) + // $categories is "empty"... +@endempty ``` -### @unless +### Switch statements + +You can construct switch statements using the Blade directives `@switch`, `@case`, `@break`, `@default`, and `@endswitch`. ```blade -@unless (Cart::content()) - Cart is empty. -@endunless +@switch($i) + @case(1) + First case... + @break + + @case(2) + Second case... + @break + + @default + Default case... +@endswitch ``` -### @for +### Loops + +You can construct loops using the Blade directives `@for`, `@foreach`, `@forelse`, `@while`, and `@endfor`, `@endforeach`, `@endforelse`, `@endwhile`. ```blade @for ($i = 0; $i < 10; $i++) @@ -203,31 +218,3 @@ Hello, @{{ name }}.

I'm looping forever.

@endwhile ``` - -### @inject - -```blade -@inject('metrics', 'App\Services\MetricsService') - -
- Monthly Revenue: {{ '{{ $metrics->monthlyRevenue() }}' }}. -
-``` - -## Unsupported Directives - -### - -| Directive | Equivalent | -| ------------------ | ---------- | -| `@extends` | Use [Theme Layouts]() | -| `@include` | Use `@partial` | -| `@includeIf` | Use `@partialIf` | -| `@includeWhen` | Use `@partialWhen` | -| `@includeUnless` | Use `@partialUnless` | -| `@includeFirst` | Use `@partialFirst` | -| `@endcomponent` | Use `@component` | -| `@componentfirst` | Use `@component` | -| `@endcomponentfirst` | Use `@component` | - - diff --git a/customize/media-files.md b/customize/media-files.md deleted file mode 100644 index 23a460e..0000000 --- a/customize/media-files.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: "Media files" -section: customize -sortOrder: 150 -callout: This section is incomplete. Please help to improve it. ---- - -## Introduction - -By default, Media Manager works with the `/assets/media` directory. It is possible to use external storages such as Amazon S3 or Rackspace CDN. - -> The [Drivers extension](https://tastyigniter.com/marketplace/item/igniter-drivers) must be installed before you can use Amazon S3 or Rackspace CDN. - -Reset the Media Manager cache, once you change its configuration. - -## Media configuration options - -Define options under **assets.media** within the **config/system.blade.php** file to configure the Media Manager according to your preference. - -Additional options can be configured from **System > Settings > Media** in the Admin interface. - -For more information on configuring external storage, check out Laravel's filesystem docs. - -## Working with Media files - -Adding media in TastyIgniter is very easy. All of your media can be managed in the Media Manager. If a media file is uploaded within the edit screen, it will automatically be attached to the current menu item being edited. \ No newline at end of file diff --git a/customize/media-manager.md b/customize/media-manager.md new file mode 100644 index 0000000..5368748 --- /dev/null +++ b/customize/media-manager.md @@ -0,0 +1,142 @@ +--- +title: "Media manager" +section: customize +sortOrder: 170 +--- + +## Introduction + +TastyIgniter provides a flexible and configurable media management system. The Media Manager allows you to upload, organize, and manage media files. By default, Media Manager works with the `storage/app/public/media` directory. It is possible to use external storages such as Amazon S3 or Rackspace CDN. + +> The [Drivers extension](https://tastyigniter.com/marketplace/item/igniter-drivers) must be installed to use external storage drivers. + +## Media configuration options + +The Media Manager in TastyIgniter can be configured according to your preference. You can do this by editing the `config/igniter-system.php` file. + +The `config/igniter-system.php` configuration file contains several options that allow you to customize the behavior of the Media Manager: + +- `media`: This section contains the configuration options for the media uploaded files. + - `disk`: This option specifies the storage disk that the Media Manager should use for uploads. By default, it uses the `public` disk. + - `folder`: This option specifies the folder within the storage disk where the media files should be stored. By default, it is set to `media/uploads/`. + - `path`: This option specifies the path to prepend to the file name when generating the file URL. By default, it is set to `media/uploads/`. + - `max_upload_size`: This option specifies the maximum size (in kilobytes) of the files that can be uploaded through the Media Manager. By default, it is set to 1500 (1.5 MB). + - `enable_uploads`: This option allows you to enable or disable file uploads. By default, it is set to `true`. + - `enable_new_folder`: This option allows you to enable or disable the creation of new folders through the Media Manager. By default, it is set to `true`. + - `enable_rename`: This option allows you to enable or disable the renaming of files and folders through the Media Manager. By default, it is set to `true`. + - `enable_move`: This option allows you to enable or disable the moving of files and folders through the Media Manager. By default, it is set to `true`. + - `enable_copy`: This option allows you to enable or disable the copying of files and folders through the Media Manager. By default, it is set to `true`. + - `enable_delete`: This option allows you to enable or disable the deletion of files and folders through the Media Manager. By default, it is set to `true`. + +- `attachment`: This section contains the configuration options for the attachment files. + - `disk`: This option specifies the storage disk that the Media Manager should use for attachments. By default, it uses the `public` disk. + - `folder`: This option specifies the folder within the storage disk where the attachment files should be stored. By default, it is set to `media/attachments/`. + - `path`: This option specifies the path to prepend to the file name when generating the file URL. By default, it is set to `media/attachments/`. + +These options provide a high level of control over how media files are handled in your application. You can customize these options according to your application's requirements. + +To publish the config file to `config/igniter-system.php` run: + +```bash +php artisan vendor:publish --tag="igniter-config" +``` + +For more information on configuring external storage, check out Laravel's filesystem docs. + +## Defining media fields + +Media fields allow you to choose or attach images, videos, and other media files from the library. You can define media fields in the configuration file of your model and use them in forms. + +To use a media field in a form, you can use the `mediafinder` form widget. For a single image field, you can use the `mediafinder` form widget with the `isMulti` set to `false`: + +```php +return [ + 'fields' => [ + 'featured_image' => [ + 'label' => 'Featured Image', + 'type' => 'mediafinder', + 'isMulti' => false, + ], + ], +]; +``` + +For a multiple images field, you can use the `mediafinder` form widget with the `isMulti` set to `true`: + +```php +return [ + 'fields' => [ + 'gallery_images' => [ + 'label' => 'Gallery Images', + 'type' => 'mediafinder', + 'isMulti' => true, + ], + ], +]; +``` + +## Attaching media fields to a model + +Media files can be attached to a model using the `Igniter\Flame\Database\Attach\HasMedia` trait and defining the `$mediable` property. For example, to attach single media files to the `gallery_images` field of `MenuItem` model, you can use the following code + +```php +class MenuItem extends Model +{ + use \Igniter\Flame\Database\Attach\HasMedia; + + public array $mediable = ['featured_image']; +} +``` + +To attach multiple media files to the `gallery_images` field of `MenuItem` model, you can use the following code: + +```php +class MenuItem extends Model +{ + use \Igniter\Flame\Database\Attach\HasMedia; + + public array $mediable = ['gallery_images' => ['multiple' => true]]; +} +``` + +## Displaying media on your site + +To display a media file in a template, you can use the `media` method of the media model. + +For a single media field, you can display the image using the following code: + +```blade +Featured Image +``` + +For a multiple media field, you can display the images using a loop: + +```blade +@foreach($model->gallery_images as $media) + Gallery Image +@endforeach +``` + +For a single attached media field, you can display the image using the following code: + +```blade +Featured Image +``` + +For a multiple attached media field, you can display the images using a loop: + +```blade +@foreach($model->gallery_images as $media) + Gallery Image +@endforeach +``` + +The `getThumb` method accepts an optional parameter to specify the size of the thumbnail. For example, to get a thumbnail of size 200x200, you can use: + +```blade +Gallery Image +``` + diff --git a/customize/pages.md b/customize/pages.md index dde731d..f4a7e8e 100644 --- a/customize/pages.md +++ b/customize/pages.md @@ -8,38 +8,48 @@ sortOrder: 110 All websites are made up of pages. In TastyIgniter, pages are the most basic building block for content. Page file names or directory structure do not affect the routing, but naming your pages according to the page function is a good idea. -Pages files live in the **/_pages** subdirectory of a theme directory. +Pages files live in the **resources/views/_pages** subdirectory of a theme directory. For example, a page file named `home.blade.php` located in the **_pages** directory of a theme. ```yaml -themes/ - your-theme/ <=== Theme directory - _pages/ <=== Pages subdirectory - home.blade.php <=== Page template file +acme/ <=== Theme vendor directory + purple/ <=== Theme directory + resources/ + views/ + _pages/ <=== Pages subdirectory + home.blade.php <=== Page template file ``` -The PHP code section is optional, but both front matter and HTML markup sections are required. For example: +A page file consists of three sections: front matter, PHP code (optional), and HTML markup. Here's an example of a page file: ```blade --- -title: My First Page -description: "My first page example" -permalink: "/page" +title: My Home Page +description: "My home page example" +permalink: "/" layout: default --- -

This is the content of my page

+ +--- +

{{ $hello }}, this is the content of my page

``` -## Page front matter +## Front matter section -A number of predefined parameters can be set in the front-matter of a page. +The front matter section is **required** for pages. A number of predefined parameters can be set in the front-matter of a page. -| VARIABLE | DESCRIPTION | -| ----------- | ------------------------------------------------------------ | -| `title` | Use this variable as the page title. | -| `permalink` | Set this variable and use it as the page URL. | -| `layout` | If set, this specifies the layout file to be used. Use the name of the layout file without the file extension. | +| Variable | Description | +|---------------|----------------------------------------------------------------------------------------------------------------| +| `title` | Use this variable as the page title. | +| `description` | Use this variable as the page description. | +| `permalink` | Set this variable and use it as the page URL, **required**. | +| `layout` | If set, this specifies the layout file to be used. Use the name of the layout file without the file extension. | -You can also set your own front-matter variables accessible in PHP. For example, if you set a food variable, you can use it on your page: +You can also define your own front-matter variables that can be accessed in PHP. For example, if you set a `food` variable, you can use it on your page: ```blade --- @@ -48,11 +58,11 @@ food: "Pizza"

{{ $this->page->food }}

``` -## Permalink syntax +### Permalink variable -The simplest way to set a permalink is using front matter. You set the `permalink` variable in the front matter to the URL you'd like. Permalinks should start with the forward slash character and can contain parameters. +The `permalink` variable is used to set the URL of the page. It can contain parameters and can be set using front matter. Permalinks should start with the forward slash character `/`. -For example, you might have a page on your site located at `/_pages/common/about.blade.php` and you want the url to be `/about`. In front matter of the page you would set: +For example, you might have a page on your site located at `resources/views/_pages/common/about.blade.php` and you want the url to be `/about`. In front matter of the page you would set: ```blade permalink: "/about" @@ -96,11 +106,95 @@ A special wildcard parameter can be used by placing the asterisk after the param permalink: "/pages/:title*/:slug" - this will match /pages/page-title/child/page/page-slug ``` +## PHP code section + +The PHP code section is optional, but the front matter and the HTML markup sections are both required. For example: + +```blade +--- +permalink: "/" +--- + +--- +

{{ $this->page->hello }}

+``` + +## Using layouts + +To use a layout, you need to specify the layout file in the front matter of your page. For example, if you have a layout file called `default.blade.php`, you would specify `default` as the layout in the front matter of your page. For example: + +```blade +--- +permalink: "/" +layout: default +--- +

This is the content of my page

+``` + +## Including partials + +[Partials](../customize/partials) are reusable Blade markup blocks that can be used in pages, layouts and other partials. Here, we'll cover the basics of rendering partials within a page. + +You can render a partial in a page using Blade's `@include` directive. For example: + +```blade +--- +permalink: "/" +food: "Pizza" +--- +@include('acme.purple::includes.sidebar') + +

{{ $this->page->food }}

+``` + +> `acme.purple` is the theme code specified in the [theme manifest file](../customize/themes#theme-manifest) and `includes.sidebar` is the partial located in `resources/views/includes/sidebar.blade.php`. + +You can pass variables to partials by defining them in the `@include` directive after the partial name. For example: + +```blade +@include('acme.purple::includes.header', ['pages' => $pages]) +``` + +You can access variables within the partial like any other template variable: + +```blade +
    + @foreach($pages as $page) +
  • {{ $page->name }}
  • + @endforeach +
+``` + +## Rendering components + +[Components](components.md) are reusable Blade markup blocks combining state and behavior that serve as building blocks in layouts or pages. Here, we'll cover the basics of rendering [Livewire components](components.md#livewire-component) within a page. + +Livewire component consists of two files. The first is the component class `src/Livewire/HelloBlock.php` and the second is the component template file `resources/views/livewire/hello-block.blade.php`. + +You can render a Livewire component in a page using the `` syntax. For example: + +```blade +--- +permalink: "/" +food: "Pizza" +--- + + +

{{ $this->page->food }}

+``` + +For more on components, see the [Components](components.md) documentation. + ## Execution life cycle In the PHP code section of pages and layouts there are specific functions: `onInit`, `onStart` and `onEnd`. -The function `onInit` is executed when all [components](../customize/components) are initialized and before AJAX requests are handled. The `onStart` function is executed at the start of the execution of the page. The `onEnd` function is executed before the page is rendered and the page components are executed. +The function `onInit` is executed when all [components](../customize/components) are initialized and before AJAX requests are handled. The `onStart` function is executed at the start of the execution of the page. The `onEnd` function is executed before the page renders and the page components executed. ```blade --- @@ -144,9 +238,7 @@ public function onStart() ## Inject page assets -The controller's `addCss` and `addJs` methods allow you to inject assets files (CSS and JavaScript) to pages. This can be done in the onStart function defined in a page or layout template PHP section. - -Asset path that **starts with a slash (/)** is relative to the root of your website, but relative to the theme, if the assets path **does not start with a slash (/)**. +The controller's `addCss` and `addJs` methods allow you to inject assets files (CSS and JavaScript) to pages. This can be done in the `onStart` function defined in a page template PHP section. ```php --- @@ -160,18 +252,18 @@ function onStart() --- ``` -In order to output the injected assets on pages or [layouts](../customize/layouts) use the `@styles` and `@scripts` tags. Example: +In order to output the injected assets on pages or layouts use the `@themeStyles` and `@themeScripts` tags. Example: ```blade ... - @styles + @themeStyles ... - @scripts + @themeScripts ``` -> The page output in the above example will include all assets files registered within the `_meta/assets.json` manifest file. +> The page output in the above example will also include all assets files registered within the `resources/meta/assets.json` manifest file. diff --git a/customize/partials.md b/customize/partials.md index 381ea68..abe9ff8 100644 --- a/customize/partials.md +++ b/customize/partials.md @@ -2,39 +2,48 @@ title: "Partials" section: customize sortOrder: 130 -callout: This section is incomplete. Please help to improve it. --- ## Introduction Partials include reusable Blade markup blocks that can be used anywhere on the website. Partials are extremely useful for page sections that appear on multiple pages or layouts. -Partial files live in the **/_partials** subdirectory of a theme directory. +While you can use Blade's `@include` directive, [components](components.md) provide similar functionality and have several advantages over the `@include` directive, including data and attribute binding. + +Partial files live in the **resources/views/includes** subdirectory of a theme directory. For example: + +## Creating a partial + +To create a partial, you need to create a new `.blade.php` file in the `resources/views/includes` directory of your theme. The name of the file will be the name of the partial. For example, to create a partial named `header`, you would create a file named `header.blade.php`. ```yaml -themes/ - your-theme/ <=== Theme directory - _partials/ <=== Partials subdirectory - sidebar.blade.php <=== Partial template file +acme/ <=== Theme vendor directory + purple/ <=== Theme directory + resources/ + views/ + includes/ <=== Partials subdirectory + header.blade.php <=== Partial template file ``` +Inside this file, you can write any Blade markup that you want to reuse across your theme. + ## Rendering partials -The Blade directive `@partial('partial-name')` renders a partial. The directive has a single parameter that is required - the name of the partial file without the `.blade.php` extension. You can specify the name of the subdirectory if you refer a partial from a subdirectory `@partial('directory/partial-name')`. You may use the `@partial` directive within a page, layout or other partials. An example of a page rendering a partial: +The Blade directive `@include('partial-name')` renders a partial. The directive has a single parameter that is required - the name of the partial file without the `.blade.php` extension. You can specify the name of the subdirectory if you refer a partial from a subdirectory `@include('directory.partial-name')`. You may use the `@include` directive within a page, layout or other partials. An example of a page rendering a partial: ```blade ``` -## Passing parameters to partials +### Passing data to partials -You may pass variables to partials by defining them in the `@partial` directive after the partial name: +You may pass variables to partials by defining them in the `@include` directive after the partial name: ```blade ``` @@ -48,3 +57,22 @@ You can access variables within the partial like any other markup variable: ``` +For more information, the [Including Subviews section of the Laravel Blade documentation](https://laravel.com/docs/blade#including-subviews) provides a good starting point. + +## Overriding a component partial + +To override a component partial in a theme, you need to create a new `.blade.php` file with the same name as the partial you want to override, in the `resources/views/_components` directory of your theme. The content of this file will be used instead of the original partial. + +For example, to override the `default` partial for component `acme.hello-world::hello-block`, you would create a file named `hello-block.blade.php` in the `resources/views/_components/hello-block.blade.php` directory of your theme. + +## Using partials within components + +Partials can be used with components to create reusable pieces of functionality. To use a partial within a component, you can use the `@include` directive, followed by the name of the partial. + +For example, to include the `header` partial within a component, you would use the following code: + +```blade +@include('header') +``` + +This will render the header partial wherever the component is used. diff --git a/customize/permissions.md b/customize/permissions.md deleted file mode 100644 index ecf51e7..0000000 --- a/customize/permissions.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: "Permissions" -section: customize -sortOrder: 160 ---- - -## Introduction - -The Permissions' system controls access and restriction to all parts of a TastyIgniter application. There are Super Admins at the lowest level (users with the `super_user` flag set to `true`), and Administrators (staff), and permissions. The `\Admin\Models\Staffs_model` and `\Admin\Models\Users_model` models are the containers that hold all the important information about an administrator. - -Super admins have access to everything in the system and can only be managed by themselves or by other super admins; they are not accessible to or editable by regular administrators, even if an administrator has the `Admin.Staff` permission. - -## How Permissions Work - -Permissions are string keys in the form of `Author.Extension.Permission` name which are given to an administrator by inheritance through the staff's Role. - -When determining whether a staff has a specific permission, the permission settings for that staff's role will be applied. For example, if administrator **Sam** belongs to **Chef** role, and role **Chef** has `manage_order` permission, then **Sam** will get to `manage_order`. - -Staff Roles are groups of permissions with a name used to identify the role of an administrator. Only one role can be assigned to a staff at once. Multiple staff may be assigned a role. TastyIgniter ships with four system roles by default; `owner`, `manager`, `waiter` and `delivery`. Any number of custom roles can be created and applied to administrators with their own combinations of permissions. - -Staff Groups have nothing to do with permissions and are strictly an administrative tool for grouping administrators. For instances, groups can be used to assign an order to all administrators in the Kitchen. - -## Registering permissions - -Administrator permissions can be registered by extensions by overriding the `registerPermissions` method within the [Extension registration class](../extend/extensions#registration). The permissions are defined as an array with keys that match the permission keys and the values holding the permission group & descriptions. The permission keys consist of the name of the author, the name of the extension and the name of the function. Here is an example: - -```yaml -Igniter.Cart.Manage -``` - -Admin controllers can use permissions defined by extensions to restrict administrator access to pages or features. Permissions are defined with a permission key and description. The next example shows how to register administrator permission items. - -```php -public function registerPermissions() -{ - return [ - 'Igniter.Pages.Manage' => [ - 'description' => 'The permission description', - 'group' => 'module', - ], - ]; -} -``` - -## Restricting access to admin pages - -Within an admin controller class, you may specify which permissions are required to access the controller pages, using the `$requiredPermissions` controller's property. This property should contain an array of permission keys. The system would allow the administrator to access the controller pages if the administrator permissions match ANY permission from the list. - -```php -user->hasPermission('Igniter.Pages.*')) { - // ... -} - -if ($this->user->hasPermission([ - 'Igniter.Pages.ManagePages', - 'Igniter.Pages.ManageMenus' -])) { - // ... -} -``` - diff --git a/customize/themes.md b/customize/themes.md index f1aa884..6b9410b 100644 --- a/customize/themes.md +++ b/customize/themes.md @@ -6,112 +6,162 @@ sortOrder: 100 ## Introduction -TastyIgniter themes are files that work together to create a TastyIgniter site's design and functionality. Each theme can be different, offering site owners many choices to change their website look instantly. This article is about developing themes for TastyIgniter. +TastyIgniter themes are files that work together to create a TastyIgniter website. Each theme can be different, offering site owners many choices to change their website look instantly. Themes, just like extensions are built on the foundation of Laravel packages. -Themes are by default subdirectories in the **/themes** directory. The subdirectory of the theme contains all the [pages](../customize/pages), [partials](../customize/partials), [layouts](../customize/layouts) and [assets](../customize/media-files) files and optional theme PHP file (theme.php). +Themes typically contains all the [pages](../customize/pages), [partials](../customize/partials), [layouts](../customize/layouts), assets files and an optional theme PHP file (`theme.php`). Additionally, a theme can have a manifest file (`theme.json`) and a meta directory (`_meta`) that contains the assets manifest file (`assets.json`) and a fields file (`fields.php`) for the Theme settings feature through the Admin Interface. -> The active theme is set in the config/system.php file with the defaultTheme parameter or in the **Design > Themes** Admin page with the Theme Selector. +Activating a theme can be done through the **Design > Themes** Admin page with the Theme Selector or by running this command: + +```bash +php artisan igniter:util set theme --theme=your-theme +``` + +This article is about developing themes for TastyIgniter. ## Directory structure Below is an example of a theme directory structure. Every TastyIgniter theme is represented by way of a separate directory and typically a theme is activated to display the website. ```yaml -themes/ - your-theme/ <=== Theme starts here - _layouts/ <=== Layouts directory - default.blade.php - _pages/ <=== Pages directory contains the website pages - home.blade.php - _partials/ <=== Partials directory contains reusable HTML chucks - sidebar.blade.php - _meta/ <=== Meta directory - assets.json <=== Registers global css, js files and HTML meta tags - _content/ <=== Content directory contains reusable HTML blocks - cta.blade.php - assets/ <=== Assets directory contains images, CSS and JavaScript files. - css/ - js/ - images/ +acme/ <=== Theme vendor directory + purple/ <=== Theme directory + public/ + css/ <=== Directory contains compiled CSS files + js/ <=== Directory contains compiled JavaScript files + images/ <=== Directory contains image files + resources/ <=== Theme resources directory + scss/ <=== Directory contains source SCSS files + js/ <=== Directory contains source JavaScript files + meta/ <=== Meta directory + assets.json <=== Registers global css, js files and HTML meta tags + fields.php <=== Registers form fields for the theme customization + views/ <=== Theme views directory + _layouts/ <=== Layouts directory + default.blade.php + _pages/ <=== Pages directory contains the website pages + home.blade.php + includes/ <=== Partials directory contains reusable HTML chucks + sidebar.blade.php screenshot.png - theme.json <=== Manifest file - theme.php + composer.json <=== Manifest file + theme.php <=== Theme PHP file - Loaded on every theme page request just before running the page code. ``` -TastyIgniter supports a single level subdirectory for layouts, pages, partials and content files (any structure can be used in the assets directory), which simplifies organizing of large websites. +TastyIgniter supports a single level subdirectory for layouts, pages and partials files (any structure can be used in the `assets` directory), making it easier to organise large websites. A theme can contain any number of other subdirectories as well. -### Theme manifest file (optional) +**Screenshot** + +Create a screenshot for your theme. The screenshot should be named `screenshot.png` and should be placed in the top level directory. The recommended image size is 1200px wide by 900px tall. The screenshot is usually smaller but the over-size image allows high-resolution viewing on HiDPI displays. -A `theme.json` file looks like this: +## Theme manifest + +A `composer.json` file for a theme looks like this: ```json { - "code": "tastyigniter-orange", - "name": "TastyIgniter Orange", - "description": "This is a front-end theme", - "author": "Dev Team", - "version": "0.1.0" + "name": "acme/ti-theme-purple", + "type": "tastyigniter-package", + "description": "Purple theme for TastyIgniter", + "authors": [ + { + "name": "Acme Labs" + } + ], + "require": { + "tastyigniter/ti-theme-orange": "*" + }, + "extra": { + "tastyigniter-theme": { + "code": "acme-purple", + "name": "Purple Theme", + "locked": true, + "source-path": "/resources/views", + "meta-path": "/resources/meta", + "publish-paths": [ + "/public" + ] + } + } } ``` -| Field | Description | -| --------------- | ------------------------------------------------------------ | -| **code** | the theme code, required. The value is used on the TastyIgniter marketplace for setting the theme code value. | -| **name** | specifies the theme name, required. | -| **description** | the theme description, required. | -| **author** | specifies the author name, required. | -| **version** | specifies the theme version, required. | -| **homepage** | specifies the author website URL, optional. | -| **require** | an array of extension names the theme depeneds on, optional. | - -### Assets manifest file +| Field | Description | +|-----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **name** | The Composer package's name in vendor/package format, **required**. You should use a vendor name that is unique to you, such as your GitHub username. You should prefix the package part with ti-theme- to indicate that your package is intended for use with TastyIgniter. | +| **type** | MUST be set to tastyigniter-package, ensures that your theme will be installed as such when someone "requires" it, **required**. | +| **description** | A one-sentence summary of what the extension does, **required**. (max. char: 130) | +| **authors** | An object to specify the name of the extension author, **required**. | +| **authors.0.name** | An object to specify the name of the extension author, **required**. | +| **authors.0.email** | An object to specify the email of the extension author, **optional**. | +| **require** | Defines other TastyIgniter packages your theme depends on, **optional**. In the example above, **acme-purple** theme depends on the **tastyigniter/ti-theme-orange** theme. | +| **extra.tastyigniter-theme** | Holds TastyIgniter-specific extension metadata, such as your theme's display name and paths, **required**. | +| **extra.tastyigniter-theme.code** | the theme code, **required**. The value is used on the TastyIgniter marketplace for setting the theme code value. | +| **extra.tastyigniter-theme.name** | specifies the theme name, **required**. | +| **extra.tastyigniter-theme.locked** | specifies whether a child theme must be created to customize the theme, **optional**. | + +## Assets manifest Before adding your files to the theme assets manifest file, you must place them within your theme in the correct directory structure, as shown in the [theme directory structure](#directory-structure). -A `_meta/assets.json` file looks like this: +A `resources/meta/assets.json` file looks like this: ```json { "doctype": "html5", "favicon": "favicon.ico", "meta": [ - //... + { + "name": "Content-type", + "content": "text/html; charset=utf-8", + "type": "equiv" + }, + { + "name": "viewport", + "content": "width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no", + "type": "name" + } ], "css": [ { - "path": "theme/assets/css/app.css", + "path": "$/acme-purple/css/app.css", "name": "app-css" } ], "js": [ { - "path": "theme/assets/js/app.js", + "path": "$/acme-purple/js/app.js", "name": "app-js" } + ], + "bundles": [ + { + "type": "scss", + "files": "acme-purple::/scss/app.scss", + "destination": "$/acme-purple/css/app.css" + } ] } ``` +> The `$` symbol is a placeholder for the `public` path. Theme assets are published to the `public` directory of the TastyIgniter installation when you install or update the theme or run the `php artisan igniter:theme-vendor-publish --theme=your-theme` command. -JavaScript code should be placed in external files whenever possible. Use `get_script_tags()` to load your scripts. - -### Screenshot - -Create a screenshot for your theme. The screenshot should be named `screenshot.png` and should be placed in the top level directory. The recommended image size is 1200px wide by 900px tall. The screenshot is usually smaller but the over-size image allows high-resolution viewing on HiDPI displays. +JavaScript code should be placed in external files whenever possible. Use [`@scripts`](../customize/markup-guide.md#themescripts) to load your scripts and [`@styles`](../customize/markup-guide#themestyles) to load your styles. ## Template structure -A template is how a page is organized, and how the content of the page is displayed. Both layouts and pages templates may contain up to three sections: front-matter, PHP code and HTML markup. Sections are separated by the `---` sequence. For example: +Template is a file that defines how a page or layout is organized and how its content is displayed. It can contain up to three sections: front-matter, PHP code, and HTML markup. These sections are separated by the `---` sequence. + +A **page template** file looks like this: ```blade --- -title: Menu Items -permalink: "/menus" +title: Homepage +permalink: / layout: default -'[cartBox]': - showCartItemThumb: 1 +'[helloBlock]': + maxItems: 1 --- ---
- @component('cartBox') +

Rendering a Theme component

+ @themeComponent('helloBlock') + +

Rendering a Livewire component

+ + +

Rendering sub views

+ @include('acme-purple::includes.sidebar')
``` +A **layout template** file looks like this: + +```blade +--- +description: Default Layout +--- + + + + + {{ $this->page->title }} + @themeStyles + + + @themePage + @themeScripts + + +``` + ### Front-matter section -The front matter must be the first thing in the file and must take the form of a valid YAML set between triple-dashed lines. You can set predefined variables between these triple-dashed lines (see below for a reference) or even create custom ones of your own. These variables will then be available to you to access using PHP tags both further down in the file and also in any template referenced. Here is a basic example: +This is the first section in the file and it contains valid YAML set between triple-dashed lines. You can set predefined variables or create custom ones which will be available to you to access from component blade views. Here is a basic example: ```blade --- -title: "Menu Items" -permalink: "/menus" -layout: "default" +title: Homepage +permalink: / +layout: default -'[cartBox]': - parameter: "value" +'[helloBlock]': + maxItems: 1 --- ``` ### PHP code section -The code within the PHP section is executed each time before the template is rendered. The PHP section is optional and -the content depends on the type of template it is defined within. The PHP open and close tags should always be set +This section is executed each time before the template is rendered. It is optional and the content depends on the type of template it is defined within. The PHP open `` tags should always be set within the section separator `---` on a different line. For example: ```blade --- ---

Categories

    @foreach ($categories as $category) { -
  • {{ $category->name }}
  • - @endforeach +
  • {{ $category }}
  • + @endforeach
``` @@ -168,31 +244,32 @@ The PHP section is converted to a PHP class when the template is parsed, you can ### HTML markup -The HTML section defines the markup to be rendered by the template. The HTML section content can contain both HTML and PHP tags, functions, the content depends on whether the template is a page, layout or partial. +The HTML section defines the markup to be rendered by the template. The HTML section content can contain both HTML and PHP tags, functions, the content depends on whether the template is a page or layout. -## Including Template files +## Including theme partials -To load a partial or content file from another template file, you can use `partial('my-partial-name')` to make it easy for a theme to reuse code sections. The template paths are always absolute. If you render a partial from the same subdirectory `blog/`, the subdirectory name still needs to be specified, `partial('blog/my-partial-name')`. +To render the `includes/sidebar.blade.php` blade view from the [directory structure](../customize/themes#directory-structure) above within a page or layout or another partial, you can use `@include('includes.sidebar')` to make it easy for a theme to reuse code sections. The template paths are always absolute. If you render a partial from the subdirectory `includes/blog/`, the subdirectory name still needs to be specified, `@include('includes.blog.sidebar')`. -## Global Variables +## Global variables -| VARIABLE | DESCRIPTION | -| -------------- | ------------------------------------------------------------ | -| **theme** | Theme object `$this->theme` for reading customization settings. | -| **page** | Page object `$this->page`. Custom variables set via front matter in [pages](../customize/pages) will be available here. | +| Variable | Description | +|----------------|---------------------------------------------------------------------------------------------------------------------------------| +| **theme** | Theme object `$this->theme` for reading customized settings. | +| **page** | Page object `$this->page`. Custom variables set via front matter in [pages](../customize/pages) will be available here. | | **layout** | Layout object `$this->layout`. Custom variables set via front matter in [layouts](../customize/layouts) will be available here. | -| **controller** | Access the underlying controller object `$this->controller`. | -## Customization API +| **controller** | Access the underlying `MainController` object `$this->controller`. | -The Theme Customization feature is available by default for almost all TastyIgniter themes from **Design > Themes**. The Theme Customization Admin page is automatically populated with form fields that a theme registers using the `_meta/fields.php` file. +## Theme settings -> Please note that the Customize Screen is only available if the active theme supports Customization. Furthermore, this screen will probably be different for each theme that enables and builds it. +The theme settings feature in TastyIgniter allows you to customize the appearance and behavior of your theme directly from the admin interface. This feature is available by default for enabled TastyIgniter themes from the **Design > Themes** Admin page. -Example of a `_meta/fields.php` file: +To enable theme settings, you need to register form fields using the `resources/meta/fields.php` file in your theme directory. This file should return an array of form fields that will be displayed in the theme settings interface. + +Here's an example of a `resources/meta/fields.php` file: ```php return [ - // Set form fields for the admin theme customisation. + // Set form fields for the admin theme settings. 'form' => [ 'fields' => [ 'font_family' => [ @@ -200,22 +277,26 @@ return [ 'type' => 'text', 'default' => '"Titillium Web",Arial,sans-serif', 'comment' => 'The font family to use for the main body text.', - 'rules' => 'required', + 'rules' => 'required|string', ], ] ] ]; ``` -The value can then be accessed inside any of the Theme templates: +In this example, a text field is defined for customizing the font family. The field has a label, a default value, a comment, and a validation rule. + +Once the fields are defined, you can access the values inside any of your theme templates using $this->theme->field_name. For example: ```blade -

Welcome to {{ $this->theme->font_family }}!

+

Welcome to our website!

``` -## Best Practices +In this example, the font family defined in the theme settings interface is applied to a heading. + +## Best practices -- Name your main CSS and JavaScript files the same name as your theme -- All template files (layouts, pages, partials, content) should use `.php` . +- All template files (layouts, pages and partials) should use `.blade.php`. - Use relative paths in your CSS files, for example: `url(../img/bg.png);` -- Use lowercase filenames \ No newline at end of file +- Use lowercase filenames +- Use hyphens `-` **NOT** underscores `_` to separate words in filenames \ No newline at end of file diff --git a/extend/building-components.md b/extend/building-components.md deleted file mode 100644 index fd79295..0000000 --- a/extend/building-components.md +++ /dev/null @@ -1,257 +0,0 @@ ---- -title: "Building a Component" -section: extend -sortOrder: 210 ---- - -## Introduction - -In this section, you will learn how to build component and not how to attach [components](../customize/components) to theme templates. Building a component involves creating the class of your component by extending the `BaseComponent` class and some of its methods, then [**registering your component**](#component-registration) to be displayed on your site and available from the Admin Interface. - -Components live in the **/components** subdirectory of an extension directory. - -```yaml -extensions/ - igniter/ - helloworld/ <=== Extension directory - components/ <=== Components subdirectory - block/ <=== Component partials directory - default.blade.php <=== Component default partial (optional) - HelloBlock.blade.php <=== Component class file -``` - -## Defining the component - -To begin, you can either use your preferred file manager to create files and directory for the **Block** component or simply call the following command from the application directory to generate a component with basic files and directories: - -```bash -php artisan create:component Igniter.HelloWorld Block -``` - -### Component class - -The component class file should extend the `\System\Classes\BaseExtension` base class and define the functionality and properties of the component. The following is an example defines the `Block` component: - -```php -namespace Igniter\HelloWorld\Components; - -class Block extends \System\Classes\BaseComponent -{ - public function defineProperties() - { - return []; - } - - public function alerts() - { - return ['Success Alert', 'Warning Alert', 'Danger Alert']; - } -} -``` - -The component properties and methods are available on the page or layout its attached through the component variable -which corresponds to the alias of the component. For example, if the `HelloBlock` component was defined on a page or -layout as `'[helloBlock]'`, you will be able to access its `alerts` through the `$helloBlock` variable: - -```blade -@foreach ($helloBlock->alerts() as $message) -

{{ $message }}

-@endforeach -``` - -### Component registration - -Components must be registered by overriding the `registerComponents` method within the [Extension registration class](extensions#registration). This lets the app know about the component and gives it an **alias name** for its use within themes. To register the `Block` component with the default alias name **helloBlock**, you may override the `registerComponents` method: - -```php -public function registerComponents() -{ - return [ - \Igniter\HelloWorld\Components\Block::class => [ - 'code' => 'helloBlock', - 'name' => 'Name of the hello block component', - 'description' => 'Description of the hello block component', - ], - ]; -} -``` - -> More information on using components can be found in the [Components article](../customize/components). - -### Component properties - -Components can be configured using properties defined for each component by overriding the `defineProperties` method. Let's define a **maxItems** property to limit the number of alerts allowed - -```php -public function defineProperties() -{ - return [ - 'maxItems' => [ - 'title' => 'Max items', - 'description' => 'The most number of alert items allowed', - 'default' => 10, - 'type' => 'text', - ] - ]; -} -``` - -The method should return an array with the property keys as indexes and the property parameters as values. The property keys are used to access the component property values within the component class. - -| Key | Description | -| --------------- | ------------------------------------------------------------ | -| **label** | required, the property label, it is used by the component Selector in the Admin Interface. | -| **type** | optional, specifies the property type. The type defines the form field type. Currently supported types are **
text**, **number**, **checkbox**, **radio**, **select** and **selectlist**. Default value: **text**. | -| **default** | optional, the default property value. | -| **comment** | optional, the property description, it is used by the component Selector in the Admin Interface. | -| **placeholder** | optional placeholder for text and select properties. | -| **options** | optional array of options for checkbox, radio, select, selectlist properties. | - - -The **options** property key can be static or dynamic. Using the `maxItems` property, let's define static options: - -```php -public function defineProperties() -{ - return [ - 'maxItems' => [ - ... - 'type' => 'select', - 'options' => [ - '20' => '20 Per page', - '50' => '50 Per page' - ] - ] - ]; -} -``` - -Dynamically, the options can be fetched by omitting the `options` key from the property definition and defining a method that returns the list of options. The method name should be the studly cased name of the property. For example, `getPropertyOptions` where **Property** is the name of the property. In this example, we'll define a method for the `maxItems` property. - -```php -public function defineProperties() -{ - return [ - 'maxItems' => [ - ... - 'type' => 'select', - ] - ]; -} - -public function getMaxItemsOptions() -{ - return [ - '20' => '20 Per page', - '50' => '50 Per page' - ]; -} -``` - -Reading the property value from within the **component class**: - -```php -// Get a single value -$maxItems = $this->property('maxItems'); - -// Get a value and return a default value if it doesn't exist -$maxItems = $this->property('maxItems', 8); - -// Get all properties as array -$properties = $this->getProperties(); -``` - -Accessing the property value from a **component partial**: - -```php -{{ $__SELF__->property('maxItems') }} -``` - -### Component partials - -Besides the default partial, components can also provide additional partials which can be used within other template files or in the default partial itself. - -```yaml -extensions/ - igniter/ - helloworld/ - components/ - partials/ <=== Component shared partials directory - shared.blade.php <=== Component shared partial file - block/ - default.blade.php - pagination.blade.php <=== Component additional partial - HelloBlock.blade.php <=== Component class file -``` - -> Components can share partial files by placing them in the **components/partials** subdirectory of the extension directory. - -### Component initialization - -Sometimes you might want to handle some initialization logic before AJAX handlers and before the execution cycle of the page. You can override the `initialize` method in the component class to handle such initialization logic. - -### Component class methods - -The following methods are supported in the component class: - -| Method | Description | -| ------------------- | ------------------------------------------------------------ | -| **initialize()** | initialization method, called when the component is attached to a page or layout | -| **onRun()** | override to hook into the page's execution life cycle. | -| **onRender()** | override to handle specific logic before rendering the default partial of the component. | -| **renderPartial()** | render a specified component partial or shared partial. | - -## Page execution cycle handlers - -Every time the page loads, the Main Controller executes the `onRun` method of the attached components. Overriding the method in the component class allows components to hook into the page execution cycle. Let's inject some variables into the page: - -```php -public function onRun() -{ - $this->page['var'] = 'value'; -} -``` - -Handler functions can be defined in the layout and page [PHP code section](../customize/themes#php-code-section) and component classes. These handlers are executed in the following sequence: - -- `onInit` layout method. -- `onInit` page method -- `onStart` layout method -- `onRun` layout components method -- `onStart` page method -- `onRun` page components method -- `onEnd` page method -- `onEnd` layout method - -## Defining AJAX handlers - -Components class can define AJAX event handlers can be defined in the component class as they can be defined in the page or layout [PHP code section](../customize/themes#php-code-section). - -```php -public function onAddItem() -{ - $value1 = post('value1'); - $value2 = post('value2'); - $this->page['result'] = $value1 + $value2; -} -``` - -If the alias for this component was `helloBlock` this handler can be accessed by `helloBlock::onAddItem`. - -> Please see the [Handling AJAX Requests](../advanced/ajax-request) article for more details. - -## Inject page assets - -Use the `addCss` and `addJs` controller methods to add assets to the pages or layouts the components are attached to: - -```php -public function onRun() -{ - // Assets path that begins with a slash (/) is relative to the website root directory - $this->addJs('/extensions/igniter/helloworld/assets/js/controls.js'); - - // Paths that does not begin with a slash is relative to the component directory - $this->addJs('assets/js/controls.js'); -} -``` - diff --git a/extend/controllers.md b/extend/controllers.md index c7bd504..520ca04 100644 --- a/extend/controllers.md +++ b/extend/controllers.md @@ -1,50 +1,233 @@ --- title: "Controllers" section: extend -sortOrder: 220 -callout: This section is incomplete. Please help to improve it. +sortOrder: 210 --- ## Introduction -## Defining the controller +TastyIgniter Admin implements the MVC pattern. Controllers manage admin pages and implement various features like forms and lists. This article describes how to develop admin controllers and how to configure controller methods. -### Controller class - -### Controller properties - -### Controller actions (behaviours) +Controllers are typically stored in the extension's `src/Http/Controllers` directory. Controller views are `.blade.php` blade views that reside in the `resources/views` extension's directory. The controller view directory name matches the controller class name written in lowercase. An example of a controller directory structure: -### Controller views +```yaml +author/ + extension/ + src/ + Http/ + Controllers/ + MyController.php <=== Controller class + resources/ + views/ + mycontroller/ <=== Controller view directory + edit.blade.php <=== Controller view file +``` -## AJAX handlers +## Writing controller -## List controller - -### List configuration - -### List column types +### Controller class -### List filter scopes +Each controller is simply a class that extends the `Igniter\Admin\Classes\AdminController` class. Here is an example of a controller class: -### Extending list controller +```php +namespace Author\Extension\Http\Controllers; -## Form controller +class MyController extends \Igniter\Admin\Classes\AdminController +{ + public function index() // Controller action + { + return $this->makeView('index'); + } +} +``` -### Form configuration +### Controller properties -### Form field types +Controllers defines a number of properties to configure the controller's behavior. The following properties are available: -### Form views +| Property | Description | +|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `$pageTitle` | The page title to display in the admin interface. | +| `$bodyClass` | The CSS class to apply to the admin page body. | +| `$currentUser` | The currently logged-in administrator. | +| `$defaultView` | The default view file to render when no view is returned from the action. | +| `$suppressView` | A boolean value that determines whether to suppress the view rendering. | +| `$layout` | The layout file to use for rendering the controller views. | +| `$requiredPermissions` | An array of permission keys that determine the access level needed to access the controller. If an administrator has any of the permissions listed, they are granted access to the controller pages. | +| `$skipRouteRegister` | A boolean value that determines whether to skip automatically registering the controller routes. | +| `$guarded` | An array of controller methods that can not be called as actions. Can be extended in the controller constructor. | -### Extending the form controller +> **Note** These properties can be set in the class definition, in the controller constructor or in the action method. -## Calendar controller +## Actions, views and routing -### Calendar configuration +Actions are methods within the controller that handle specific tasks. They interact with the model, manipulate data, and load views. Routing is used to map URLs to these controller actions. +For example, the URL for the `index` action of the `MyController` controller in the `Author.Extension` extension would be: +```blade +http://site.com/admin/author/extension/mycontroller/index +``` +## Passing data to views +Data can be passed from the controller to the view using the `$this->vars` property. This property is an array that holds the data to be passed to the view. Here is an example of passing data to the view: -## \ No newline at end of file +```php +public function index() +{ + $this->vars['records'] = Record::all(); +} +``` + +The variables passed with the `$this->vars` property can now be accessed directly in your view: + +```php +@foreach ($records as $record) + {{ $record->name }} +@endforeach +``` + +## Rendering views + +Views are rendered using the `makeView` method. This method takes the view file name as an argument and returns the rendered view. Here is an example of rendering a view: + +```php +public function index() +{ + return $this->makeView('index'); +} +``` + +## Setting the navigation context + +Extensions can register admin navigation menus and submenus in the [Extension class](../extend/extensions#extension-class-methods). The navigation context can be set in the controller to highlight the active menu item in the admin interface. The `AdminMenu::setContext` method is used to set the navigation context. Here is an example of setting the navigation context: + +```php +public function __construct() +{ + parent::__construct(); + + AdminMenu::setContext('nav-item', 'parent-item'); +} +``` + +## Controller middleware + +For example, TastyIgniter includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application. + +Controller middleware is executed after the request is processed by TastyIgniter, but before the response is sent to the browser, allowing you to perform actions or modify the request/response during this lifecycle stage. + +To define middleware for your controller, you may specify it in the `__construct()` method of your Admin controller by calling the `middleware()` method. Here is an example of defining middleware for a controller: + +```php +public function __construct() +{ + parent::__construct(); + + $this->middleware(function ($request, $response) { + // Middleware functionality + }); +} +``` + +You can also control which actions will use your middleware by using the `only()` and `except()` modifiers. For example, to restrict the middleware to only run on the `index` action or on every action except the `index` action, you could do the following: + +```php +public function __construct() +{ + parent::__construct(); + + $this->middleware(function ($request, $response) { + // Middleware functionality + })->only('index'); + + // Or + + $this->middleware(function ($request, $response) { + // Middleware functionality + })->except('index'); +} +``` + +## Controller action classes + +Action classes are behaviours that can be attached to controllers to extend their functionality. Action classes are useful for sharing common controller logic across multiple controllers. To attach an action class to a controller, you can set the `$implement` property on the controller class. + +Here is an example of attaching an action class to a controller: + +```php +namespace Author\Extension\Http\Controllers; + +class MyController extends \Igniter\Admin\Classes\AdminController +{ + public array $implement = [\Author\Extension\Http\Actions\MyAction::class]; + + // +} +``` + +Each controller action is simply a class that extends the `Igniter\System\Classes\ControllerAction` class. Here is an example of a controller action class: + +```php +namespace Author\Extension\Http\Actions; + +class MyAction extends \Igniter\System\Classes\ControllerAction +{ + public function __construct($controller) + { + parent::__construct($controller); + + // Configure the action + } + + public function index() // Action method + { + return $this->makeView('index'); + } +} +``` + +## Using AJAX handlers + +Controllers can define AJAX handlers to handle AJAX requests. AJAX handlers are methods with the name starting with "on" string that return an array of data, throw an exception or redirect to another page (see [AJAX event handlers](../advanced/ajax-request#using-ajax-handlers)). Here is an example of defining an AJAX handler: + +```php +public function onAction() +{ + if (Request::input('someVar') != 'someValue') { + throw new ApplicationException('Invalid value'); + } + + return ['data' => 'value']; +} +``` + +The AJAX handler can be triggered with the data-request attribute in the view: + +```blade + +``` + +## Restricting access + +Access to controller actions can be restricted using the `$requiredPermissions` property. This property holds an array of permission keys that determine the access level needed. If an administrator has any of the permissions listed, they are granted access to the controller pages. + +Here is an example of how to restrict access to a controller using permissions: + +```php +namespace Author\Extension\Http\Controllers; + +class MyController extends \Igniter\Admin\Classes\AdminController +{ + public null|string|array $requiredPermissions = ['Author.Extension.ManageRecord']; + + // +} +``` + +See more about [restricting access to admin pages](../extend/permissions#restricting-access-to-admin-pages) and [restricting access to admin controller actions](../extend/permissions#restricting-access-to-admin-controller-actions). \ No newline at end of file diff --git a/extend/extensions.md b/extend/extensions.md index 9cfd90b..daed4c8 100644 --- a/extend/extensions.md +++ b/extend/extensions.md @@ -6,29 +6,27 @@ sortOrder: 200 ## Introduction -Extensions are the foundation for adding new features to TastyIgniter by extending it. The core of TastyIgniter is designed to be lean and lightweight, to maximize flexibility and minimize code bloat. With extensions, you can add functionality to your site, instead of hacking the core code of TastyIgniter. +Extensions are the foundation for adding new features to TastyIgniter by extending it. The core of TastyIgniter is designed to be lean and lightweight, to maximize flexibility and minimize code bloat. With extensions, you can add specific set of features or services, such as: -An extension can add to TastyIgniter specific set of features or services, such as: define components, defines staff permissions, add or extend menu items, lists and forms, create or alter database table structures and seed data, alter core or other extension functionality, provide services, admin controllers, views, assets and other files. +- Define components, mail templates and staff permissions +- Add, remove or replace navigation items +- Create or alter database table structures and seed database records +- Alter core or other extension functionality +- Provide services, admin controllers and assets. -### How TastyIgniter Loads Extensions - -When TastyIgniter loads the list of extensions on the **System -> Extensions** page of the TastyIgniter Admin, it searches through the `extensions` folder (and its second level subdirectories) to find the `Extension.php` PHP Class file. +TastyIgniter extensions are built on the foundation of Laravel packages. They leverage standard practices such as implementing service providers to register routes, views, and translations. If you're new to Laravel package development, [the Package Development part of the Laravel documentation](https://laravel.com/docs/packages) is a useful resource. ### Directory structure -Extensions live in the **/extensions** subdirectory of the application directory. Below is an example of an extension directory structure. +Below is an example of an extension directory structure. ```yaml -extensions/ -acme/ <=== Author name (namespace) -helloworld/ <=== Extension name - components/ - controllers/ -models/ -composer.json <=== Contains extension metadata -Extension.php <=== Extension registration file - README.md <=== Extension readme file - routes.php <=== Extension routes file +acme/ <=== Author name (namespace) + helloworld/ <=== Extension name + src/ + Extension.php <=== Extension class + composer.json <=== Contains extension metadata + README.md <=== Extension readme file ``` ## Creating an extension @@ -37,8 +35,7 @@ This section of the article covers the steps you need to take - and some things ### Naming your extension -The first step in creating an extension is to select a **Namespace** and **Short Name** for it. This extension name ** -Namespace.ShortName** is used to refer to your extension by core TastyIgniter. The namespace will be used as your author +The first step in creating an extension is to select a **Namespace** and **Short Name** for it. This extension name **Namespace.ShortName** is used to refer to your extension by core TastyIgniter. The namespace will be used as your author code when publishing your extensions on the [TastyIgniter marketplace](https://tastyigniter.com/marketplace). Both namespace and extension name must follow these important rules: @@ -51,28 +48,31 @@ Both namespace and extension name must follow these important rules: Here's an example: **Acme.HelloWorld** Given the above example **Acme.HelloWorld**, creating an extension is pretty simple and straightforward, simply call the -following command from the application directory to generate a basic extension directory and files: +following command from the application directory to generate a basic extension directory and files within your `extensions` directory: ```bash -php artisan create:extension Igniter.HelloWorld +php artisan make:igniter-extension Acme.HelloWorld ``` -> We strongly recommend that you follow the [TastyIgniter coding standards](../php-coding-guidelines) when creating your own extensions. It is a requirement for any changes to the TastyIgniter core code. +> We strongly recommend that you follow the [TastyIgniter coding standards](../resources/php-coding-guidelines.md) when creating your own extensions. It is a requirement for any changes to the TastyIgniter core code. -### Extension manifest file (composer.json) +### Extension manifest (composer.json) A `composer.json` file is essential for storing metadata about the extension. ```json { "name": "acme/ti-ext-helloworld", - "type": "tastyigniter-extension", + "type": "tastyigniter-package", "description": "Say hello to the rest of the world..", "authors": [ { "name": "Acme Labs" } ], + "require": { + "tastyigniter/ti-ext-local": "*" + }, "extra": { "tastyigniter-extension": { "code": "acme.helloworld", @@ -81,29 +81,24 @@ A `composer.json` file is essential for storing metadata about the extension. "class": "fa fa-puzzle-piece", "color": "#FFF", "backgroundColor": "#ED561A" - }, - "require": { - "igniter.local": "*", - "igniter.user": "*", - "igniter.payregister": "*" } } } } ``` -| Field | Description | -| --------------- | ------------------------------------------------------------ | -| **name** | the Composer package's name in vendor/package format, required. You should use a vendor name that is unique to you, such as your GitHub username. You should prefix the package part with `ti-ext-` to indicate that your package is intended for use with TastyIgniter. | -| **type** | MUST be set to `tastyigniter-extension`. ensures that your extension will be installed as such when someone "requires" it, required. | -| **description** | a one-sentence summary of what the extension does, required. (max. char: 130) | -| **authors** | an object to specify the name of the extension author, required. | -| **extra.tastyigniter-extension** | holds TastyIgniter-specific extension metadata, such as your extension's display name and icon style. | -| **extra.tastyigniter-extension.code** | the extension unique identifier code, required. | -| **extra.tastyigniter-extension.name** | specifies the extension name, required. The value is used as the extension display name. | -| **extra.tastyigniter-extension.icon** | an object that defines the icon for your extension. The **name** property is the name of a [Font Awesome icon class](https://fontawesome.com/icons). All other properties are used as the style attribute for your extension's icon. | -| **extra.tastyigniter-extension.homepage** | specifies the extension website URL, optional. | -| **extra.tastyigniter-extension.require** | defines other TastyIgniter extensions your extension depends on, optional. In the example above, **igniter.cart** extension depends on the **igniter.local** extension. | +| Field | Description | +| --------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **name** | The Composer package's name in vendor/package format, **required**. You should use a vendor name that is unique to you, such as your GitHub username. You should prefix the package part with ti-ext- to indicate that your package is intended for use with TastyIgniter. | +| **type** | MUST be set to tastyigniter-package, ensures that your extension will be installed as such when someone "requires" it, **required**. | +| **description** | A one-sentence summary of what the extension does, **required**. (max. char: 130) | +| **authors** | An object to specify the name of the extension author, **required**. | +| **require** | Defines other TastyIgniter extensions your extension depends on, **optional**. In the example above, **acme.helloworld** extension depends on the **tastyigniter/ti-ext-local** extension. | +| **extra.tastyigniter-extension** | Holds TastyIgniter-specific extension metadata, such as your extension's display name and icon style, **required**. | +| **extra.tastyigniter-extension.code** | The extension unique identifier code, **required**. | +| **extra.tastyigniter-extension.name** | Specifies the extension name, **required**. The value is used as the extension display name. | +| **extra.tastyigniter-extension.icon** | An object that defines the icon for your extension. The **name** property is the name of a [Font Awesome icon class](https://fontawesome.com/icons). All other properties are used as the style attribute for your extension's icon. | +| **extra.tastyigniter-extension.homepage** | Specifies the extension website URL, **optional**. | See [the composer.json schema](https://getcomposer.org/doc/04-schema.md) documentation for information about other properties you can add to composer.json. @@ -111,34 +106,21 @@ properties you can add to composer.json. ### Readme file If you want to publish your extension on the [TastyIgniter marketplace](https://tastyigniter.com/marketplace), you must -create a **readme.md** file in a standardized format in your extension directory. - -### Routes file +create a **README.md** file in a standardized format in your extension directory. -Extensions can also provide a file named **routes.php** with custom routing logic as described in -the [routing article](../advanced/routing). +## Extension class -## Registration +An **Extension.php** file (aka *Extension class*) is an essential part of the TastyIgniter extension for providing methods for extending the TastyIgniter core. -An **Extension.php** file (aka *Extension registration file*) is an essential part of the TastyIgniter extension for providing methods for extending the TastyIgniter core. +The extension class should extend the `\Igniter\System\Classes\BaseExtension` class, which in turn extends Laravel's `Illuminate\Foundation\Support\Providers\EventServiceProvider` class. This allows the Extension class to take advantage of the functionality provided by Laravel's service providers, such as registering services, event subscribers, model observers and listening for events. -The registration script should define an extension name class which extends the class `\System\Classes\BaseExtension`. The following is an example Extension registration file. +Here is an example of an Extension class: ```php namespace Acme\HelloWord; -class Extension extends \System\Classes\BaseExtension +class Extension extends \Igniter\System\Classes\BaseExtension { - public function extensionMeta() - { - return [ - 'name' => 'The extension name', - 'author' => 'The extension author name', - 'description' => 'The extension description', - 'icon' => 'The extension icon. Any FontAwesome icon name, for example: `fa-puzzle-piece`', - ]; - } - public function register() { @@ -151,32 +133,30 @@ class Extension extends \System\Classes\BaseExtension } ``` -> Its recommended to define the extension metadata using the `composer.json` file instead of overriding the `extensionMeta` method. +In this example, the `register` method is used to bind services into the container, and the `boot` method is used to perform any operations after all other services have been registered. -### Registration class methods +### Extension class methods -The following methods are supported in the extension registration class: +The following methods are supported in the extension class: -| Method | Description | -| ------------------------------ | ------------------------------------------------------------ | -| **register()** | register method, called when the plugin is first registered. | -| **boot()** | boot method, called right before the request route. | -| **extensionMeta()** | returns metadata about the extension, when an extension.json is not supplied. | -| **registerComponents()** | registers any [front-end components](../customize/components) supplied by this extension. | -| **registerNavigation()** | registers admin navigation menu items for this extension, see below for example. | -| **registerPermissions()** | registers any [staff permissions](../customize/permissions#registering=permissions) supplied by this extension. | -| **registerSettings()** | registers any [admin settings page](#registering-settings-link) supplied by this extension. | -| **registerDashboardWidgets()** | registers any [admin dashboard widgets](../extend/widgets#dashboard-widget), supplied by this extension. | -| **registerFormWidgets()** | registers any [admin form widgets](../extend/widgets#form-widget) supplied by this extension. | -| **registerMailLayouts()** | registers any mail view layouts supplied by this extension. | -| **registerMailTemplates()** | registers any mail view templates supplied by this extension, see below for example. | -| **registerMailPartials()** | registers any mail view partials supplied by this extension. | -| **registerPaymentGateways()** | registers any payment gateways supplied by this extension. | +| Method | Description | +|--------------------------------|----------------------------------------------------------------------------------------------------------------------------| +| **register()** | register method, called when the plugin is first registered. | +| **boot()** | boot method, called right before the request route. | +| **registerNavigation()** | registers admin navigation menu items for this extension, see below for example. | +| **registerPermissions()** | registers any [staff permissions](../extend/permissions.md#registering-permissions) supplied by this extension. | +| **registerSettings()** | registers any [admin settings page](../extend/extensions#registering-settings-navigation-link) supplied by this extension. | +| **registerDashboardWidgets()** | registers any [admin dashboard widgets](../extend/widgets#using-dashboard-widget), supplied by this extension. | +| **registerFormWidgets()** | registers any [admin form widgets](../extend/widgets#using-form-widget) supplied by this extension. | +| **registerMailLayouts()** | registers any mail view layouts supplied by this extension. | +| **registerMailTemplates()** | registers any mail view templates supplied by this extension, see below for example. | +| **registerMailPartials()** | registers any mail view partials supplied by this extension. | +| **registerSchedule()** | registers any [scheduled tasks](../advanced/scheduling-tasks) supplied by this extension. | An example registering **mail templates view** file `extensions/acme/helloworld/views/mail/contact`: ```php - public function registerMailTemplates() + public function registerMailTemplates(): array { return [ 'acme.helloworld::mail.contact' => 'Contact form email to admin', @@ -188,7 +168,7 @@ An example registering **mail templates view** file `extensions/acme/helloworld/ An example registering a top-level and child **menu navigation menu item**: ```php -public function registerNavigation() +public function registerNavigation(): array { return [ 'messages' => [ @@ -215,21 +195,19 @@ To register a custom **middleware**, you can call any of the following in your * public function boot() { // Add a new middleware to a controller class. - \Main\Classes\MainController::extend(function($controller) { + \Igniter\Main\Classes\MainController::extend(function($controller) { $controller->middleware(\Path\To\CustomMiddleware::class); }); - // Alternatively, add a new middleware to beginning of the stack. - $this->app[\Illuminate\Contracts\Http\Kernel::class] - ->prependMiddleware(\Path\To\CustomMiddleware::class); + // Alternatively, add a new middleware to beginning of the igniter group stack. + $this->app['router']->prependMiddlewareToGroup('igniter', \Path\To\CustomMiddleware::class); - // Alternatively, add a new middleware to end of the stack. - $this->app[\Illuminate\Contracts\Http\Kernel::class] - ->pushMiddleware(\Path\To\CustomMiddleware::class); + // Alternatively, add a new middleware to end of the igniter group stack. + $this->app['router']->pushMiddlewareToGroup('igniter', \Path\To\CustomMiddleware::class); } ``` -An example registering **console commands** supplied by **Igniter.Api** extension: +An example registering **console commands**: ```php public function register() @@ -240,126 +218,101 @@ public function register() } ``` -## Using Third-Party Composer Packages - -There are a number of scenarios that require the developer to add a third-party composer packages to their extension. - -Here is a full example of how the **Igniter.PayRegister** extension adds third-party package `omnipay/stripe`: - -```json -{ - "name": "tastyigniter/ti-ext-payregister", - "type": "tastyigniter-extension", - "description": "Allows you to accept credit card payments using PayPal, Stripe, Authorize.Net and/or Mollie.", - "keywords": [ - "tastyigniter", - "paypal", - "stripe", - "payment", - "gateway" - ], - "license": "MIT", - "authors": [ - { - "name": "Sam Poyigi", - "email": "sam@sampoyigi.com" - } - ], - "require": { - "omnipay/stripe": "~3.0" - }, - "extra": { - "tastyigniter-extension": { - "code": "igniter.payregister", - "name": "Pay Register", - "icon": { - "class": "fa fa-cash-register", - "backgroundColor": "#88C425", - "color": "#1B2707" - }, - "homepage": "https://tastyigniter.com/marketplace/item/igniter-payregister" - } - } -} -``` - -> Do not commit the `/vendor` directory, the `composer.json` file should be committed to the repository. +## Resources -### Dependencies install process +### Configuration -The marketplace takes the following extra few steps when preparing extensions that define third-party dependencies using `composer.json`. +There are two ways to configure extensions; with settings models (database settings) and configuration files. -- Injects dependencies already included in the TastyIgniter core into the `replace` property of `composer.json` -- Executes `composer install` in the extension directory -- Deletes `composer.lock` files to prevent duplicating dependencies with the core `composer.json`, since a `/vendor` - folder already exists in the extension directory. -- Lastly, the final result is packaged and ready to be consumed via Update API by the TastyIgniter Update Manager +#### Using the settings model configuration -## Settings and Configuration - -There are two ways to configure extensions; with admin settings (database settings) and configuration files. - -### Using the settings model - -Settings models, like any other models, resides in the **/models** subdirectory of the extension directory. +Settings models, like any other models, resides in the **src/Models** subdirectory of the extension directory. ```yaml -extensions/ - igniter/ - helloworld/ +acme/ + helloworld/ + resources/ models/ - config/ <=== Setting model config directory - cartsettings.php <=== Setting model form fields - CartSettings.php <=== Setting model class file + settings.php <=== Setting model form fields + src/ + Models/ + Settings.php <=== Setting model class file ``` -By implementing the `SettingsModel` action class and extending the base `Model` class in a model class, you can create models for storing settings in the database. +By implementing the `\Igniter\System\Actions\SettingsModel` action class and extending the base `\Igniter\Flame\Database\Model` class in a model class, you can create models for storing settings in the `extension_settings` database table. ```php - [ + 'toolbar' => [ + 'buttons' => [ + 'save' => ['label' => 'lang:admin::lang.button_save', 'class' => 'btn btn-primary', 'data-request' => 'onSave'], + 'saveClose' => [ + 'label' => 'lang:admin::lang.button_save_close', + 'class' => 'btn btn-default', + 'data-request' => 'onSave', + 'data-request-data' => 'close:1', + ], + ], + ], + 'fields' => [ + 'field_name' => [ + 'label' => 'Field Label', + 'type' => 'text', + 'span' => 'left', + ], + ], + ], +]; +``` + An example of **writing** to a settings model: ```php -use Igniter\Cart\Models\CartSettings; +use Acme\HelloWorld\Models\Settings; // Set a single value -CartSettings::set('cart_key', 'ABCD'); +Settings::set('cart_key', 'ABCD'); // Set an array of values -CartSettings::set(['cart_key' => 'ABCD']); +Settings::set(['cart_key' => 'ABCD']); ``` An example of **reading** from a settings model: ```php -use Igniter\Cart\Models\CartSettings; +use Acme\HelloWorld\Models\Settings; // Get a single value -$cartKey = CartSettings::get('cart_key'); +$cartKey = Settings::get('cart_key'); // Get a value and return a default value if it doesn't exist -$abandonedCart = CartSettings::get('abandoned_cart', true); +$abandonedCart = Settings::get('abandoned_cart', true); ``` -### Using the file-based configuration +#### Using the file-based configuration -Extensions can have a `config.php` configuration file in the extension directory `config` subdirectory. Configuration files are PHP scripts that define and return an array, e.g. `/extensions/igniter/cart/config/config.php` configuration file: +Just like Laravel packages, extensions can have configuration files in the extension `config` subdirectory. Configuration files are PHP scripts that define and return an array, e.g. `acme/helloworld/config/settings.php` configuration file ```php 120 ]; ``` +To make the configuration file available to the application, you need to register the configuration file in the extension class `register` method. + +```php +public function register() +{ + $this->mergeConfigFrom(__DIR__.'/config/settings.php', 'acme.helloworld::settings'); +} +``` -Use the `Config` class to access the configuration values defined in the configuration file. +Use the `Config` facade to access the configuration values defined in the configuration file. ```php use Config; // Get a value and return a default value if it doesn't exist -$cartSessionTtl = Config::get('igniter.cart::config.cartSessionTtl', 120); +$cartSessionTtl = Config::get('acme.helloworld::settings.cartSessionTtl', 120); ``` -### Registering settings link +#### Registering settings navigation link -An example showing how to create an admin settings link to a settings model. Registered settings links will appear on the **System > Settings** Admin page. +An example showing how to register a system settings item which links to a settings model. Registered settings will appear on the **System > Settings** admin page. ```php -public function registerSettings() +public function registerSettings(): array { return [ - 'cartsettings' => [ - 'label' => 'Cart Settings', - 'description' => 'Manage cart settings.', - 'icon' => 'fa fa-cart-plus', - 'model' => Igniter\Cart\Models\CartSettings::class, - 'permissions' => ['Module.Cart'], + 'settings' => [ + 'label' => 'Extension Settings', + 'description' => 'Manage extension settings.', + 'icon' => 'fa fa-plugin', + 'model' => Acme\HelloWorld\Models\Settings::class, + 'permissions' => ['Acme.HelloWorld.Settings'], ], ]; } ``` -## Extending an extension +### Migrations + +If your extension contains database migrations stored in the extension's `database/migrations` directory, TastyIgniter will automatically load them when the extension is loaded. + +Here is an example of a `2020_01_01_000000_create_messages_table.php` migration file located in `acme/helloworld/database/migrations`: + +```php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +return new class extends Migration +{ + public function up() + { + Schema::create('acme_helloworld_messages', function (Blueprint $table) { + $table->increments('id'); + $table->string('subject'); + $table->text('message'); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('acme_helloworld_messages'); + } +}; +``` + +For more information on database migrations, refer to the [Laravel documentation on database migrations](https://laravel.com/docs/migrations). + +### Seeders + +Seeders are used to populate database tables with sample data. Just like Laravel Packages, seeders are stored in the extension's `database/seeds` directory. + +Here is an example of a `MessagesTableSeeder.php` seeder file located in `acme/helloworld/database/seeds`: -Why extend an extension with another extension? To keep the changes compatible, if the extension gets an update. Extensions are mainly extended to inject or modify the functionality of the core classes and other extensions using the event service. +```php +namespace Acme\HelloWorld\Database\Seeds; + +use Illuminate\Database\Seeder; + +class MessagesTableSeeder extends Seeder +{ + public function run() + { + DB::table('acme_helloworld_messages')->insert([ + 'subject' => 'Hello World', + 'message' => 'Welcome to the world of TastyIgniter!', + ]); + } +} +``` -The most common place to subscribe to an event is the extension registration file `boot` method. +To run the seeder, you can use the `php artisan db:seed --class=Acme\\HelloWorld\\Database\\Seeds\\MessagesTableSeeder` command. + +### Routes + +If your extension includes a `routes/web.php` route file, TastyIgniter will automatically load it, adding any defined routes to the application's routing table. + +Extensions in TastyIgniter can define routes using the `routes/web.php` file or handle admin routes through admin controllers. + +To handle admin routes, use [admin controllers](../extend/controllers). TastyIgniter automatically maps admin URLs to any controller class that extends the `Igniter\Admin\Classes\AdminController` and resides in the extension's `src/Http/Controllers` directory. For example, admin URL `acme/helloworld/messages` will be mapped to the `Acme\HelloWorld\Http\Controllers\Messages` admin controller. + +### Language files + +If your extension contains [language files](../advanced/localization) stored in the extension's `resources/lang` directory, TastyIgniter will automatically load them when the extension is loaded. When developing your extension, you should consider using language strings even if you do not intend to use it in more than one language. You never know: if you decide to make your extension available to users around the world, it can be handy later. + +It's highly recommended to include a complete set of English resources with your extension, especially if you plan to publish your extension in the TastyIgniter marketplace. + +Here's an example of a language file named `default.php` located in `acme/helloworld/resources/lang`: + +```php +return [ + 'label' => 'Hello World', + 'description' => 'Say hello to the rest of the world.', +]; +``` + +To reference these language lines, use the `author.extension::file.key` syntax. For instance, to access the `label` language string from the `acme.helloworld` extension, use the `lang` helper function: + +```php +echo lang('acme.helloworld::default.label'); +``` + +In the example above, `acme.helloworld` prefix is the extension code, `default` is the language file name without the `.php` extension, and `label` is the key of the language string. + +### Views + +If your extension contains views stored in the extension's `resources/views` directory, TastyIgniter will automatically load them when the extension is loaded. + +Extension views are referenced using the `author.extension::view` syntax convention. So, once your extension is loaded, you can load the `hello.blade.php` view file from the `acme.helloworld` extension like so: + +```php +return view('acme.helloworld::hello'); +``` + +#### Overriding extension views + +When TastyIgniter automatically loads your view files, it registers two locations for your views: the application's `resources/views/vendor` directory and the extension's own `resources/views` directory. This setup enables developers to customize or override the views of your extension by placing a modified version in the `resources/views/vendor/author/extension` directory within the application. + +For more information on views, refer to the [Laravel documentation on views](https://laravel.com/docs/views). + +## Using Third-Party composer packages + +There are a number of scenarios that require the developer to add a third-party composer packages to their extension. + +Here is a full example of how the **Igniter.Api** extension adds third-party package `laravel/sanctum`: + +```json +{ + "name": "tastyigniter/ti-ext-api", + "type": "tastyigniter-package", + "require": { + "laravel/sanctum": "^3.0" + }, + "extra": { + "tastyigniter-extension": { + "code": "igniter.api", + "name": "APIs", + "icon": { + "class": "fa fa-cloud", + "color": "#fff", + "backgroundColor": "#02586F" + }, + "homepage": "https://tastyigniter.com/marketplace/item/igniter-api" + } + } +} +``` + +> Do not commit the `/vendor` directory, the `composer.json` file should be committed to the repository. + +## Extending an extension -## Writing tests +Why extend one extension with another? To ensure that the changes remain compatible if the extension is updated. Extensions are mostly used to inject or modify the functionality of core classes and other extensions via the 'Event' dispatcher service. -If you want to start writing a new extension, remember that unit testing helps you deliver extensions of higher quality. +The most common place to subscribe to an event is the extension class `boot` method. diff --git a/extend/form-requests.md b/extend/form-requests.md deleted file mode 100644 index fabf002..0000000 --- a/extend/form-requests.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: "Form Requests" -section: extend -sortOrder: 200 -callout: This section is incomplete. Please help to improve it. ---- - -## Introduction - -### How TastyIgniter resolves Form Requests - - - -## Creating a form request - -### Form request methods - -### Defining the validation rules - - - -## Customising the error messages - - - -## Customising the validation attributes - - - -### - diff --git a/extend/forms.md b/extend/forms.md new file mode 100644 index 0000000..be24df5 --- /dev/null +++ b/extend/forms.md @@ -0,0 +1,1238 @@ +--- +title: "Forms" +section: extend +sortOrder: 230 +--- + +## Introduction + +The `Igniter\Admin\Http\Actions\FormController` class provides a convenient way to create, update, and preview forms in the TastyIgniter admin interface. The `FormController` defines the actions and views needed to manage form submissions, including the ability to define form fields, validation rules, and form widgets. + +## Configuring the form controller + +To use the `FormController` in your extension, you need to add it to the controller's `$implement` property. Also, you should define a `$formConfig` property in your controller and its value should be an array of configuration options. Here is an example of a form controller configuration: + +```php +namespace Author\Extension\Http\Controllers; + +class MyController extends \Igniter\Admin\Classes\AdminController +{ + public array $formConfig = [ + 'name' => 'My Form', + 'model' => 'Author\Extension\Models\Record', + 'request' => 'Author\Extension\Http\Requests\RecordRequest', + 'create' => [ + 'title' => 'Create Record', + ], + 'edit' => [ + 'title' => 'Edit Record', + ], + 'preview' => [ + 'title' => 'Preview Record', + ], + 'configFile' => 'record', + ]; +} +``` + +The following fields are required in the form configuration: + +- `model`: The model class used to load and store form data. +- `configFile`: Reference to the [form definitions file](../extend/forms#form-definition-file). + +The following fields are optional in the form configuration: + +- `name`: The name of the object being managed by this form. +- `request`: The form request class used to validate form fields. +- `create`: Configuration options for the create form view. +- `edit`: Configuration options for the update form view. +- `preview`: Configuration options for the preview form view. + +### Form definition file + +The form definition file is typically located in the extension's `resources/models` directory. The form definition file should return a `form` array of [toolbar buttons](../extend/lists#toolbar-button-options) and [form fields](../extend/lists#scope-options). For example: + +```php +return [ + 'form' => [ + 'toolbar' => [ + 'buttons' => [ + // ... + ], + ], + 'fields' => [ + // ... + ], + ], +]; +``` + +### Create page + +To support the Create page add the following configuration to the form configuration: + +```php +public array $formConfig = [ + // ... + 'create' => [ + 'title' => 'Create Record', + 'redirect' => 'author/extension/records/edit/{id}', + 'redirectClose' => 'author/extension/records', + ], +]; +``` + +The following configuration options are available for the Create page: + +- `title`: The title of the Create page. +- `redirect`: The URL to redirect to after creating a record. +- `redirectClose`: The URL to redirect to after closing the Create page. +- `flashSave`: The flash message to display after creating a record. +- `configFile`: Override the form definition file for the Create page. + +### Edit page + +To support the Update page add the following configuration to the form configuration: + +```php +public array $formConfig = [ + // ... + 'edit' => [ + 'title' => 'Edit Record', + 'redirect' => 'author/extension/records/edit/{id}', + 'redirectClose' => 'author/extension/records', + ], +]; +``` + +The following configuration options are available for the Update page: + +- `title`: The title of the Update page. +- `redirect`: The URL to redirect to after updating a record. +- `redirectClose`: The URL to redirect to after closing the Update page. +- `flashSave`: The flash message to display after updating a record. +- `configFile`: Override the form definition file for the Update page. + +### Preview page + +To support the Preview page add the following configuration to the form configuration: + +```php +public array $formConfig = [ + // ... + 'preview' => [ + 'title' => 'Preview Record', + ], +]; +``` + +The following configuration options are available for the Preview page: + +- `title`: The title of the Preview page. +- `configFile`: Override the form definition file for the Preview page. + +### Restricting with permissions + +You can restrict access to the form controller actions by setting the `$requiredPermissions` property in the controller class. For example, restricting access to the Create page: + +```php +class MyController extends \Igniter\Admin\Classes\AdminController +{ + public null|string|array $requiredPermissions = [ + 'create' => 'Author.Extension.ManageRecord' + ]; +} +``` + +## Defining form fields + +Form fields are defined in the form definition file using the `fields` key. Fields can be placed either in the outside area or primary tabs. Here is an example of a form controller with fields defined in the form definition file `resources/models/record.php`: + +```php +return [ + 'form' => [ + // Outside area + 'fields' => [ + 'name' => [ + 'label' => 'Name', + 'type' => 'text', + 'span' => 'left', + ], + 'email' => [ + 'label' => 'Email', + 'type' => 'text', + 'span' => 'right', + ], + ], + // Primary tabs + 'tabs' => [ + 'fields' => [ + // ... + ], + ], + ], +]; +``` + +### Tab options + +The following options are available for form tabs: + +- `stretch`: Whether the tab should stretch to fit the parent height. +- `defaultTab`: The default tab to assign fields that do not belong to any tab. Default is `General`. + +### Field options + +The following options are available for form fields (where applicable): + +- `label`: The label to display for the field +- `type`: Defines how the field should be rendered (see [Fields types](../extend/forms#available-field-types) below). Default is `text`. +- `span`: Aligns the field. Options are `left`, `right`, `full`. Default is `left`. +- `comment`: A comment to display below the field. +- `commentAbove`: A comment to display above the field. +- `commentHtml`: Allow HTML markup inside the comment. Default is `false`. +- `placeholder`: The placeholder text for the field. +- `default`: The default value for the field. +- `defaultFrom`: References another field to get the default value from. +- `tab`: The tab to assign the field to. +- `readOnly`: Prevents the field from being modified. Default is `false`. +- `disabled`: Prevents the field from being modified and excludes it from the saved data. Default is `false`. +- `hidden`: Hides the field from the form and excludes it from the saved data. Default is `false`. +- `context`: The context in which the field is displayed. Context can also be passed by using an `@` symbol in the field name, for example, `name@update`. +- `trigger`: Use [trigger events](../extend/forms#trigger-events) specify conditions for this field. +- `dependsOn`: Use [field dependencies](../extend/forms#field-dependencies) to update this field based on changes to another field. +- `required`: Places a red asterisk next to the field label. Default is `false`. +- `cssClass`: Additional CSS classes to apply to the field. +- `attributes`: Additional HTML attributes to apply to the field. +- `containerAttributes`: Additional HTML attributes to apply to the field container. +- `permissions`: The [permissions](../extend/permissions) required to view this field. + +## Available field types + +The following native field types are available for form fields. For more advanced form fields, a [form widget](../extend/forms#form-widgets) can be used instead. + +- [Text](../extend/forms#text) +- [Number](../extend/forms#number) +- [Money](../extend/forms#money) +- [Currency](../extend/forms#currency) +- [Password](../extend/forms#password) +- [Email](../extend/forms#email) +- [Permalink](../extend/forms#permalink) +- [URL](../extend/forms#url) +- [Textarea](../extend/forms#textarea) +- [Select](../extend/forms#select) +- [Checkbox](../extend/forms#checkbox) +- [Checkbox list](../extend/forms#checkbox-list) +- [Checkbox toggle](../extend/forms#checkbox-toggle) +- [Radio list](../extend/forms#radio-list) +- [Radio toggle](../extend/forms#radio-toggle) +- [Switch](../extend/forms#switch) +- [Section](../extend/forms#section) +- [Partial](../extend/forms#partial) +- [Widget](../extend/forms#widget) + +### Text + +`text` renders a simple text input field. + +```php +'name' => [ + 'label' => 'Name', + 'type' => 'text', +], +``` + +### Number + +`number` renders an input field that takes only numbers. + +```php +'quantity' => [ + 'label' => 'Quantity', + 'type' => 'number', +], +``` + +### Money + +`money` renders an input field that takes only numbers and formats the value to two decimal places. + +```php +'price' => [ + 'label' => 'Price', + 'type' => 'money', +], +``` + +### Currency + +`currency` renders an input field that takes only numbers and formats the value matching the active currency settings. + +```php +'price' => [ + 'label' => 'Price', + 'type' => 'currency', +], +``` + +### Password + +`password` renders a password input field. + +```php +'password' => [ + 'label' => 'Password', + 'type' => 'password', +], +``` + +### Email + +`email` renders an input field that takes only email addresses. + +```php +'email' => [ + 'label' => 'Email', + 'type' => 'email', +], +``` + +### Permalink + +`permalink` renders an input field that only accepts alphanumeric characters, dashes, and underscores. + +```php +'slug' => [ + 'label' => 'Slug', + 'type' => 'permalink', +], +``` + +### URL + +`url` renders an input field that only accepts valid URLs. + +```php +'website' => [ + 'label' => 'Website', + 'type' => 'url', +], +``` + +### Textarea + +`textarea` renders a textarea input field. + +```php +'description' => [ + 'label' => 'Description', + 'type' => 'textarea', + + // Optional + 'attributes' => [ + 'rows' => 5, + ], +], +``` + +### Select + +`select` renders a dropdown select field. There are 6 ways to provide the dropdown options. All six ways should return an array of options in the format `key => label`. + +Provide an array of **options directly** in the field definition. + +```php +'order_type' => [ + 'label' => 'Order type', + 'type' => 'select', + 'options' => [ + 'delivery' => 'Delivery', + 'collection' => 'Pick-up', + ], +], +``` + +Provide an array of options from a **matching method** `get*FieldName*Options` declared in the model class. Using the example above, the model should declare the `getOrderTypeOptions` method. + +```php +public function getOrderTypeOptions($value, $formData) +{ + return ['delivery' => 'Delivery', ...]; +} +``` + +Additionally, you can declare a **global method** `getDropdownOptions` in the model class to provide dropdown options for all `select` fields. + +```php +public function getDropdownOptions($fieldName, $value, $formData) +{ + if ($fieldName == 'order_type') { + return ['delivery' => 'Delivery', ...]; + } + else { + return ['' => '-- none --']; + } +} +``` + +Provide an array of options from a **specific model method** declared in the model class. + +```php +'order_type' => [ + // ... + 'type' => 'select', + 'options' => 'listOrderTypes' +], +``` + +```php +public function listOrderTypes() +{ + return ['delivery' => 'Delivery', ...]; +} +``` + +Provide an array of options from a **static method** declared on a class. + +```php +'order_type' => [ + // ... + 'type' => 'select', + 'options' => \Author\Extension\Classes\FormHelper::listOrderTypes +], +``` + +```php +public static function listOrderTypes($formWidget, $formField) +{ + return ['delivery' => 'Delivery', ...]; +} +``` + +Provide an array of options from a **callable object** via an array definition. + +```php +'order_type' => [ + // ... + 'type' => 'select', + 'options' => [Author\Extension\Classes\FormHelper::class, 'listOrderTypes'] +], +``` + +```php +public static function listOrderTypes($formWidget, $formField) +{ + return ['delivery' => 'Delivery', ...]; +} +``` + +The following options are available for the `select` field type: + +- `placeholder`: The placeholder text for the field when no option is selected or the field is empty. +- `showSearch`: Whether to enable search functionality in the dropdown. Default is `false`. +- `multiOption`: Whether to allow multiple selections. Default is `false`. + +### Checkbox + +`checkbox` renders a checkbox input field. + +```php +'is_active' => [ + 'label' => 'Is active', + 'type' => 'checkbox', +], +``` + +### Checkbox list + +`checkboxlist` renders a list of checkboxes. Checkbox lists support the same methods for defining the options as the [select field type](../extend/forms#select). + +```php +'colors' => [ + 'label' => 'Colors', + 'type' => 'checkboxlist', + 'options' => [ + 'red' => 'Red', + 'green' => 'Green', + 'blue' => 'Blue', + ], +], +``` +Options for checkbox lists also support secondary descriptions using the array format `key => [label, description]`. + +```php +'colors' => [ + // ... + 'options' => [ + 'red' => ['Red', 'This is the color red'], + 'green' => ['Green', 'This is the color green'], + 'blue' => ['Blue', 'This is the color blue'], + ], +], +``` + +### Checkbox toggle + +`checkboxtoggle` renders a button-like checkbox toggle. Checkbox toggles support the same methods for defining the options as the [select field type](../extend/forms#select). + +```php +'colors' => [ + 'label' => 'Colors', + 'type' => 'checkboxtoggle', + 'options' => [ + 'red' => 'Red', + 'green' => 'Green', + 'blue' => 'Blue', + ], +], +``` + +### Radio list + +`radiolist` renders a list of radio buttons. Radio lists support the same methods for defining the options as the [select field type](../extend/forms#select). These options also support secondary descriptions just like [checkbox lists](../extend/forms#checkbox-list). + +```php +'colors' => [ + 'label' => 'Colors', + 'type' => 'radiolist', + 'options' => [ + 'red' => 'Red', + 'green' => 'Green', + 'blue' => 'Blue', + ], +], +``` + +### Radio toggle + +`radiotoggle` renders a button-like radio toggle. Radio toggles support the same methods for defining the options as the [select field type](../extend/forms#select). + +```php +'color' => [ + 'label' => 'Color', + 'type' => 'radiotoggle', + 'options' => [ + 'red' => 'Red', + 'green' => 'Green', + 'blue' => 'Blue', + ], +], +``` + +### Switch + +`switch` renders a switch toggle field. + +```php +'is_active' => [ + 'label' => 'Is active', + 'type' => 'switch', + 'onText' => 'Yes', + 'offText' => 'No', +], +``` + +### Section + +`section` renders a section heading and subheading. + +```php +'section' => [ + 'label' => 'Section', + 'type' => 'section', + 'comment' => 'This is a section comment', +], +``` + +### Partial + +`partial` renders a partial view. The `path` option should be the path to the partial view file otherwise the field name is used as the partial name. + +```php +'partial' => [ + 'type' => 'partial', + 'path' => 'path/to/partial', +], +``` + +### Widget + +`widget` renders a form widget. The `type` option should be the class name of the form widget or the registered alias name. + +```php +'widget' => [ + 'type' => \Igniter\Admin\FormWidgets\RichEditor::class, +], +``` + +## Form widgets + +TastyIgniter includes several form widgets, although it is common for extensions to provide their own custom form widgets. For a deeper dive into how these widgets work and how you can implement or modify them, you can refer to the [Form Widgets](../extend/widgets#using-form-widget) article. + +- [Code editor](../extend/forms#code-editor) +- [Color picker](../extend/forms#color-picker) +- [Components](../extend/forms#components) +- [Connector](../extend/forms#connector) +- [Data table](../extend/forms#data-table) +- [Date picker](../extend/forms#date-picker) +- [Markdown editor](../extend/forms#markdown-editor) +- [Media finder](../extend/forms#media-finder) +- [Record editor](../extend/forms#record-editor) +- [Relation](../extend/forms#relation) +- [Repeater](../extend/forms#repeater) +- [Rich editor](../extend/forms#rich-editor--wysiwyg) +- [Status editor](../extend/forms#status-editor) +- [Template editor](../extend/forms#template-editor) + +### Code editor + +`codeeditor` renders an editor field for editing code or HTML markup. + +```php +'code' => [ + 'label' => 'Code', + 'type' => 'codeeditor', +], +``` + +The following options are available for the `codeeditor` field type: + +- `mode`: The programming language to use for syntax highlighting. Default is `css`. +- `theme`: The color theme option passed to the CodeMirror JS library. Default is `material`. + +### Color picker + +`colorpicker` renders the browser supported color picker. + +```php +'color' => [ + 'label' => 'Color', + 'type' => 'colorpicker', +], +``` + +The following options are available for the `colorpicker` field type: + +- `availableColors`: An array of colors to display in the color picker for quick color selection. + +### Components + +`components` renders a field for selecting and managing both [theme](../customize/components#theme-component) and [livewire](../customize/components#livewire-component) components from the component library as well as rendering them to a theme template. + +```php +'components' => [ + 'label' => 'Components', + 'type' => 'components', + 'form' => [ + 'fields' => [ + // ... + ], + ], +], +``` + +The following options are available for the `components` field type: + +- `form`: The form definition for the component fields. +- `prompt`: The prompt text to display when no component is selected. +- `addTitle`: The title of the add button. Default is `Add component`. +- `editTitle`: The title of the edit button. Default is `Edit component`. +- `copyPartialTitle`: The title of the override partial button. Default is `Override component partial`. + +### Connector + +`connector` renders a field for attaching and managing related records from a model. + +```php +'products' => [ + 'label' => 'Products', + 'type' => 'connector', + 'form' => [ + 'fields' => [ + 'name' => [ + 'label' => 'Name', + 'type' => 'text', + ], + 'price' => [ + 'label' => 'Price', + 'type' => 'money', + ], + ], + ], +], +``` + +The following options are available for the `connector` field type: + +- `form`: The form definition for creating and managing related records. Either a reference to the [form definition file](../extend/forms#form-definition-file) or an array of fields. +- `formName`: The form name to use for the record editor popup. Default is `Record`. +- `nameFrom`: The model attribute to use as the display name for the related records. Default is `name`. +- `descriptionFrom`: The model attribute to use as the description for the related records. Default is `description`. +- `partial`: The partial view to use for rendering each related record. Leave empty to use the default partial. +- `sortable`: Whether to allow sorting of the related records. Default is `false`. +- `sortColumnName`: The field name to use for sorting the related records. Default is `priority`. +- `editable`: Whether to allow editing of the related records. Default is `true`. +- `newRecordTitle`: The title of the popup when creating a record . Default is `New %s`. +- `editRecordTitle`: The title of the popup when editing a record. Default is `Edit %s`. +- `emptyMessage`: The message to display when there are no related records. For example: `No records found`. +- `confirmMessage`: The message to display when deleting a record. For example: `Are you sure you want to delete this record?`. +- `popupSize`: The size of the popup window. Options are `modal-sm`, `modal-md`, `modal-lg`, `modal-xl`. +- `hideNewButton`: Whether to hide the new related record button. Default is `true`. + +### Data table + +`datatable` renders a table for displaying and editing tabular data. + +```php +'products' => [ + 'label' => 'Products', + 'type' => 'datatable', + 'columns' => [ + 'name' => [ + 'title' => 'Name', + ], + 'price' => [ + 'title' => 'Price', + ], + ], +], +``` + +The following options are available for the `datatable` field type: + +- `columns`: An array of columns to display in the table. Each column should have a `title` definition. +- `defaultSort`: The default column to sort by. Example `name asc`. +- `searchableFields`: The fields to search when filtering the table. +- `showRefreshButton`: Whether to show the refresh button. Default is `true`. +- `useAjax`: Whether to use AJAX to load the table data. Default is `false`. +- `showPagination`: Whether to show pagination controls. Default is `true`. +- `pageLimit`: The number of records to display per page. Default is `10`. +- `dynamicHeight`: Whether to adjust the table height based on the number of records. Default is `false`. +- `height`: The height of the table. Default is `auto`. +- `keyFrom`: The model attribute to use as the primary key. Default is `id`. +- `toolbar`: The configuration of toolbar buttons to display above the table. +- `fieldName`: The custom field name to use for the table. Default to the field alias. + +### Date picker + +`datepicker` renders the browser supported date picker field for selecting dates and times. + +```php +'date' => [ + 'label' => 'Date', + 'type' => 'datepicker', +], +``` + +The following options are available for the `datepicker` field type: + +- `mode`: The date picker mode. Options are `date`, `time`, `datetime`. Default is `date`. +- `dateFormat`: The date format to use when displaying the date. Default is `Y-m-d`. +- `timeFormat`: The time format to use when displaying the time. Default is `H:i`. +- `startDate`: The minimum date that can be selected. +- `endDate`: The maximum date that can be selected. + +### Markdown editor + +`markdown` renders an editor field for editing markdown content. + +```php +'markdown' => [ + 'label' => 'Markdown', + 'type' => 'markdown', +], +``` + +The following options are available for the `markdown` field type: + +- `mode`: The editor view mode. Options are `tab` or `split`. Default is `tab`. + +### Media finder + +`mediafinder` renders a field for selecting media files from the media library. + +```php +'image' => [ + 'label' => 'Image', + 'type' => 'mediafinder', +], +``` + +The following options are available for the `mediafinder` field type: + +- `mode`: The media finder view mode. Options are `grid`, `inline`. Default is `grid`. +- `prompt`: The prompt text to display when no media is selected. +- `isMulti`: Whether to allow multiple media selections. Default is `false`. +- `useAttachment`: Whether to use the attachment ID instead of the media path. Default is `false`. +- `thumbOptions`: Configuration options for generating media thumbnails. Default is `['fit' => 'contain', 'width' => 122, 'height' => 122]`. + +### Record editor + +`recordeditor` renders a field for selecting and managing records from a model. + +```php +'products' => [ + 'label' => 'Products', + 'type' => 'recordeditor', + 'modelClass' => 'Author\Extension\Models\Product', + 'form' => [ + 'fields' => [ + 'name' => [ + 'label' => 'Name', + 'type' => 'text', + ], + 'price' => [ + 'label' => 'Price', + 'type' => 'money', + ], + ], + ], +], +``` + +The following options are available for the `recordeditor` field type: + +- `modelClass`: The model class to use for fetching records. +- `form`: The form definition for creating and managing records. Either a reference to the [form definition file](../extend/forms#form-definition-file) or an array of fields. +- `formName`: The form name to use for the record editor popup. Default is `Record`. +- `addonRight`: An array of button options (see below) to display on the right side of the record editor. +- `addonLeft`: An array of button options (see below) to display on the left side of the record editor. +- `popupSize`: The size of the popup window. Options are `modal-sm`, `modal-md`, `modal-lg`, `modal-xl`. +- `hideEditButton`: Whether to hide the edit button. Default is `false`. +- `hideDeleteButton`: Whether to hide the delete button. Default is `false`. +- `hideCreateButton`: Whether to hide the create button. Default is `false`. +- `attachToField`: The field name to attach the selected record to. +- `addLabel`: The label to display on the create button. Default is `Add`. +- `editLabel`: The label to display on the edit button. Default is `Edit`. +- `deleteLabel`: The label to display on the delete button. Default is `Delete`. +- `attachLabel`: The label to display on the attach button. Default is `Attach`. + +The following options are available for the `addonRight` and `addonLeft` buttons: + +- `label`: The button label. +- `tag`: The button tag. Options are `div`, `button`, `a`. Default is `div`. +- `attributes`: Additional HTML attributes to apply to the button. Define as an array of key-value pairs. + +### Relation + +`relation` renders a single or multiple selection dropdown field for selecting related records. The label used for displaying each relation is retrieved by the `nameFrom` or `select` definition. + +```php +'category_id' => [ + 'label' => 'Category', + 'type' => 'relation', + 'relationFrom' => 'category', + 'nameFrom' => 'name', +], +``` + +The following options are available for the `relation` field type: + +- `relationFrom`: The relation name to use for fetching related records, if different from the field name. +- `nameFrom`: The model attribute name to use for displaying the related label. +- `select`: A custom SQL select statement to use for each relation item label. +- `order`: Used to sort options. Example `name asc`. +- `scope`: A custom query scope method to apply to the relation query. +- `emptyOption`: The text to display for the empty option. Default is `-- none --`. + +### Repeater + +`repeater` renders a field for repeating a set of fields. + +```php +'products' => [ + 'label' => 'Products', + 'type' => 'repeater', + 'form' => [ + 'fields' => [ + 'name' => [ + 'label' => 'Name', + 'type' => 'text', + ], + 'price' => [ + 'label' => 'Price', + 'type' => 'money', + ], + ], + ], +], +``` + +The following options are available for the `repeater` field type: + +- `form`: The form definition for the fields to repeat. Either a reference to the [form definition file](../extend/forms#form-definition-file) or an array of fields. +- `prompt`: The text to display for the create button. Default is `Add item`. +- `sortable`: Whether to allow sorting of the repeater items. Default is `false`. +- `sortColumnName`: The column name to use for sorting the repeater items. Default is `priority`. +- `showAddButton`: Whether to show the add button. Default is `true`. +- `showRemoveButton`: Whether to show the remove button. Default is `true`. +- `emptyMessage`: The message to display when there are no items in the repeater. Default is `lang:igniter::admin.text_empty`. + +### Rich editor / WYSIWYG + +`richeditor` renders a rich text editor field for editing HTML content. + +```php +'content' => [ + 'label' => 'Content', + 'type' => 'richeditor', +], +``` + +The following options are available for the `richeditor` field type: + +- `size`: The size of the editor. Options are `small`, `large`. Default is `large`. +- `toolbarButtons`: The buttons to display in the editor toolbar. + +### Status editor + +`statuseditor` renders a field for updating status and assignee for orders and reservations. + +```php +'status' => [ + 'label' => 'Status', + 'type' => 'statuseditor', + 'form' => [ + 'fields' => [ + 'status_id' => [ + 'label' => 'Status', + 'type' => 'select', + 'options' => 'listStatuses', + ], + 'assignee_id' => [ + 'label' => 'Assignee', + 'type' => 'select', + 'options' => 'listAssignees', + ], + ], + ], +], +``` + +The following options are available for the `statuseditor` field type: + +- `form`: The form definition for creating and managing status and assignee. Either a reference to the [form definition file](../extend/forms#form-definition-file) or an array of fields. +- `formTitle`: The title of the popup window. Default is `Add %s`. +- `statusFormName`: The form name to use for the status editor popup. +- `assigneeFormName`: The form name to use for the assignee editor popup. +- `statusKeyFrom`: The model attribute to use as the primary key for the status. +- `assigneeKeyFrom`: The model attribute to use as the primary key for the assignee. +- `assigneeGroupKeyFrom`: The model attribute to use as the primary key for the assignee group. +- `statusNameFrom`: The model attribute to use as the display name for the status. +- `assigneeNameFrom`: The model attribute to use as the display name for the assignee. +- `assigneeGroupNameFrom`: The model attribute to use as the display name for the assignee group. +- `statusColorFrom`: The model attribute to use as the color for the status. +- `statusRelationFrom`: The relation name to use for fetching status records. +- `assigneeRelationFrom`: The relation name to use for fetching assignee records. + +### Template editor + +`templateeditor` renders a field for editing theme template files. + +```php +'content' => [ + 'label' => 'Content', + 'type' => 'templateeditor', +], +``` + +The following options are available for the `templateeditor` field type: + +- `form`: The form definition for creating and managing [layouts](../customize/layouts) and [pages](../customize/pages) template files. Either a reference to the [form definition file](../extend/forms#form-definition-file) or an array of fields. +- `formName`: The form name to use for the template editor popup. +- `addLabel`: The label to display on the add button. +- `editLabel`: The label to display on the edit button. +- `deleteLabel`: The label to display on the delete button. +- `placeholder`: The placeholder text to display when no template is selected. + +## Displaying the form + +TastyIgniter provides a view file with the corresponding name (`create.blade.php`, `edit.blade.php` and `preview.blade.php`) for each page supported by form controllers, so you don't have to create them manually. + +You can use the `renderForm` method on the `FormController` class to render the form fields. The first argument is an array of options to pass to the form fields, and the second argument is a boolean value indicating whether to render the toolbar buttons. + +### Create page + +Here is an example of what the `create.blade.php` blade view file might look like: + +```blade +{!! form_open([ + 'id' => 'edit-form', + 'role' => 'form', + 'method' => 'POST', +]) !!} + + {!! $this->renderFormToolbar() !!} + + {!! $this->renderForm([], true) !!} + +{!! form_close() !!} +``` + +In the example above, the `renderForm` method is used to render the form fields. The first argument is an array of options to pass to the form fields, and the second argument is a boolean value indicating whether to render the toolbar buttons. + +### Edit page + +Here is an example of what the `edit.blade.php` blade view file might look like: + +```blade +{!! form_open([ + 'id' => 'edit-form', + 'role' => 'form', + 'method' => 'PATCH', +]) !!} + + {!! $this->renderFormToolbar() !!} + + {!! $this->renderForm([], true) !!} + +{!! form_close() !!} +``` + +> Notice the `PATCH` method used in the form open tag. + +### Preview page + +Here is an example of what the `preview.blade.php` blade view file might look like: + +```blade +{!! form_open([ + 'id' => 'edit-form', + 'role' => 'form', + 'method' => 'POST', +]) !!} + + {!! $this->renderFormToolbar() !!} + + {!! $this->renderForm(['preview' => true], true) !!} + +{!! form_close() !!} +``` + +## Applying conditions to fields + +Sometimes you want to manipulate the value or visibility of a form field based on specific rules, such as hiding an input if a checkbox is selected. There are few ways to achieve this, including using the trigger API or field dependencies. These options are discussed in more detail below. + +### Input preset converter + +The input preset converter is a way to convert the value of a field based of the value in another field. You can use the `preset` property in the field definition to define `preset` options. For example, to convert a value on the `title` field to a _slug_ on the `permalink` field: + +```php +'title' => [ + 'label' => 'Title', + 'type' => 'text', +], +'permalink' => [ + 'label' => 'Permalink', + 'type' => 'permalink', + 'preset' => [ + 'field' => 'title', + 'type' => 'slug', + ], +], +``` + +The following options are available for the `preset` property: + +- `field`: The name of the other field that this field get its value from. +- `type`: The type of preset to apply. Options are `exact`, `slug`, `url`, `camelCase`, and `file`. +- `prefixInput`: The CSS Selector of the input element to get the prefix value from. + +### Trigger events + +In TastyIgniter, you can apply conditions to form fields using the `trigger` property in the field definition. This allows you to create dynamic forms where the visibility or value of a field can change based on the state of other fields. For example, to show a field only when a checkbox is selected: + +```php +'is_active' => [ + 'label' => 'Is active', + 'type' => 'checkbox', +], +'activation_date' => [ + 'label' => 'Activation Date', + 'type' => 'datepicker', + 'trigger' => [ + 'action' => 'show', + 'field' => 'is_active', + 'condition' => 'checked', + ], +], +``` + +In this example, the `activation_date` field will only be shown if the `is_active` checkbox is checked. The trigger property is an array that defines the following keys: + +- `action`: The action to perform. It can be `show`, `hide`, `enable`, `disable`. +- `field`: The name of the other field that this field is dependent on. +- `condition`: The condition that must be met for the action to be performed. It can be `checked`, `unchecked`, `value[somevalue]`. + +### Field dependencies + +Field dependencies are a way to update a field based on changes to another field. You can use the `dependsOn` property in the field definition to define the field dependencies. The `dependsOn` property is a string that defines the name of the other field that this field is dependent on. For example: + +```php +'is_active' => [ + 'label' => 'Is active', + 'type' => 'checkbox', +], +'activation_date' => [ + 'label' => 'Activation Date', + 'type' => 'datepicker', + 'dependsOn' => 'is_active', +], +``` + +In this example, the `activation_date` field will be updated whenever the `is_active` checkbox is changed. + +### Preventing a field from being submitted + +In TastyIgniter, you can prevent a field from being submitted by prefixing the field name with an underscore `_`. Form fields beginning with underscore will be excluded from the saved data. For example: + +```php +'_map' => [ + 'label' => 'Point your address on the map', + 'type' => 'mapview', +], +``` + +Additionally, you can add the `disabled` property to the field definition to prevent the field from being modified and exclude it from the saved data. For example: + +```php +'map' => [ + 'label' => 'Point your address on the map', + 'type' => 'mapview', + 'disabled' => true, +], +``` + +## Validating form fields + +To validate the fields of your form you should add a form request class to the `request` key in the form controller configuration `$formConfig` property. The form request class should extend the `Igniter\System\Classes\FormRequest` class and define a `rules` method that returns an array of validation rules. See [Validation](../advanced/validation) for more information on how to define validation rules. + +## Extending the form controller + +You may need to extend the form controller to add custom functionality. There are several ways to extend the form controller: + +### Overriding controller action + +You can override the `create`, `edit` and `preview` controller action by defining a method with the same name in your controller, then optionally call the parent method to execute the default action. For example: + +```php +public function edit($recordId, $context = null) +{ + // Your custom logic here + + $this->asExtension('FormController')->edit($recordId, $context); +} +``` + +### Overriding form views + +You can override the form views by creating a new view file in the extension's `resources/views` directory. The view file should have the same name as the form view file you want to override. For example, to override the `create.blade.php` view file rendered from `MyController`, create a new view file in the `resources/views/mycontroller` directory with the same name. Here is an example adding a sidebar to the form **create** page: + +```blade +
+
+ {!! form_open([ + 'id' => 'edit-form', + 'role' => 'form', + 'method' => 'POST', + ]) !!} + {!! $this->renderFormToolbar() !!} + {!! $this->renderForm([], true) !!} + {!! form_close() !!} +
+
+
+
+
Sidebar
+

This is a sidebar

+
+
+
+
+``` + +### Extending form model query + +You can extend the model query by overriding the `formExtendQuery` method in your controller. This method is called before the form fields are rendered and can be used to modify the query used to fetch the model data. For example: + +```php +public function formExtendQuery($query) +{ + return $query->where('status', 'active'); +} +``` + +Or, you can use the `admin.controller.extendFormQuery` event to extend the query from another extension. For example: + +```php +Event::listen('admin.form.extendQuery', function ($controller, $query) { + if ($controller instanceof MyController) { + $query->where('status', 'active'); + } +}); +``` + +### Extending form fields + +You can extend the form fields by overriding the `formExtendFields` method in your controller. This method is called before the form fields are rendered and can be used to add or modify form fields. For example: + +```php +public function formExtendFields(Form $widget) +{ + $widget->addFields([ + 'is_active' => [ + 'label' => 'Is active', + 'type' => 'switch', + ], + ]); +} +``` + +Or, you can use the `admin.form.extendFields` event to extend the form fields from another extension. For example: + +```php +Event::listen('admin.form.extendFields', function (Form $widget, $fields) { + if ($widget->getController() instanceof MyController) { + $widget->addFields([ + 'is_active' => [ + 'label' => 'Is active', + 'type' => 'switch', + ], + ]); + } +}); +``` + +Additionally, you can override the `formExtendFieldsBefore` method in your controller or use the `admin.form.extendFieldsBefore` event to modify the query before the form fields are rendered. For example: + +```php +public function formExtendFieldsBefore(Form $widget) +{ + unset($widget->fields['name']); +} + +// Or use the event + +Event::listen('admin.form.extendFieldsBefore', function (Form $widget, $query) { + if ($widget->getController() instanceof MyController) { + unset($widget->fields['name']); + } +}); +``` + +### Filtering form fields + +You may filter the form field definitions by overriding the `filterFields` method of the Model used. This lets you change the visibility and other field properties based on model data. The method accepts three parameters. `$widget` form widget object, `$fields` an array containing the fields defined by the field configuration, and `$context` the active form context. + +```php +public function filterFields($widget, &$fields, $context = null) +{ + if ($this->source_type == 'http') { + $fields['source_url']['hidden'] = true; + } + + if ($this->source_type == 'file') { + $fields['source_file']['hidden'] = true; + } +} +``` \ No newline at end of file diff --git a/extend/lists.md b/extend/lists.md new file mode 100644 index 0000000..8dc930f --- /dev/null +++ b/extend/lists.md @@ -0,0 +1,692 @@ +--- +title: "Lists" +section: extend +sortOrder: 240 +--- + +## Introduction + +The `Igniter\Admin\Http\Actions\ListController` provide a way to display a list of records from a model and handle user interaction such as searching, sorting, filtering, and pagination. + +## Configuring the list controller + +To use the `ListController` in your extension, you need to add it to the controller's `$implement` property. Also, you should define a `$listConfig` property in your controller and its value should be an array of configuration options. Here is an example of a list controller configuration: + +```php +namespace Author\Extension\Http\Controllers; + +class MyController extends \Igniter\Admin\Classes\AdminController +{ + public array $listConfig = [ + 'model' => 'Author\Extension\Models\Record', + 'title' => 'Records', + 'emptyMessage' => 'No records found', + 'defaultSort' => ['id', 'DESC'], + 'configFile' => 'record', + ]; +} +``` + +The following fields are required in the list configuration: + +- `model` - The model class name to use for the list. +- `configFile` - Reference to the [list definition file](../extend/lists#list-definition-file). + +The configuration options listed below are optional. + +- `title` - The title of the list. +- `emptyMessage` - The message to display when no records are found. +- `showSorting` - Whether to show sorting controls. Default is `true`. +- `defaultSort` - The default sort order for the list. The value should be an array with the column name and sort direction. +- `pageLimit` - The number of records to display per page. Default is `20`. +- `showPageNumbers` - Whether to show page numbers. Default is `true`. +- `showCheckboxes` - Whether to show checkboxes for each record. +- `showSetup` - Whether to show the setup button. Default is `true`. + +### List definition file + +The list definition file is typically located in the extension's `resources/models` directory. The list definition file should return a `list` array of [toolbar buttons](../extend/lists#toolbar-button-options), [filter scopes](../extend/lists#scope-options) and [lists columns](../extend/lists#column-options) definitions. For example: + +```php +return [ + 'list' => [ + 'toolbar' => [ + 'buttons' => [ + // ... + ], + ], + 'filter' => [ + 'search' => [ + 'prompt' => 'Search records', + 'mode' => 'all', + ], + 'scopes' => [ + // ... + ], + ], + 'columns' => [ + // ... + ], + ], + // ... +]; +``` + +## Adding a Toolbar + +You can add a toolbar to the list controller by defining a `toolbar` key in the list definition file. The toolbar configuration should be an array of toolbar buttons. Here is an example of a list controller with a toolbar defined in the list definition file `resources/models/record.php`: + +```php +return [ + 'list' => [ + 'toolbar' => [ + 'buttons' => [ + 'new' => [ + 'label' => 'New Record', + 'class' => 'btn btn-primary', + 'href' => 'author/extension/mycontroller/create', + ], + ], + ], + ], +]; +``` + +### Toolbar button options + +For each toolbar button, you can specify these options: + +- `type` - The type of button to display. Available types are: `link`, `button`, `dropdown`. Default is `link`. +- `label` - The label to display for the button. +- `context` - The context to apply to the button. Default is `primary`. +- `disabled` - Whether the button is disabled. Default is `false`. +- `partial` - The partial view to render when the button is clicked. +- `permissions` - The [permissions](../extend/permissions) required to access the button. +- `class` - The CSS class to apply to the button. +- `href` - The URL to link to when the button is clicked. + +## Filtering the list + +You can filter the list by defining a `filter` key in the list definition file. The filter configuration should be an array of the search configuration and filter scopes. Here is an example of a list controller with a filter defined in the list definition file `resources/models/record.php`: + +```php +return [ + 'list' => [ + 'filter' => [ + 'search' => [ + 'prompt' => 'Search records', + 'mode' => 'all', + ], + 'scopes' => [ + 'status' => [ + 'label' => 'Status', + 'type' => 'switch', + 'conditions' => 'status = :filtered', + ], + ], + ], + ], +]; +``` + +### Search options + +For the search filter, you can specify these options: + +- `prompt` - The placeholder text to display in the search input. +- `mode` - The search mode to use. Available modes are: `all`, `any`, `exact`. Default is `all`. +- `scope` - The query scope method defined in the list model to apply to the search query. + +### Scope options + +For each scope you can specify these options (where applicable): + +- `label` - The label to display for the filter scope. +- `type` - The type of filter scope to display. +- `conditions` - The raw where query statement to apply to the list query. `:filtered` parameter represents the filtered value(s). +- `default` - The default value for the filter scope. +- `options` - An array of options to display in the filter scope dropdown. +- `scope` - The query scope method defined in the list model to apply to the list query. +- `nameFrom` - The model attribute to use as the label of the filter scope. +- `permissions` - The [permissions](../extend/permissions) required to access the filter scope. + +### Available filter scope types + +These types can be used to determine how the filter scope should be displayed. + +- [Switch](../extend/lists#switch) +- [Select](../extend/lists#select) +- [Select list](../extend/lists#select-list) +- [Date](../extend/lists#date) +- [Date range](../extend/lists#date-range) +- [Checkbox](../extend/lists#checkbox) + +#### Switch + +`switch` used as a switch to toggle between two predefined conditions. + +```php +'status' => [ + 'label' => 'Status', + 'type' => 'switch', + 'default' => 1, + 'conditions' => ['status <> true', 'status = :filtered'], +], +``` + +#### Select + +`select` used as a dropdown to apply a predefined condition to the list. + +```php +'status' => [ + 'label' => 'Status', + 'type' => 'select', + 'conditions' => 'status = :filtered', + 'options' => [ + 'active' => 'Active', + 'inactive' => 'Inactive', + ], +], +``` + +#### Select list + +`selectlist` used as a dropdown to apply one or more predefined conditions to the list. + +```php +'status' => [ + 'label' => 'Status', + 'type' => 'selectlist', + 'conditions' => 'status = :filtered', + 'options' => [ + 'active' => 'Active', + 'inactive' => 'Inactive', + ], +], +``` + +#### Date + +`date` displays a date picker for a single date to be selected and applied to the list. + +```php +'date' => [ + 'label' => 'Date', + 'type' => 'date', + 'conditions' => 'date = :filtered', +], +``` + +#### Date range + +`daterange` - Date range picker + +#### Checkbox + +`checkbox` - Checkbox input + +## Defining list columns + +You can define the columns to display in the list by defining a `columns` key in the list definition file. The columns configuration should be an array of column definitions. Here is an example of a list controller with columns defined in the list definition file `resources/models/record.php`: + +```php +return [ + 'list' => [ + 'columns' => [ + 'name' => [ + 'label' => 'Name', + 'searchable' => true, + ], + 'email' => [ + 'label' => 'Email', + 'searchable' => true, + ], + ], + ], +]; +``` + +### Column options + +For each column can specify these options (where applicable): + +- `label` - The label to display for the column. +- `type` - The type of column to display (see [Column types](../extend/lists#available-column-types) below). Default is `text`. +- `default` - The default value for the column. +- `searchable` - Whether the column is searchable. Default is `false`. +- `sortable` - Whether the column is sortable. Default is `true`. +- `invisible` - Whether the column is visible. Default is `false`. +- `select` - Defines a custom SQL select statement to use for the value. +- `relation` - The model relationship name to use to fetch the column value. +- `valueFrom` - The model attribute to use as the column value. +- `cssClass` - The CSS class to apply to the column container. +- `width` - The width of the column. Default is `auto`. +- `permissions` - The [permissions](../extend/permissions) required to access the column. + +### Available column types + +There are various column types that can be used to control how the list column is displayed. + +- [Text](../extend/lists#text) +- [Switch](../extend/lists.md#switch-1) +- [Money](../extend/lists#money) +- [Currency](../extend/lists#currency) +- [Date](../extend/lists#date-1) +- [Time](../extend/lists#time) +- [Datetime](../extend/lists#datetime) +- [Time since](../extend/lists#time-since) +- [Time tense](../extend/lists#time-tense) +- [Date since](../extend/lists#date-since) +- [Partial](../extend/lists#partial) + +#### Text + +`text` displays a text column. The `type` key is optional and defaults to `text`. + +```php +'name' => [ + 'label' => 'Name', + 'searchable' => true, +], +``` + +#### Switch + +`switch` displays on or off state for boolean columns. + +```php +'is_active' => [ + 'label' => 'Active', + 'type' => 'switch', +], +``` + +#### Money + +`money` displays a column with a numeric value formatted to two decimal places. + +```php +'price' => [ + 'label' => 'Price', + 'type' => 'money', +], +``` + +#### Currency + +`currency` displays a column with a numeric value formatted with a currency symbol. + +```php +'price' => [ + 'label' => 'Price', + 'type' => 'currency', +], +``` + +#### Date + +`date` displays the column value as date format `MMM DD, YYYY` - **Dec 01, 2024**. You can customise this format setting the value of `format` key in the column configuration. + +```php +'date' => [ + 'label' => 'Date', + 'type' => 'date', + 'format' => 'MMM DD, YYYY', // Optional +], +``` + +#### Time + +`time` displays the column value as time format `hh:mm a` - **09:05 pm**. You can customise this format setting the value of `format` key in the column configuration. + +```php +'time' => [ + 'label' => 'Time', + 'type' => 'time', + 'format' => 'hh:mm a', // Optional +], +``` + +#### Datetime + +`datetime` displays the column value as datetime format `DD MMMM YYYY HH:mm` - **01 December 2024 16:05**. You can customise this format setting the value of `format` key in the column configuration. + +```php +'datetime' => [ + 'label' => 'Datetime', + 'type' => 'datetime', + 'format' => 'DD MMMM YYYY HH:mm', // Optional +], +``` + +#### Time since + +`timesince` displays the human-readable time difference from the column value to the current time. Eg: **10 days ago**, **20 minutes ago**, **Just now** + +```php +'timesince' => [ + 'label' => 'Time Since', + 'type' => 'timesince', +], +``` + +#### Time tense + +`timetense` displays 24-hour time and the day using the grammatical tense of the current date. Eg: **Today at 14:59**, **Yesterday at 4:00** or **18 Sep 2023 at 16:23**. + +```php +'timetense' => [ + 'label' => 'Time Tense', + 'type' => 'timetense', +], +``` + +#### Date since + +`datesince` displays the column value using the grammatical tense of the current date. Eg: **Today**, **Yesterday**, **18 Sep 2023** + +```php +'datesince' => [ + 'label' => 'Date Since', + 'type' => 'datesince', +], +``` + +#### Partial + +`partial` displays a partial view in the column. The `path` key is required and should be the path to the partial view file. + +```php +'partial' => [ + 'label' => 'Partial', + 'type' => 'partial', + 'path' => '/path/to/partial', +], +``` + +## Displaying the list + +Typically, lists are rendered in the `index` blade view file. Because lists include the toolbar and filters, the view file will look like this: + +```blade +{!! $this->renderListToolbar() !!} + +{!! $this->renderListFilter() !!} + +{!! $this->renderList(null, true) !!} +``` + +## Multiple list definitions + +You can define multiple list configurations on the `$listConfig` property by using the `lists` key. Each list configuration should be an array of configuration options. Here is an example of `$listConfig` property with multiple list configurations: + +```php +public array $listConfig = [ + 'list1' => [ + 'model' => 'Author\Extension\Models\Record', + 'title' => 'Records', + 'emptyMessage' => 'No records found', + 'defaultSort' => ['id', 'DESC'], + 'configFile' => 'record', + ], + 'list2' => [ + 'model' => 'Author\Extension\Models\Record', + 'title' => 'Records', + 'emptyMessage' => 'No records found', + 'defaultSort' => ['id', 'DESC'], + 'configFile' => 'record', + ], +]; +``` + +Each defined list can be rendered by passing the list name as an argument to the `renderList` method. For example: + +```php +{!! $this->renderList('list1', true) !!} +``` + +## Extending list controller + +You may need to extend the list controller to add custom functionality. There are several ways to extend the list controller: + +### Extending the list configuration + +You can extend the list configuration by overriding the `listExtendConfig` method in the controller. Here is an example of extending the list configuration: + +```php +public function listExtendConfig($config, $listName) +{ + if ($listName === 'list1') { + $config['toolbar']['buttons']['new'] = [ + 'label' => 'New Record', + 'class' => 'btn btn-primary', + 'href' => 'author/extension/mycontroller/create', + ]; + } + + return $config; +} +``` + +### Overriding controller action + +You can override the controller action by defining a method with the same name as the action method in the controller. Here is an example of overriding the `index` action: + +```php +public function index() +{ + // Call the ListController action index() method + $this->asExtension('ListController')->index(); +} +``` + +### Overriding views + +You can override the list views by creating a new view file in the extension's `resources/views` directory. The view file should have the same name as the list view file you want to override. For example, to override the `index.blade.php` view file rendered from `MyController`, create a new view file in the `resources/views/mycontroller` directory with the same name. Here is an example adding a sidebar to the list: + +```blade +
+
+ +
+
+ {!! $this->renderListToolbar() !!} + + {!! $this->renderListFilter() !!} + + {!! $this->renderList(null, true) !!} +
+
+``` + +### Extending column definitions + +You can extend the list columns by overriding the `listExtendColumns` method in the controller: + +```php +public function listExtendColumns(Lists $widget, $model) +{ + if (!$model instanceof MyModel) { + return; + } + + $list->addColumns([ + 'my_column' => [ + 'label' => 'My Column' + ] + ]); +} +``` + +Or, you can use the `admin.list.extendColumns` event to extend the list columns from another extension: + +```php +Event::listen('admin.list.extendColumns', function (Lists $widget, $model) { + if (!$model instanceof MyModel) { + return; + } + + $list->addColumns([ + 'my_column' => [ + 'label' => 'My Column' + ] + ]); +}); +``` + +### Extending filter scopes + +You can extend the list filter scopes by overriding the `listFilterExtendScopes` method in the controller: + +```php +public function listFilterExtendScopes(Filter $widget, $scopes) +{ + if (!$widget->getController() instanceof MyController) { + return; + } + + // Add a new filter scope + $widget->addScopes([ + 'my_scope' => [ + 'label' => 'My Scope', + 'conditions' => 'my_column = :filtered', + ] + ]); +} +``` + +Or, you can use the `admin.filter.extendScopes` event to extend the filter scopes from another extension: + +```php +Event::listen('admin.filter.extendScopes', function (Filter $widget, $scopes) { + if (!$widget->getController() instanceof MyController) { + return; + } + + // Add a new filter scope + $widget->addScopes([ + 'my_scope' => [ + 'label' => 'My Scope', + 'conditions' => 'my_column = :filtered', + ] + ]); +}); +``` + +Additionally, you can override the `listFilterExtendScopesBefore` method in your controller or use the `admin.filter.extendScopesBefore` event to modify the filter scope definitions before any of the filter scopes object is created: + +```php +public function listFilterExtendScopesBefore(Filter $widget) +{ + if (!$widget->getController() instanceof MyController) { + return; + } + + unset($widget->scopes['status']); +} + +// Or use the event + +Event::listen('admin.filter.extendScopesBefore', function (Filter $widget) { + if (!$widget->getController() instanceof MyController) { + return; + } + + unset($widget->scopes['status']); +}); +``` + +### Extending the list model query + +You can extend the list query by overriding the `listExtendQuery` method in the controller: + +```php +public function listExtendQuery($query, $alias) +{ + return $query->where('status', 'active'); +} +``` + +Or, you can use the `admin.list.extendQuery` event to extend the list query from another extension: + +```php +Event::listen('admin.list.extendQuery', function ($widget, $query) { + if (!$widget->getController() instanceof MyController) { + return; + } + + return $query->where('status', 'active'); +}); +``` + +Additionally, you can override the `listExtendQueryBefore` method in your controller or use the `admin.list.extendQueryBefore` event to modify the query just after the query builder is created, and before any conditions are applied: + +```php +public function listExtendQueryBefore($query, $alias) +{ + return $query->where('status', 'active'); +} + +// Or use the event + +Event::listen('admin.list.extendQueryBefore', function ($widget, $query) { + if (!$widget->getController() instanceof MyController) { + return; + } + + return $query->where('status', 'active'); +}); +``` + +### Extending the filter model query + +You can extend the filter query by overriding the `listFilterExtendQuery` method in the controller: + +```php +public function listFilterExtendQuery($query, $scope) +{ + if ($scope->scopeName == 'status') { + $query->where('status', 'active'); + } +} +``` + +Or, you can use the `admin.filter.extendQuery` event to extend the filter query from another extension: + +```php +Event::listen('admin.filter.extendQuery', function ($widget, $query, $scope) { + if (!$widget->getController() instanceof MyController) { + return; + } + + if ($scope->scopeName == 'status') { + $query->where('status', 'active'); + } +}); +``` + +### Extending the records collection + +You can extend the records collection by overriding the `listExtendRecords` method in the controller: + +```php +public function listExtendRecords($records) +{ + return $records->where('status', 'active'); +} +``` + +Or, you can use the `admin.list.extendRecords` event to extend the records collection from another extension: + +```php +Event::listen('admin.list.extendRecords', function ($widget, $records) { + if (!$widget->getController() instanceof MyController) { + return; + } + + return $records->where('status', 'active'); +}); +``` diff --git a/extend/permissions.md b/extend/permissions.md new file mode 100644 index 0000000..d93f58a --- /dev/null +++ b/extend/permissions.md @@ -0,0 +1,109 @@ +--- +title: "Permissions" +section: customize +sortOrder: 290 +--- + +## Introduction + +The Permissions system in TastyIgniter is designed to manage access and restrictions to the admin interface and its features. Permissions are assigned to staff roles, and staff roles are assigned to staff members. Staff members inherit the permissions of the roles they are assigned. + +Super Admins are identified by the `super_user` flag set to `true`. Below them are Administrators who have varying levels of permissions. Super Admins have unrestricted access to the entire system and can only be managed by themselves or other Super Admins. Regular administrators, regardless of whether they possess the `Admin.Staff` permission, cannot access or modify Super Admin accounts. + +## How Permissions Work + +Permissions in TastyIgniter are represented by string keys formatted as `Author.Extension.Permission`. These permissions are assigned to an administrator via the staff's role, which inherits specific permissions. + +For instance, if administrator _Sam_ is part of the _Chef_ role and the _Chef_ role includes the `Admin.AssignOrder` permission, Sam will inherit the ability to manage orders. Staff Roles function as named groups of permissions, defining the role of an administrator within the system. A staff member can be assigned only one role at a time, but multiple staff members can share the same role. TastyIgniter comes with four predefined system roles: `owner`, `manager`, `waiter`, and `delivery`. Additionally, you can create and assign any number of custom roles with unique permission combinations to administrators. + +It's important to note that Staff Groups are unrelated to permissions. They serve purely as an administrative tool for organizing administrators. For example, groups can be used to assign tasks to all administrators in the Kitchen, facilitating management and coordination. + +## Registering permissions + +Administrator permissions in TastyIgniter can be registered by extensions by overriding the `registerPermissions` method in the [Extension class](../extend/extensions#extension-class). Permissions are defined as an array where the keys are the permission name, and the values provide details about the permission group and descriptions. Each permission key follows a format that includes the name of the author, the name of the extension, and the name of the function. + +Here is an example of how permissions might be registered: + +```php +public function registerPermissions(): array +{ + return [ + 'Author.Extension.ManageSettings' => [ + 'group' => 'Configuration', + 'label' => 'Manage extension settings' + ], + ]; +} +``` + +In this example, each key `Author.Extension.ManageSettings` represents a specific action or capability within the extension that can be enabled or disabled per administrator. The `group` and `label` provide context and description for these permissions, making it easier to understand and manage within the admin interface. + +## Wildcard permissions + +Additionally, you can use the asterisk symbol (`*`) to represent a wildcard, indicating the "all permissions" condition within a specific scope. This allows any administrator with permissions starting with a specific prefix to access the controller pages. For example: + +```php +public $requiredPermissions = ['Author.Extension.*']; +``` + +This setup means that any administrator with permissions that begin with `Author.Extension.` (such as `Author.Extension.Create`, `Author.Extension.Edit`, etc.) will have access to the pages controlled by the `StaticPages` controller. This wildcard approach is useful for granting access to multiple permissions at once. + +## Restricting access to admin pages + +In the [admin controller](../extend/controllers) class of TastyIgniter, you can specify the required permissions for accessing the controller's actions using the `$requiredPermissions` property. This property holds an array of permission keys that determine the access level needed. If an administrator has any of the permissions listed, they are granted access to the controller pages. + +Here is an example of how to restrict access to a controller using permissions: + +```php + 'Author.Extension.DeleteRecord' + ]; +} +``` + +## Restricting access to features + +In TastyIgniter, the `\Igniter\User\Models\User` user model includes a method named `hasPermission` for determining whether the administrator has specific permissions. This functionality is particularly useful for implementing access controls within the admin user interface, ensuring that only authorized users can access certain features or data. + +The `hasPermission` method can be called with either a single permission key string or an array of key strings. Additionally, there is an optional parameter that allows you to specify whether all listed permissions are required (`true`) or if having any one of the permissions is sufficient (`false`). By default, this parameter is set to `false`, meaning the function will return `true` if any of the specified permissions match. + +This method will always return `true` for administrators with the `super_user` flag set to `true`, indicating they are superadmins and have unrestricted access. For other users, it checks the permissions assigned through their role or group. + +Here an example using the `hasPermission` method in the controller code: + +```php +// Check if the user has any permission within the 'Author.Extension' scope +if ($this.user.hasPermission('Author.Extension.*')) { + // +} + +// Check if the user has both 'ManagePages' and 'ManageMenus' permissions +if ($this.user.hasPermission([ + 'Author.Extension.ManagePages', + 'Author.Extension.ManageMenus' +], true)) { + // Execute code only if the user has both permissions +} +``` diff --git a/extend/widgets.md b/extend/widgets.md index 1cd4e3c..7696c9a 100644 --- a/extend/widgets.md +++ b/extend/widgets.md @@ -1,32 +1,354 @@ --- -title: "Creating a Widget" +title: "Widgets" section: extend -sortOrder: 230 -callout: This section is incomplete. Please help to improve it. +sortOrder: 220 --- ## Introduction -## Defining a generic widget +In TastyIgniter, widgets are self-contained blocks of functionality used to perform specific tasks within the Admin Interface. Widgets always have a user interface and admin controller, referred to as the widget class. The widget class is responsible for preparing data for the widget and handling AJAX requests that are initiated from the widget's user interface. + +## Generic widget + +Widgets in TastyIgniter are the admin equivalent of frontend [components](../customize/components). The major difference is that admin widgets use PHP arrays for configuration and are linked specifically to admin pages. + +Widget classes reside in the extension's `src/Widgets` directory. Widgets may include assets and partials to enhance functionality. Here's an example of a typical widget directory structure: + +```yaml +author/ + extension/ + src/ + Widgets/ + MyWidget.php + resources/ + css/ + mywidget.css + js/ + mywidget.js + views/ + _partials/ + widgets/ + mywidget.blade.php +``` ### Widget class -## Defining a form widget +The widget class is a PHP class that extends the `\Igniter\Admin\Classes\BaseWidget` class. The class contains properties and methods that define the widget's behavior and appearance. Here is an example of a simple widget class: + +```php +namespace Author\Extension\Widgets; + +class MyWidget extends \Igniter\Admin\Classes\BaseWidget +{ + public string $defaultAlias = 'mywidget'; + + public function render() + { + $this->vars['var'] = 'value'; + + return $this->makePartial('mywidget'); + } +} +``` + +The widget class must implement a `render()` method that returns the widget's markup. In this example, the `makePartial()` method will scan the extension's `resources/views/widgets` or `resources/views` directory to render the `mywidget.blade.php` view file. The `$vars` property is used to pass data to the view file. Alternatively you may pass the variables to the second parameter of the `makePartial()` method: + +```php +return $this->makePartial('mywidget', ['var' => 'value']); +``` + +### AJAX handlers + +Widgets in TastyIgniter implement the same AJAX handling approach as [admin controllers](../extend/controllers). Widgets can handle AJAX requests by defining methods that start with `on` followed by the AJAX handler name. For example, to handle an AJAX request with the handler name `onAction`, you would define a method named `onAction` in the widget class. Here's an example of an AJAX handler method: + +```php +public function onAction() +{ + // Your AJAX handler logic here +} +``` + +The only different between widget AJAX handlers and those of admin controllers is how they are referenced. When referring to a widget AJAX handler within widget partials, you should use the widget's `getEventHandler()` method to accurately return the handler name specific to the widget. For example: + +```blade + +``` + +The example above will generate the following HTML attribute value by prefixing the handler name with the widget's alias: + +```html + +``` + +### Binding widgets to controllers + +Before you can use a widget on admin pages in TastyIgniter, it must be bound to an admin controller. This is done using the widget's `bindToController` method. The optimal place to initialize a widget is within the constructor of the controller. For example: + +```php +public function __construct() +{ + parent::__construct(); + + $myWidget = new MyWidget($this); + $myWidget->bindToController(); +} +``` + +Once a widget is bound to a backend controller in TastyIgniter, you can access it within the controller's view or partial using its assigned alias. + +```blade +{{ $this->widgets['mywidget']->render() }} +``` + +## Using form widget + +Form widgets in TastyIgniter allow you to introduce new control types to admin forms. To use form widgets, they must first be registered in the [Extension class](../extend/extensions#extension-class). + +Form widget classes are located in the extension's `src/FormWidgets` directory. Form widgets can also include assets and partials. Here's an example: + +```yaml +author/ + extension/ + src/ + FormWidgets/ + MyFormWidget.php + resources/ + css/ + myformwidget.css + js/ + myformwidget.js + views/ + _partials/ + formwidgets/ + myformwidget.blade.php +``` ### Form widget class +The form widget class is a PHP class that extends the `\Igniter\Admin\Classes\BaseFormWidget` class. A registered widget can be used in the admin [form definition file](../extend/forms#form-definition-file). Here is an example of a simple form widget class: + +```php +namespace Author\Extension\FormWidgets; + +class MyFormWidget extends \Igniter\Admin\Classes\BaseFormWidget +{ + public string $defaultAlias = 'myformwidget'; + + public function render() + { + $this->vars['var'] = 'value'; + + return $this->makePartial('myformwidget'); + } +} +``` + ### Form widget properties +Form widgets can have properties that define their behavior and appearance that can be set in the form definition file. Define the configurable properties directly on the class. Then, within the `initialize` method, use the `fillFromConfig` method to populate these properties with values from your form definition file. Here is an example of a form widget class with properties: + +```php +namespace Author\Extension\FormWidgets; + +class MyFormWidget extends \Igniter\Admin\Classes\BaseFormWidget +{ + // + // Configurable properties + // + + public string $mode = 'grid'; + + public string $property = 'value'; + + // + // Object properties + // + + public string $defaultAlias = 'myformwidget'; + + public function initialize() + { + $this->fillFromConfig([ + 'mode' + 'property' + ]); + } +} +``` + +You can then set these properties in the form definition file: + +```php +'field' => [ + 'label' => 'Field', + 'type' => 'myformwidget', + 'mode' => 'inline', + 'property' => 'new value', +], +``` + ### Form widget registration -## Defining a dashboard widget +To register a form widget, you must add it to the `registerFormWidgets` method in the extension class. The method returns an array containing the widget class in the keys and widget short code as the value. Here is an example of how to register a form widget: + +```php +public function registerFormWidgets() +{ + return [ + 'Author\Extension\FormWidgets\MyFormWidget' => 'myformwidget', + ]; +} +``` + +> **Note:** The widget short code should be a unique value. + +### Loading form data + +The primary function of a form widget is to interact with your model, by loading and saving data to the database. When a form widget is rendered, it retrieves its stored value using the `getLoadValue` method. Additionally, the `getId` and `getFieldName` methods provide a unique identifier and the name for a HTML element used in the form. These values are typically passed to the widget partial at the time of rendering. + +Here's how you might implement this in the `render` method: + +```php +public function render() +{ + $this->vars['id'] = $this->getId(); + $this->vars['name'] = $this->getFieldName(); + $this->vars['value'] = $this->getLoadValue(); + + return $this->makePartial('myformwidget'); +} +``` + +In the partial `myformwidget`, the HTML element can be rendered using the prepared variables: + +```blade + +``` + +### Saving form data + +When it comes to storing user input in the database, the form widget uses the `getSaveValue` method internally to capture the value. If you need to modify this behavior, you can override this method in your form widget class: + +```php +public function getSaveValue($value) +{ + return $value; +} +``` + +In scenarios where you might not want any value to be saved (e.g., a form widget that displays information without saving it), you can return a special constant `FormField::NO_SAVE_DATA` from the `Igniter\Admin\Classes\FormField` class to ensure the value is ignored: + +```php +public function getSaveValue($value) +{ + return \Igniter\Admin\Classes\FormField::NO_SAVE_DATA; +} +``` + +## Using dashboard widget + +Dashboard widgets in TastyIgniter are used to display information on the admin dashboard. They are similar to form widgets but are designed to be used on the dashboard page. Dashboard widgets can be registered in the [Extension class](../extend/extensions#extension-class). + +Dashboard widget classes are located in the extension's `src/DashboardWidgets` directory. Similarly to all form widgets, dashboard widgets can also include assets and partials. Here's an example: + +```yaml +author/ + extension/ + src/ + DashboardWidgets/ + MyDashboardWidget.php + resources/ + css/ + mydashboardwidget.css + js/ + mydashboardwidget.js + views/ + _partials/ + dashboardwidgets/ + mydashboardwidget.blade.php +``` ### Dashboard widget class +The dashboard widget class is a PHP class that extends the `\Igniter\Admin\Classes\BaseDashboardWidget` class. Here is an example of a simple dashboard widget class: + +```php +namespace Author\Extension\DashboardWidgets; + +class MyDashboard extends \Igniter\Admin\Classes\BaseDashboardWidget +{ + public string $defaultAlias = 'mydashboardwidget'; + + public function render() + { + $this->vars['var'] = 'value'; + + return $this->makePartial('mydashboardwidget'); + } +} +``` + +When designing a widget partial, you can include various types of content such as charts, indicators, lists, or any other HTML markup. To ensure consistent styling and integration within the admin, wrap your markup within a **DIV** element with the class `dashboard-widget`. It's also recommended to use an **H3** element for the widget's header. + +```blade +
+

My Dashboard Widget

+ +
+
    +
  • First Data Point: 100
  • +
  • Second Data Point: 200
  • +
  • Third Data Point: 300
  • +
+
+
+``` + ### Dashboard widget properties +Dashboard widgets can have properties that define their behavior and appearance. These properties can be defined using the `defineProperties` method in the dashboard widget class. Here is an example of a dashboard widget class with properties: + +```php +namespace Author\Extension\DashboardWidgets; + +class MyDashboard extends \Igniter\Admin\Classes\BaseDashboardWidget + + public function defineProperties(): array + { + return [ + 'property' => [ + 'label' => 'Property', + 'type' => 'text', + 'default' => 'value', + ], + ]; + } +} +``` + ### Dashboard widget registration -## AJAX handlers +To register a dashboard widget, you must add it to the `registerDashboardWidgets` method in the extension class. The method returns an array containing the widget class in the keys and widget configuration (label, context, and required permissions) as the value. Here is an example of how to register a dashboard widget: -## \ No newline at end of file +```php +public function registerDashboardWidgets() +{ + return [ + \Author\Extension\DashboardWidgets\MyDashboard::class => [ + 'label' => 'My Dashboard Widget', + 'context' => 'dashboard', + 'permissions' => ['Author.Extension.*'], + ], + ]; +} +``` diff --git a/installation.md b/installation.md index e104cd6..584b8b3 100644 --- a/installation.md +++ b/installation.md @@ -130,12 +130,33 @@ command if it fails. For more information on configuring Supervisor and using Queues, consult the Laravel Queue docs. -## Web server configuration +### Application configuration + +**Debug mode** + +The debug setting is found in the `config/app.php` configuration file with the `debug` parameter, and is disabled by default. + +When enabled, this setting will display detailed error messages when they occur along with other debugging functions. +Debug mode should always be disabled in a live production site. This prevents the display of potentially sensitive +information to the end user. + +> **Important:** Always set the `APP_DEBUG` setting to false in production environments. + +**CSRF protection** + +TastyIgniter offers a simple method to protect your application from cross-site request forgeries. + +For every active user session managed by the application, TastyIgniter automatically generates a CSRF "token." This +token is used to check that the authenticated user is the one who actually makes the client requests. + +Although CSRF security is enabled by default, you can disable it by updating the `ENABLE_CSRF` variable in your application's `.env` file. + +### Apache/Nginx configuration TastyIgniter has basic configuration that should be applied to your webserver. Common webservers and their configuration can be found below. -### Apache configuration +**Apache configuration** TastyIgniter includes a `.htaccess` file - make sure it's been uploaded correctly. **There are some extra system requirements if your webserver is running Apache, `mod_rewrite` should be installed and @@ -163,7 +184,7 @@ If you've created a subdirectory, you can specify the subdirectory name as well: RewriteBase /mysubdirectory/ ``` -### Nginx configuration +**Nginx configuration** Make sure that [`.nginx.conf`](https://github.com/tastyigniter/TastyIgniter/blob/v4/.nginx.conf) file included with TastyIgniter has been uploaded correctly. Then, assuming you have Nginx @@ -196,27 +217,6 @@ server { } ``` -## Application configuration - -### Debug mode - -The debug setting is found in the `config/app.php` configuration file with the `debug` parameter, and is disabled by default. - -When enabled, this setting will display detailed error messages when they occur along with other debugging functions. -Debug mode should always be disabled in a live production site. This prevents the display of potentially sensitive -information to the end user. - -> **Important:** Always set the `APP_DEBUG` setting to false in production environments. - -### CSRF protection - -TastyIgniter offers a simple method to protect your application from cross-site request forgeries. - -For every active user session managed by the application, TastyIgniter automatically generates a CSRF "token." This -token is used to check that the authenticated user is the one who actually makes the client requests. - -Although CSRF security is enabled by default, you can disable it by updating the `ENABLE_CSRF` variable in your application's `.env` file. - ## Getting Started You can access the administrator panel from `/admin` with your username and password asked during the setup process. diff --git a/code-of-conduct.md b/resources/code-of-conduct.md similarity index 99% rename from code-of-conduct.md rename to resources/code-of-conduct.md index 094e7a4..89c2237 100644 --- a/code-of-conduct.md +++ b/resources/code-of-conduct.md @@ -4,8 +4,6 @@ section: "getting-started" sortOrder: 20 --- -## Welcome to the TastyIgniter Community - One of our main goals, as an expanding community is to include as many contributors from various backgrounds and areas. We want every single member of the TastyIgniter community to get as much out of it as possible. Therefore, we don't want to scare people off and want to make it a place where all people can co-exist regardless of religion, socio-economic status, ethnicity, ability, sexual orientation or gender. Whether you are using the TastyIgniter forum, GitHub, Discord chat or an alternative means of communication outside of our community, this code of conduct is applicable. diff --git a/contribution-guide.md b/resources/contribution-guide.md similarity index 66% rename from contribution-guide.md rename to resources/contribution-guide.md index f3d8139..22d0a9e 100644 --- a/contribution-guide.md +++ b/resources/contribution-guide.md @@ -7,14 +7,14 @@ sortOrder: 40 Interested in contributing to the development of TastyIgniter? All contributions are appreciated and welcome: from opening a bug report to creating a pull request. -Before contributing, please read the [code of conduct](code-of-conduct). +Before contributing, please read the [code of conduct](code-of-conduct.md). To order to learn a little more about how TastyIgniter operates, we suggest that you read the documentation, if you're just beginning. ## New features -If you have a feature idea, the TastyIgniter forum is the best place to suggest it. Please do not use GitHub issues to +If you have a feature idea, the [TastyIgniter forum](https://forum.tastyigniter.com/) is the best place to suggest it. Please do not use GitHub issues to suggest a new feature. Use GitHub only if you plan to contribute and develop a new feature. If you'd like to discuss your idea first, you can @@ -32,14 +32,7 @@ Issues are a quick way to point out a bug. If you find a bug in TastyIgniter the 3. The issue has already been fixed (look for closed Issues) 4. Is it something really obvious that you can fix yourself? -We work hard to process bugs that are reported, to assist with this please ensure the following details are always -included: - -- Bug summary: Make sure your summary reflects what the problem is and where it is. -- Reproduce steps: Clearly mention the steps to reproduce the bug. -- Version number: The TastyIgniter version affected. -- Expected behavior: How TastyIgniter should behave on above mentioned steps. -- Actual behavior: What is the actual result on running above steps i.e. the bug behavior - include any error messages. +When you are creating a bug report, please include as many details as possible. Fill out the required template, the information it asks for helps us resolve issues faster Please be very clear on your commit messages and pull request, duplicate or empty commit or pull request messages may be rejected without reason. @@ -48,7 +41,7 @@ rejected without reason. > **Note:** This section applies specifically to those sending pull requests to any repositories under the TastyIgniter organization. -**All** bug fixes should be sent to the latest stable branch that supports bug fixes (currently `3.x`). Bug fixes +**All** bug fixes should be sent to the latest stable branch that supports bug fixes (currently `4.x` and `master` for packages). Bug fixes should **never** be sent to the `develop` branch unless they fix features that exist only in the upcoming release. **Minor** features that are **fully backward compatible** with the current release may be sent to the latest stable @@ -69,59 +62,40 @@ TastyIgniter maintainers. ## Development setup -tastyigniter/TastyIgniter is the core +tastyigniter/TastyIgniter is the stand-alone application for installing -tastyigniter/flame using Composer. We suggest -forking them and cloning them into a -Composer path repository to work on these: - -```bash -git clone https://github.com/tastyigniter/TastyIgniter.git -cd TastyIgniter +tastyigniter/core using Composer. -# Set up a Composer path repository for TastyIgniter packages -composer config repositories.0 path "packages/*" -git clone https://github.com/tastyigniter/flame.git packages/flame -git clone https://github.com/tastyigniter/ti-ext-frontend.git packages/frontend # etc -``` - -Next, make sure Composer accepts unstable releases from your local copies by adjusting the value of `minimum-stability` +- Make sure Composer accepts unstable releases from your local copies by adjusting the value of `minimum-stability` in `composer.json` to `dev`. +- Run `composer install` to install composer dependencies. +- Finally, run `composer update "tastyigniter/*" --prefer-source` to clone TastyIgniter packages into the `vendor` directory for development. -Finally, run `composer install` to complete the installation from the path repositories. ## Development workflow Follow these steps: -- **Clone** the tastyigniter/TastyIgniter - repository -- **Branch** off the **develop** branch into a new feature branch. -- Run **composer** install -- Make your **changes** +- Complete the development setup and make your **changes** - Run ./vendor/bin/phpunit to **test** your code +- Run ./vendor/bin/pint to **fix** any code style issues - **Commit** your code with a descriptive message. - Submit in the **pull request** on Github -## Reporting security issues - -If you wish to contact us about any security vulnerability in TastyIgniter you may find, please send an e-mail to -support@tastyigniter.com - -## Coding style +## Development tools -To keep the TastyIgniter codebase clean and consistent, we follow a number of coding style guidelines. Read source code -when in doubt. +Most TastyIgniter contributors develop with +PHPStorm. However, feel free to use your preferred IDE. -TastyIgniter follows -the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding and -the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. +To serve a local TastyIgniter website, Laravel +Valet (Mac), XAMPP (Windows), +and TastyIgniter Docker (Linux) are popular +choices. -We do comply with a range of other style rules. Where possible, we use PHP 7 type hinting and return type declarations, -and PHPDoc for inline documentation. Try to imitate the style used by the rest of the codebase. +## Reporting security issues -Do not worry if the style of your code isn't great! After pull requests are merged, StyleCI will automatically merge any -style fixes into TastyIgniter repositories. This helps us to focus on what matters. +If you wish to contact us about any security vulnerability in TastyIgniter you may find, please send an e-mail to +support@tastyigniter.com ## Writing documentation @@ -142,14 +116,4 @@ contribute. Here's how styling perfect TastyIgniter documentation pages is done: - For your reference, see the [pages.md](https://github.com/tastyigniter/docs/blob/master/customize/pages.md) or [themes.md](https://github.com/tastyigniter/docs/blob/master/customize/themes.md) files. -## Development tools - -Most TastyIgniter contributors develop with -PHPStorm. However, feel free to use your preferred IDE. - -To serve a local TastyIgniter website, Laravel -Valet (Mac), XAMPP (Windows), -and TastyIgniter Docker (Linux) are popular -choices. - > For more information on contributing, read the guide here \ No newline at end of file diff --git a/js-coding-guidelines.md b/resources/js-coding-guidelines.md similarity index 100% rename from js-coding-guidelines.md rename to resources/js-coding-guidelines.md diff --git a/php-coding-guidelines.md b/resources/php-coding-guidelines.md similarity index 72% rename from php-coding-guidelines.md rename to resources/php-coding-guidelines.md index 062d987..38adbef 100644 --- a/php-coding-guidelines.md +++ b/resources/php-coding-guidelines.md @@ -90,29 +90,29 @@ guidelines for naming classes. Also, follow naming conventions accepted by Laravel community: -| What | How | Good | Bad -|-------------------------------------|-------------------------------------|-------------------------------------------|--------------------------------------------------- - **Controller** | plural | `ArticlesController` | `ArticleController` - **Route** | plural | `articles/1` | `article/1` - **Model** | singular | `User` | `Users` - **Table** | plural | `article_comments` | `article_comment, articleComments` - **Pivot table** | singular model names | `article_user` | `articles_users` - **Table column** | snake_case without model name | `meta_title` | `MetaTitle, article_meta_title` - **Foreign key** | singular model name with _id suffix | `article_id` | `ArticleId, id_article, articles_id` - **Primary key** | - | `id` | `custom_id` - **Migration** | - | `2017_01_01_000000_create_articles_table` | `2017_01_01_000000_articles` - **Method** | camelCase | `getAll` | `get_all` - **Function** | snake_case | `abort_if` | `abortIf` - **Method in test class** | camelCase | `testGuestCannotSeeArticle` | `test_guest_cannot_see_article` - **Model property** | snake_case | `$model->model_property` | `$model->modelProperty` - **Variable** | camelCase | `$anyOtherVariable` | `$any_other_variable` - **Collection** | descriptive, plural | `$activeUsers = User::active()->get()` | `$active, $data` - **Object** | descriptive, singular | `$activeUser = User::active()->first()` | `$users, $obj` - **Config and language files index** | snake_case | `articles_enabled` | `ArticlesEnabled, articles-enabled` - **View file name** | kebab-case | `show-filtered.blade.php` | `showFiltered.blade.php, show_filtered.blade.php` - **Config file name** | kebab-case | `google-calendar.php` | `googleCalendar.php, google_calendar.php` - **Contract (interface)** | adjective or noun | `Authenticatable` | `AuthenticationInterface, IAuthentication` - **Trait** | adjective | `Notifiable` | `NotificationTrait` +| What | How | Good | Bad | +|-------------------------------------|-------------------------------------|-------------------------------------------|---------------------------------------------------| +| **Controller** | plural | `ArticlesController` | `ArticleController` | +| **Route** | plural | `articles/1` | `article/1` | +| **Model** | singular | `User` | `Users` | +| **Table** | plural | `article_comments` | `article_comment, articleComments` | +| **Pivot table** | singular model names | `article_user` | `articles_users` | +| **Table column** | snake_case without model name | `meta_title` | `MetaTitle, article_meta_title` | +| **Foreign key** | singular model name with _id suffix | `article_id` | `ArticleId, id_article, articles_id` | +| **Primary key** | - | `id` | `custom_id` | +| **Migration** | - | `2017_01_01_000000_create_articles_table` | `2017_01_01_000000_articles` | +| **Method** | camelCase | `getAll` | `get_all` | +| **Function** | snake_case | `abort_if` | `abortIf` | +| **Method in test class** | camelCase | `testGuestCannotSeeArticle` | `test_guest_cannot_see_article` | +| **Model property** | snake_case | `$model->model_property` | `$model->modelProperty` | +| **Variable** | camelCase | `$anyOtherVariable` | `$any_other_variable` | +| **Collection** | descriptive, plural | `$activeUsers = User::active()->get()` | `$active, $data` | +| **Object** | descriptive, singular | `$activeUser = User::active()->first()` | `$users, $obj` | +| **Config and language files index** | snake_case | `articles_enabled` | `ArticlesEnabled, articles-enabled` | +| **View file name** | kebab-case | `show-filtered.blade.php` | `showFiltered.blade.php, show_filtered.blade.php` | +| **Config file name** | kebab-case | `google-calendar.php` | `googleCalendar.php, google_calendar.php` | +| **Contract (interface)** | adjective or noun | `Authenticatable` | `AuthenticationInterface, IAuthentication` | +| **Trait** | adjective | `Notifiable` | `NotificationTrait` | ### Jobs @@ -154,24 +154,24 @@ $request->input('name'); Consider using helpers instead of facades. They can clean up your code. - Common syntax | Shorter and more readable syntax -------------------------------------------------------------------------|---------------------------------------------------- - `Session::get('foo')` | `session('foo')` - `$request->session()->get('foo')` | `session('foo')` - `Session::put('foo', $data)` | `session(['foo' => $data])` - `$request->input('name'),Request::get('name')` | `$request->name,request('name')` - `return Redirect::back()` | `return redirect()->back()` - `is_null($object->relation) ? $object->relation->id : null;` | `optional($object->relation)->id` - `return view('index')->with('title', $title)->with('client', $client)` | `return view('index', compact('title', 'client'))` - `$request->has('value') ? $request->value : 'default';` | `$request->get('value','default')` - `Carbon::now(), Carbon::today()` | `now(), today()` - `App::make('Class')` | `app('Class')` - `->where('column', '=', 1)` | `->where('column', 1)` - `->orderBy('created_at', 'desc')` | `->latest()` - `->orderBy('age', 'desc')` | `->latest('age')` - `->orderBy('created_at', 'asc')` | `->oldest()` - `->select('id', 'name')->get()` | `->get(['id', 'name'])` - `->first()->name` | `->value('name')` +| Common syntax | Shorter and more readable syntax | +|------------------------------------------------------------------------|----------------------------------------------------| +| `Session::get('foo')` | `session('foo')` | +| `$request->session()->get('foo')` | `session('foo')` | +| `Session::put('foo', $data)` | `session(['foo' => $data])` | +| `$request->input('name'),Request::get('name')` | `$request->name,request('name')` | +| `return Redirect::back()` | `return redirect()->back()` | +| `is_null($object->relation) ? $object->relation->id : null;` | `optional($object->relation)->id` | +| `return view('index')->with('title', $title)->with('client', $client)` | `return view('index', compact('title', 'client'))` | +| `$request->has('value') ? $request->value : 'default';` | `$request->get('value','default')` | +| `Carbon::now(), Carbon::today()` | `now(), today()` | +| `App::make('Class')` | `app('Class')` | +| `->where('column', '=', 1)` | `->where('column', 1)` | +| `->orderBy('created_at', 'desc')` | `->latest()` | +| `->orderBy('age', 'desc')` | `->latest('age')` | +| `->orderBy('created_at', 'asc')` | `->oldest()` | +| `->select('id', 'name')->get()` | `->get(['id', 'name'])` | +| `->first()->name` | `->value('name')` | ## Docblocks diff --git a/upgrade-guide.md b/upgrade-guide.md index 2de628c..60a9ca5 100644 --- a/upgrade-guide.md +++ b/upgrade-guide.md @@ -112,10 +112,9 @@ organization and easier unit testing. `ExtensionManager::instance()` is now `res #### Blade Directives -New Blade directives have been introduced to simplify theme development and avoid conflicts. The `@themeContent` directive -allows rendering of content template files, while `@themePage` replaces `@page` used for rendering page contents. -Additionally, -`@componentPartial` and `@themePartial` directives replace the previous `@component` and `@partial` directives. +We've introduced new Blade directives to streamline theme development. We've also renamed existing directives to prevent conflicts. The `@themeContent` directive now replaces `@content`, enabling the rendering of content template files. Similarly, `@themePage` has taken over from `@page` for rendering page contents. Additionally, `@themeStyles` and `@themeScripts` directives replace `@styles` and `@scripts` respectively. Furthermore, `@themeComponent` and `@themePartial` directives now replace the previous `@component` and `@partial` directives. + +See [Blade Directives on Markup guide](customize/markup-guide#directives) for more details. ### Medium impact changes From b8ab979a7e0f9a67e2ba9553160fec7b5eb9c7ba Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Thu, 25 Apr 2024 02:24:53 +0100 Subject: [PATCH 04/14] Fix headings --- extend/forms.md | 68 ++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/extend/forms.md b/extend/forms.md index be24df5..95f800b 100644 --- a/extend/forms.md +++ b/extend/forms.md @@ -207,7 +207,7 @@ The following options are available for form fields (where applicable): - `containerAttributes`: Additional HTML attributes to apply to the field container. - `permissions`: The [permissions](../extend/permissions) required to view this field. -## Available field types +### Available field types The following native field types are available for form fields. For more advanced form fields, a [form widget](../extend/forms#form-widgets) can be used instead. @@ -231,7 +231,7 @@ The following native field types are available for form fields. For more advance - [Partial](../extend/forms#partial) - [Widget](../extend/forms#widget) -### Text +#### Text `text` renders a simple text input field. @@ -242,7 +242,7 @@ The following native field types are available for form fields. For more advance ], ``` -### Number +#### Number `number` renders an input field that takes only numbers. @@ -253,7 +253,7 @@ The following native field types are available for form fields. For more advance ], ``` -### Money +#### Money `money` renders an input field that takes only numbers and formats the value to two decimal places. @@ -264,7 +264,7 @@ The following native field types are available for form fields. For more advance ], ``` -### Currency +#### Currency `currency` renders an input field that takes only numbers and formats the value matching the active currency settings. @@ -275,7 +275,7 @@ The following native field types are available for form fields. For more advance ], ``` -### Password +#### Password `password` renders a password input field. @@ -286,7 +286,7 @@ The following native field types are available for form fields. For more advance ], ``` -### Email +#### Email `email` renders an input field that takes only email addresses. @@ -297,7 +297,7 @@ The following native field types are available for form fields. For more advance ], ``` -### Permalink +#### Permalink `permalink` renders an input field that only accepts alphanumeric characters, dashes, and underscores. @@ -308,7 +308,7 @@ The following native field types are available for form fields. For more advance ], ``` -### URL +#### URL `url` renders an input field that only accepts valid URLs. @@ -319,7 +319,7 @@ The following native field types are available for form fields. For more advance ], ``` -### Textarea +#### Textarea `textarea` renders a textarea input field. @@ -335,7 +335,7 @@ The following native field types are available for form fields. For more advance ], ``` -### Select +#### Select `select` renders a dropdown select field. There are 6 ways to provide the dropdown options. All six ways should return an array of options in the format `key => label`. @@ -432,7 +432,7 @@ The following options are available for the `select` field type: - `showSearch`: Whether to enable search functionality in the dropdown. Default is `false`. - `multiOption`: Whether to allow multiple selections. Default is `false`. -### Checkbox +#### Checkbox `checkbox` renders a checkbox input field. @@ -443,7 +443,7 @@ The following options are available for the `select` field type: ], ``` -### Checkbox list +#### Checkbox list `checkboxlist` renders a list of checkboxes. Checkbox lists support the same methods for defining the options as the [select field type](../extend/forms#select). @@ -471,7 +471,7 @@ Options for checkbox lists also support secondary descriptions using the array f ], ``` -### Checkbox toggle +#### Checkbox toggle `checkboxtoggle` renders a button-like checkbox toggle. Checkbox toggles support the same methods for defining the options as the [select field type](../extend/forms#select). @@ -487,7 +487,7 @@ Options for checkbox lists also support secondary descriptions using the array f ], ``` -### Radio list +#### Radio list `radiolist` renders a list of radio buttons. Radio lists support the same methods for defining the options as the [select field type](../extend/forms#select). These options also support secondary descriptions just like [checkbox lists](../extend/forms#checkbox-list). @@ -503,7 +503,7 @@ Options for checkbox lists also support secondary descriptions using the array f ], ``` -### Radio toggle +#### Radio toggle `radiotoggle` renders a button-like radio toggle. Radio toggles support the same methods for defining the options as the [select field type](../extend/forms#select). @@ -519,7 +519,7 @@ Options for checkbox lists also support secondary descriptions using the array f ], ``` -### Switch +#### Switch `switch` renders a switch toggle field. @@ -532,7 +532,7 @@ Options for checkbox lists also support secondary descriptions using the array f ], ``` -### Section +#### Section `section` renders a section heading and subheading. @@ -544,7 +544,7 @@ Options for checkbox lists also support secondary descriptions using the array f ], ``` -### Partial +#### Partial `partial` renders a partial view. The `path` option should be the path to the partial view file otherwise the field name is used as the partial name. @@ -555,7 +555,7 @@ Options for checkbox lists also support secondary descriptions using the array f ], ``` -### Widget +#### Widget `widget` renders a form widget. The `type` option should be the class name of the form widget or the registered alias name. @@ -584,7 +584,7 @@ TastyIgniter includes several form widgets, although it is common for extensions - [Status editor](../extend/forms#status-editor) - [Template editor](../extend/forms#template-editor) -### Code editor +#### Code editor `codeeditor` renders an editor field for editing code or HTML markup. @@ -600,7 +600,7 @@ The following options are available for the `codeeditor` field type: - `mode`: The programming language to use for syntax highlighting. Default is `css`. - `theme`: The color theme option passed to the CodeMirror JS library. Default is `material`. -### Color picker +#### Color picker `colorpicker` renders the browser supported color picker. @@ -615,7 +615,7 @@ The following options are available for the `colorpicker` field type: - `availableColors`: An array of colors to display in the color picker for quick color selection. -### Components +#### Components `components` renders a field for selecting and managing both [theme](../customize/components#theme-component) and [livewire](../customize/components#livewire-component) components from the component library as well as rendering them to a theme template. @@ -639,7 +639,7 @@ The following options are available for the `components` field type: - `editTitle`: The title of the edit button. Default is `Edit component`. - `copyPartialTitle`: The title of the override partial button. Default is `Override component partial`. -### Connector +#### Connector `connector` renders a field for attaching and managing related records from a model. @@ -679,7 +679,7 @@ The following options are available for the `connector` field type: - `popupSize`: The size of the popup window. Options are `modal-sm`, `modal-md`, `modal-lg`, `modal-xl`. - `hideNewButton`: Whether to hide the new related record button. Default is `true`. -### Data table +#### Data table `datatable` renders a table for displaying and editing tabular data. @@ -713,7 +713,7 @@ The following options are available for the `datatable` field type: - `toolbar`: The configuration of toolbar buttons to display above the table. - `fieldName`: The custom field name to use for the table. Default to the field alias. -### Date picker +#### Date picker `datepicker` renders the browser supported date picker field for selecting dates and times. @@ -732,7 +732,7 @@ The following options are available for the `datepicker` field type: - `startDate`: The minimum date that can be selected. - `endDate`: The maximum date that can be selected. -### Markdown editor +#### Markdown editor `markdown` renders an editor field for editing markdown content. @@ -747,7 +747,7 @@ The following options are available for the `markdown` field type: - `mode`: The editor view mode. Options are `tab` or `split`. Default is `tab`. -### Media finder +#### Media finder `mediafinder` renders a field for selecting media files from the media library. @@ -766,7 +766,7 @@ The following options are available for the `mediafinder` field type: - `useAttachment`: Whether to use the attachment ID instead of the media path. Default is `false`. - `thumbOptions`: Configuration options for generating media thumbnails. Default is `['fit' => 'contain', 'width' => 122, 'height' => 122]`. -### Record editor +##### Record editor `recordeditor` renders a field for selecting and managing records from a model. @@ -813,7 +813,7 @@ The following options are available for the `addonRight` and `addonLeft` buttons - `tag`: The button tag. Options are `div`, `button`, `a`. Default is `div`. - `attributes`: Additional HTML attributes to apply to the button. Define as an array of key-value pairs. -### Relation +#### Relation `relation` renders a single or multiple selection dropdown field for selecting related records. The label used for displaying each relation is retrieved by the `nameFrom` or `select` definition. @@ -835,7 +835,7 @@ The following options are available for the `relation` field type: - `scope`: A custom query scope method to apply to the relation query. - `emptyOption`: The text to display for the empty option. Default is `-- none --`. -### Repeater +#### Repeater `repeater` renders a field for repeating a set of fields. @@ -868,7 +868,7 @@ The following options are available for the `repeater` field type: - `showRemoveButton`: Whether to show the remove button. Default is `true`. - `emptyMessage`: The message to display when there are no items in the repeater. Default is `lang:igniter::admin.text_empty`. -### Rich editor / WYSIWYG +#### Rich editor / WYSIWYG `richeditor` renders a rich text editor field for editing HTML content. @@ -884,7 +884,7 @@ The following options are available for the `richeditor` field type: - `size`: The size of the editor. Options are `small`, `large`. Default is `large`. - `toolbarButtons`: The buttons to display in the editor toolbar. -### Status editor +#### Status editor `statuseditor` renders a field for updating status and assignee for orders and reservations. @@ -925,7 +925,7 @@ The following options are available for the `statuseditor` field type: - `statusRelationFrom`: The relation name to use for fetching status records. - `assigneeRelationFrom`: The relation name to use for fetching assignee records. -### Template editor +#### Template editor `templateeditor` renders a field for editing theme template files. From 1c7f7282270bf81745d5f16166efbe7f886de215 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Thu, 25 Apr 2024 02:40:59 +0100 Subject: [PATCH 05/14] Fix headings --- SUMMARY.md | 4 -- advanced/ajax-request.md | 82 ++++++++++++++++++++---------- extend/extensions.md | 2 +- resources/code-of-conduct.md | 4 +- resources/contribution-guide.md | 4 +- resources/js-coding-guidelines.md | 4 +- resources/php-coding-guidelines.md | 4 +- 7 files changed, 65 insertions(+), 39 deletions(-) delete mode 100644 SUMMARY.md diff --git a/SUMMARY.md b/SUMMARY.md deleted file mode 100644 index 5da1733..0000000 --- a/SUMMARY.md +++ /dev/null @@ -1,4 +0,0 @@ -# Table of contents - -* [Initial page](README.md) - diff --git a/advanced/ajax-request.md b/advanced/ajax-request.md index ec0db2f..03ea42e 100644 --- a/advanced/ajax-request.md +++ b/advanced/ajax-request.md @@ -124,7 +124,21 @@ The `$.request` object supports additional options for customizing AJAX requests Some of the common options include: -### `update` +- [update](../advanced/ajax-request#update) +- [confirm](../advanced/ajax-request#confirm) +- [data](../advanced/ajax-request#data) +- [redirect](../advanced/ajax-request#redirect) +- [headers](../advanced/ajax-request#headers) +- [attach-loading](../advanced/ajax-request#attach-loading) +- [replace-loading](../advanced/ajax-request#replace-loading) +- [beforeUpdate](../advanced/ajax-request#beforeUpdate) +- [success](../advanced/ajax-request#success) +- [error](../advanced/ajax-request#error) +- [complete](../advanced/ajax-request#complete) +- [submit](../advanced/ajax-request#submit) +- [form](../advanced/ajax-request#form) + +#### `update` _(Object)_ Specifies a list of partials and page elements to be updated with the response data. The key is the partial name, and the value is the CSS selector of the target element to be updated. @@ -144,7 +158,7 @@ $.request('onSave', { > You may prepend the CSS Selector with `@` to append contents to the element, `^` to prepend and `~` to replace with. -### `confirm` +#### `confirm` _(string)_ Specifies a confirmation message that will be displayed to the user before sending the request. If the user confirms the request, the request will be sent; otherwise, the request will be canceled. @@ -159,7 +173,7 @@ $.request('onSave', { ``` -### `data` +#### `data` _(Object)_ Specifies the data to be sent with the request. The data should be an object containing key-value pairs of the request data. @@ -177,7 +191,7 @@ $.request('onSave', { ``` -### `redirect` +#### `redirect` _(string)_ Specifies the URL to redirect to after the request is completed. @@ -192,7 +206,7 @@ $.request('onSave', { ``` -### `headers` +#### `headers` _(Object)_ Specifies additional headers to be sent with the request. @@ -205,7 +219,7 @@ $.request('onSave', { }); ``` -### `attach-loading` +#### `attach-loading` _(string)_ Specifies the CSS selector to add to the target element while the request is loading. The attribute value is optional, if not provided, the target element will be disabled. @@ -214,7 +228,7 @@ _(string)_ Specifies the CSS selector to add to the target element while the req ``` -### `replace-loading` +#### `replace-loading` _(string)_ Specifies the CSS selector to replace on the target element while the request is loading. @@ -223,7 +237,7 @@ _(string)_ Specifies the CSS selector to replace on the target element while the ``` -### `beforeUpdate` +#### `beforeUpdate` _(function)_ Specifies a callback function or Javascript code to be executed before updating the target element with the response. @@ -240,7 +254,7 @@ $.request('onSave', { ``` -### `success` +#### `success` _(function)_ Specifies a callback function or Javascript code to be executed after the request is successful. @@ -257,7 +271,7 @@ $.request('onSave', { ``` -### `error` +#### `error` _(function)_ Specifies a callback function or Javascript code to be executed when an error occurs during the request. @@ -274,7 +288,7 @@ $.request('onSave', { ``` -### `complete` +#### `complete` _(function)_ Specifies a callback function or Javascript code to be executed after the request is completed. @@ -291,7 +305,7 @@ $.request('onSave', { ``` -### `submit` +#### `submit` When set to `true`, the form will be submitted using the default form submission method. @@ -306,7 +320,7 @@ $.request('onSave', { ``` -### `form` +#### `form` _(CSS Selector)_ Specifies the form element to be submitted. Useful when the request is triggered by a button outside the form. @@ -325,7 +339,23 @@ $.request('onSave', { The AJAX framework triggers several events on the updated elements, the triggering element, form, and the window object. These events are triggered regardless of which API was used - the data attributes API or the JavaScript API. -### `ajaxBeforeSend` +Here are some of the global AJAX events that you can listen to: + +- [ajaxBeforeSend](../advanced/ajax-request#ajaxbeforesend) +- [ajaxBeforeUpdate](../advanced/ajax-request#ajaxbeforeupdate) +- [ajaxUpdate](../advanced/ajax-request#ajaxupdate) +- [ajaxUpdateComplete](../advanced/ajax-request#ajaxupdatecomplete) +- [ajaxSuccess](../advanced/ajax-request#ajaxsuccess) +- [ajaxError](../advanced/ajax-request#ajaxerror) +- [ajaxErrorMessage](../advanced/ajax-request#ajaxerrormessage) +- [ajaxConfirmMessage](../advanced/ajax-request#ajaxconfirmmessage) +- [ajaxSetup](../advanced/ajax-request#ajaxsetup) +- [ajaxPromise](../advanced/ajax-request#ajaxpromise) +- [ajaxDone](../advanced/ajax-request#ajaxdone) +- [ajaxFail](../advanced/ajax-request#ajaxfail) +- [ajaxAlways](../advanced/ajax-request#ajaxalways) + +#### `ajaxBeforeSend` Triggered on the window object before the AJAX request is sent. The handler receives the context object as an argument. @@ -335,7 +365,7 @@ $(window).on('ajaxBeforeSend', function(context) { }); ``` -### `ajaxBeforeUpdate` +#### `ajaxBeforeUpdate` Triggered on the form element immediately after the request is completed but before updating the page. The event handler receives the `event` object, the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. @@ -345,7 +375,7 @@ $('form').on('ajaxBeforeUpdate', function(event, context, data, status, jqXHR) { }); ``` -### `ajaxUpdate` +#### `ajaxUpdate` Triggered on the page element after updating the element with the response data. The event handler receives the `event` object, the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. @@ -355,7 +385,7 @@ $('#element').on('ajaxUpdate', function(event, context, data, status, jqXHR) { }); ``` -### `ajaxUpdateComplete` +#### `ajaxUpdateComplete` Triggered on the window object after all element are updated. The event handler receives the `event` object, the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. @@ -365,7 +395,7 @@ $(window).on('ajaxUpdateComplete', function(event, context, data, status, jqXHR) }); ``` -### `ajaxSuccess` +#### `ajaxSuccess` Triggered on the form element after the request is successful. The event handler receives the `event` object, the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. @@ -375,7 +405,7 @@ $('form').on('ajaxSuccess', function(event, context, data, status, jqXHR) { }); ``` -### `ajaxError` +#### `ajaxError` Triggered on the form element when an error occurs during the AJAX request. The event handler receives the `event` object, the `context` object, the `error` message, the `status` text string, and the `jqXHR` object as arguments. @@ -385,7 +415,7 @@ $('form').on('ajaxError', function(event, context, error, status, jqXHR) { }); ``` -### `ajaxErrorMessage` +#### `ajaxErrorMessage` Triggered on the window object when an error occurs during the AJAX request. The event handler receives the `event` object and `error` message as an argument. @@ -395,7 +425,7 @@ $(window).on('ajaxErrorMessage', function(event, error) { }); ``` -### `ajaxConfirmMessage` +#### `ajaxConfirmMessage` Triggered on the window object when a `confirm` option is given. The event handler receives the event object and the confirmation message as arguments. @@ -405,7 +435,7 @@ $(window).on('ajaxConfirmMessage', function(event, message) { }); ``` -### `ajaxSetup` +#### `ajaxSetup` Triggered on the triggering element before the AJAX request is formed. The event handler receives the `context` object as an argument. @@ -415,7 +445,7 @@ $('#element').on('ajaxSetup', function(context) { }); ``` -### `ajaxPromise` +#### `ajaxPromise` Triggered on the triggering element before the AJAX request is sent. The event handler receives the `context` object as an argument. @@ -425,7 +455,7 @@ $('#element').on('ajaxPromise', function(context) { }); ``` -### `ajaxDone` +#### `ajaxDone` Triggered on the triggering element when the AJAX request is successful. The event handler receives the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. @@ -435,7 +465,7 @@ $('#element').on('ajaxDone', function(context, data, textStatus, jqXHR) { }); ``` -### `ajaxFail` +#### `ajaxFail` Triggered on the triggering element when the AJAX request fails. The event handler receives the `context` object, the `status` text string, and the `jqXHR` object as arguments. @@ -445,7 +475,7 @@ $('#element').on('ajaxFail', function(context, textStatus, jqXHR) { }); ``` -### `ajaxAlways` +#### `ajaxAlways` Triggered on the triggering element when the AJAX request is completed. The event handler receives the `context` object, the `data` object received from the server, the `status` text string, and the `jqXHR` object as arguments. diff --git a/extend/extensions.md b/extend/extensions.md index daed4c8..f918fde 100644 --- a/extend/extensions.md +++ b/extend/extensions.md @@ -220,7 +220,7 @@ public function register() ## Resources -### Configuration +### Settings & Configuration There are two ways to configure extensions; with settings models (database settings) and configuration files. diff --git a/resources/code-of-conduct.md b/resources/code-of-conduct.md index 89c2237..8098e2d 100644 --- a/resources/code-of-conduct.md +++ b/resources/code-of-conduct.md @@ -1,7 +1,7 @@ --- title: "Code Of Conduct" -section: "getting-started" -sortOrder: 20 +section: "resources" +sortOrder: 400 --- One of our main goals, as an expanding community is to include as many contributors from various backgrounds and areas. We want every single member of the TastyIgniter community to get as much out of it as possible. Therefore, we don't want to scare people off and want to make it a place where all people can co-exist regardless of religion, socio-economic status, ethnicity, ability, sexual orientation or gender. diff --git a/resources/contribution-guide.md b/resources/contribution-guide.md index 22d0a9e..d28e2a3 100644 --- a/resources/contribution-guide.md +++ b/resources/contribution-guide.md @@ -1,7 +1,7 @@ --- title: "Contribution Guide" -section: "getting-started" -sortOrder: 40 +section: "resources" +sortOrder: 410 --- Interested in contributing to the development of TastyIgniter? All contributions are appreciated and welcome: from diff --git a/resources/js-coding-guidelines.md b/resources/js-coding-guidelines.md index 7c6bfdd..df110ab 100644 --- a/resources/js-coding-guidelines.md +++ b/resources/js-coding-guidelines.md @@ -1,7 +1,7 @@ --- title: "Javascript Coding Guidelines" -section: "getting-started" -sortOrder: 370 +section: "resources" +sortOrder: 470 --- [Prettier](https://prettier.io/) determines our code style. While Prettier's output isn't always the prettiest, it's consistent and removes all (meaningless) discussion about code style. diff --git a/resources/php-coding-guidelines.md b/resources/php-coding-guidelines.md index 38adbef..4789091 100644 --- a/resources/php-coding-guidelines.md +++ b/resources/php-coding-guidelines.md @@ -1,7 +1,7 @@ --- title: "PHP Coding Guidelines" -section: "getting-started" -sortOrder: 360 +section: "resources" +sortOrder: 460 --- **Consistency is key** From d55a572378a9b46380a9b200f9978165119e3969 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Thu, 25 Apr 2024 03:11:51 +0100 Subject: [PATCH 06/14] Fix typos and spelling errors --- advanced/mail.md | 14 ++++---- customize/components.md | 52 +++++++++++++++--------------- customize/layouts.md | 6 ++-- customize/pages.md | 4 +-- customize/partials.md | 2 +- customize/themes.md | 30 ++++++++--------- extend/extensions.md | 28 ++++++++-------- extend/lists.md | 2 +- extend/widgets.md | 2 +- installation.md | 2 +- resources/code-of-conduct.md | 2 +- resources/contribution-guide.md | 10 +++--- resources/php-coding-guidelines.md | 8 ++--- upgrade-guide.md | 2 +- 14 files changed, 82 insertions(+), 82 deletions(-) diff --git a/advanced/mail.md b/advanced/mail.md index 66ec2af..36e93dd 100644 --- a/advanced/mail.md +++ b/advanced/mail.md @@ -48,10 +48,10 @@ Thank you for your order. The **configuration** section sets the mail view parameters. The following configuration parameters are supported: -| Parameter | Description | -|------------------|------------------| -| `subject` | the mail message subject, **required**. | -| `layout` | the mail layout code, **optional**. Default value is default. | +| Parameter | Description | +|-------------|---------------------------------------------------------------| +| `subject` | the mail message subject, **required**. | +| `layout` | the mail layout code, **optional**. Default value is default. | The **plain text** section is optional, while the **configuration** and **HTML markup** sections are required. @@ -143,7 +143,7 @@ You can include the mail partial in a mail template or layout using the `@partia ### Mail variables -You may access all of the data passed to the mail view or template by using the `{{ $variable }}` syntax. For example, if you pass a `$customer_name` variable to the mail view, you can access it in the view like this: +You may access all the data passed to the mail view or template by using the `{{ $variable }}` syntax. For example, if you pass a `$customer_name` variable to the mail view, you can access it in the view like this: ```blade

Hello {{ $customer_name }},

@@ -198,7 +198,7 @@ Mail::sendTemplate('vendor.extension::mail.message', $data, function($message) u ### Queueing mail -To queue a mail message, you can use the `queueTemplate` method on the `Mail` facade. This method will automatically push the email onto the queue so it will be sent in the background by a queue worker. This can help to improve the response time of your application by offloading the sending of the email to a background process: +To queue a mail message, you can use the `queueTemplate` method on the `Mail` facade. This method will automatically push the email onto the queue, so it will be sent in the background by a queue worker. This can help to improve the response time of your application by offloading the sending of the email to a background process: ```php use Illuminate\Support\Facades\Mail; @@ -212,7 +212,7 @@ Mail::queueTemplate('vendor.extension::mail.message', $data, function($message) ## Registering mail templates, layouts & partials -To register mail templates, layouts, and partials in the Extension class, you can use the [`registerMailTemplates`](../extend/extensions#extension-class-methods), [`registerMailLayouts`](../extend/extensions#extension-class-methods), and ](../extend/extensions#extension-class-methods)[`registerMailPartials`] methods, respectively. These methods allow you to define the mail templates, layouts, and partials that your extension provides, making them available for customization via the admin interface: +To register mail templates, layouts, and partials in the Extension class, you can use the [`registerMailTemplates`](../extend/extensions#extension-class-methods), [`registerMailLayouts`](../extend/extensions#extension-class-methods), and [`registerMailPartials`](../extend/extensions#extension-class-methods) methods, respectively. These methods allow you to define the mail templates, layouts, and partials that your extension provides, making them available for customization via the admin interface: ```php public function registerMailTemplates(): array diff --git a/customize/components.md b/customize/components.md index 2dbfa1c..c930c82 100644 --- a/customize/components.md +++ b/customize/components.md @@ -101,14 +101,14 @@ class HelloBlock extends \Livewire\Component implements \Igniter\System\Contract // ... } ``` -| Key | Description | -| --------------- | ------------------------------------------------------------ | -| **label** | required, the property label, it is used by the component Selector in the Admin Interface. | +| Key | Description | +|-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **label** | required, the property label, it is used by the component Selector in the Admin Interface. | | **type** | optional, specifies the property type. The type defines the form field type. Currently supported types are **
text**, **number**, **checkbox**, **radio**, **select** and **selectlist**. Default value: **text**. | -| **default** | optional, the default property value. | -| **comment** | optional, the property description, it is used by the component Selector in the Admin Interface. | -| **placeholder** | optional placeholder for text and select properties. | -| **options** | optional array of options for checkbox, radio, select, selectlist properties. | +| **default** | optional, the default property value. | +| **comment** | optional, the property description, it is used by the component Selector in the Admin Interface. | +| **placeholder** | optional placeholder for text and select properties. | +| **options** | optional array of options for checkbox, radio, select, selectlist properties. | The **options** property key can be static or dynamic. Using the `maxItems` property, let's define static options: @@ -184,18 +184,18 @@ For more information, reference the [Livewire Component Actions documentation](h ### Component lifecycle handlers -Livewire includes a number of lifecycle hooks that allow you to run code at specific stages of a component's lifecycle. These hooks let you to conduct activities before or after specific events, including as component initialization, property updates, and template rendering. +Livewire includes a number of lifecycle hooks that allow you to run code at specific stages of a component's lifecycle. These hooks let you conduct activities before or after specific events, including as component initialization, property updates, and template rendering. -| Hook Method | Description | -|------------------| ------------------------------------------------------------ | -| **mount()** | Called when a component is created | -| **hydrate** | Called when a component is re-hydrated at the beginning of a subsequent request | -| **boot** | Called at the beginning of every request. Both initial, and subsequent | -| **updating** | Called before updating a component property | -| **updated** | Called after updating a property | -| **rendering** | Called before render() is called | -| **rendered** | Called after render() is called | -| **dehydrate** | Called at the end of every component request | +| Hook Method | Description | +|---------------|---------------------------------------------------------------------------------| +| **mount()** | Called when a component is created | +| **hydrate** | Called when a component is re-hydrated at the beginning of a subsequent request | +| **boot** | Called at the beginning of every request. Both initial, and subsequent | +| **updating** | Called before updating a component property | +| **updated** | Called after updating a property | +| **rendering** | Called before render() is called | +| **rendered** | Called after render() is called | +| **dehydrate** | Called at the end of every component request | For more information, reference the [Livewire Component Livecycle Hooks documentation](https://livewire.laravel.com/docs/lifecycle-hooks). @@ -292,7 +292,7 @@ class HelloBlock extends \Igniter\System\Classes\BaseComponent } ``` -The component properties and methods are available on the page or layout its attached through the component variable +The component properties and methods are available on the page or layout it is attached to through the component variable which corresponds to the alias of the component. For example, if the `HelloBlock` component was defined on a page or layout as `'[helloBlock]'`, you will be able to access its `alerts` through the `$helloBlock` variable: @@ -339,14 +339,14 @@ public function defineProperties(): array The method should return an array with the property keys as indexes and the property parameters as values. The property keys are used to access the component property values within the component class. -| Key | Description | -| --------------- | ------------------------------------------------------------ | -| **label** | required, the property label, it is used by the component Selector in the Admin Interface. | +| Key | Description | +|-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **label** | required, the property label, it is used by the component Selector in the Admin Interface. | | **type** | optional, specifies the property type. The type defines the form field type. Currently supported types are **
text**, **number**, **checkbox**, **radio**, **select** and **selectlist**. Default value: **text**. | -| **default** | optional, the default property value. | -| **comment** | optional, the property description, it is used by the component Selector in the Admin Interface. | -| **placeholder** | optional placeholder for text and select properties. | -| **options** | optional array of options for checkbox, radio, select, selectlist properties. | +| **default** | optional, the default property value. | +| **comment** | optional, the property description, it is used by the component Selector in the Admin Interface. | +| **placeholder** | optional placeholder for text and select properties. | +| **options** | optional array of options for checkbox, radio, select, selectlist properties. | The **options** property key can be static or dynamic. Using the `maxItems` property, let's define static options: diff --git a/customize/layouts.md b/customize/layouts.md index ad35a50..49c69ae 100644 --- a/customize/layouts.md +++ b/customize/layouts.md @@ -149,7 +149,7 @@ You can access variables within the partial like any other template variable: ## Rendering components -[Components](components.md) are reusable Blade markup blocks combining state and behavior that serve as building blocks in layouts or pages. Here, we'll cover the basics of rendering [Livewire components](components.md#livewire-component) within a layout. +[Components](../customize/components) are reusable Blade markup blocks combining state and behavior that serve as building blocks in layouts or pages. Here, we'll cover the basics of rendering [Livewire components](../customize/components#livewire-component) within a layout. Livewire component consists of two files. The first is the component class `src/Livewire/HelloBlock.php` and the second is the component template file `resources/views/livewire/hello-block.blade.php`. @@ -169,13 +169,13 @@ You can render a Livewire component in a layout using the ` ``` -For more on components, see the [Components](components.md) documentation. +For more on components, see the [Components](../customize/components) documentation. ## Execution life cycle Specific functions can be defined in the layouts PHP code section for handling the page execution life cycle: `onInit`, `onStart` and `onEnd`. -The `onInit` function is executed when all [components](../customize/components) are initialized and before AJAX requests are handled. The `onStart` function is executed at the start of the execution of the page. The `onEnd` function is executed after the page is rendered. +The `onInit` function is executed when all [components](../customize/components) are initialized and before AJAX requests are handled. The `onStart` function is executed at the start of the execution of the page. The `onEnd` function executes after the page renders. ```blade --- diff --git a/customize/pages.md b/customize/pages.md index f4a7e8e..6a4a107 100644 --- a/customize/pages.md +++ b/customize/pages.md @@ -172,7 +172,7 @@ You can access variables within the partial like any other template variable: ## Rendering components -[Components](components.md) are reusable Blade markup blocks combining state and behavior that serve as building blocks in layouts or pages. Here, we'll cover the basics of rendering [Livewire components](components.md#livewire-component) within a page. +[Components](../customize/components) are reusable Blade markup blocks combining state and behavior that serve as building blocks in layouts or pages. Here, we'll cover the basics of rendering [Livewire components](../customize/components#livewire-component) within a page. Livewire component consists of two files. The first is the component class `src/Livewire/HelloBlock.php` and the second is the component template file `resources/views/livewire/hello-block.blade.php`. @@ -188,7 +188,7 @@ food: "Pizza"

{{ $this->page->food }}

``` -For more on components, see the [Components](components.md) documentation. +For more on components, see the [Components](../customize/components) documentation. ## Execution life cycle diff --git a/customize/partials.md b/customize/partials.md index abe9ff8..546f386 100644 --- a/customize/partials.md +++ b/customize/partials.md @@ -8,7 +8,7 @@ sortOrder: 130 Partials include reusable Blade markup blocks that can be used anywhere on the website. Partials are extremely useful for page sections that appear on multiple pages or layouts. -While you can use Blade's `@include` directive, [components](components.md) provide similar functionality and have several advantages over the `@include` directive, including data and attribute binding. +While you can use Blade's `@include` directive, [components](../customize/components) provide similar functionality and have several advantages over the `@include` directive, including data and attribute binding. Partial files live in the **resources/views/includes** subdirectory of a theme directory. For example: diff --git a/customize/themes.md b/customize/themes.md index 6b9410b..115f3aa 100644 --- a/customize/themes.md +++ b/customize/themes.md @@ -87,19 +87,19 @@ A `composer.json` file for a theme looks like this: } ``` -| Field | Description | -|-----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **name** | The Composer package's name in vendor/package format, **required**. You should use a vendor name that is unique to you, such as your GitHub username. You should prefix the package part with ti-theme- to indicate that your package is intended for use with TastyIgniter. | -| **type** | MUST be set to tastyigniter-package, ensures that your theme will be installed as such when someone "requires" it, **required**. | -| **description** | A one-sentence summary of what the extension does, **required**. (max. char: 130) | -| **authors** | An object to specify the name of the extension author, **required**. | -| **authors.0.name** | An object to specify the name of the extension author, **required**. | -| **authors.0.email** | An object to specify the email of the extension author, **optional**. | -| **require** | Defines other TastyIgniter packages your theme depends on, **optional**. In the example above, **acme-purple** theme depends on the **tastyigniter/ti-theme-orange** theme. | -| **extra.tastyigniter-theme** | Holds TastyIgniter-specific extension metadata, such as your theme's display name and paths, **required**. | -| **extra.tastyigniter-theme.code** | the theme code, **required**. The value is used on the TastyIgniter marketplace for setting the theme code value. | -| **extra.tastyigniter-theme.name** | specifies the theme name, **required**. | -| **extra.tastyigniter-theme.locked** | specifies whether a child theme must be created to customize the theme, **optional**. | +| Field | Description | +|-------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **name** | The Composer package's name in vendor/package format, **required**. You should use a vendor name that is unique to you, such as your GitHub username. You should prefix the package part with ti-theme- to indicate that your package is intended for use with TastyIgniter. | +| **type** | MUST be set to tastyigniter-package, ensures that your theme will be installed as such when someone "requires" it, **required**. | +| **description** | A one-sentence summary of what the extension does, **required**. (max. char: 130) | +| **authors** | An object to specify the name of the extension author, **required**. | +| **authors.0.name** | An object to specify the name of the extension author, **required**. | +| **authors.0.email** | An object to specify the email of the extension author, **optional**. | +| **require** | Defines other TastyIgniter packages your theme depends on, **optional**. In the example above, **acme-purple** theme depends on the **tastyigniter/ti-theme-orange** theme. | +| **extra.tastyigniter-theme** | Holds TastyIgniter-specific extension metadata, such as your theme's display name and paths, **required**. | +| **extra.tastyigniter-theme.code** | the theme code, **required**. The value is used on the TastyIgniter marketplace for setting the theme code value. | +| **extra.tastyigniter-theme.name** | specifies the theme name, **required**. | +| **extra.tastyigniter-theme.locked** | specifies whether a child theme must be created to customize the theme, **optional**. | ## Assets manifest @@ -146,7 +146,7 @@ A `resources/meta/assets.json` file looks like this: ``` > The `$` symbol is a placeholder for the `public` path. Theme assets are published to the `public` directory of the TastyIgniter installation when you install or update the theme or run the `php artisan igniter:theme-vendor-publish --theme=your-theme` command. -JavaScript code should be placed in external files whenever possible. Use [`@scripts`](../customize/markup-guide.md#themescripts) to load your scripts and [`@styles`](../customize/markup-guide#themestyles) to load your styles. +JavaScript code should be placed in external files whenever possible. Use [`@scripts`](../customize/markup-guide#themescripts) to load your scripts and [`@styles`](../customize/markup-guide#themestyles) to load your styles. ## Template structure @@ -204,7 +204,7 @@ description: Default Layout ### Front-matter section -This is the first section in the file and it contains valid YAML set between triple-dashed lines. You can set predefined variables or create custom ones which will be available to you to access from component blade views. Here is a basic example: +This is the first section in the file which contains valid YAML set between triple-dashed lines. You can set predefined variables or create custom ones which will be available to you to access from component blade views. Here is a basic example: ```blade --- diff --git a/extend/extensions.md b/extend/extensions.md index f918fde..dd583dc 100644 --- a/extend/extensions.md +++ b/extend/extensions.md @@ -54,7 +54,7 @@ following command from the application directory to generate a basic extension d php artisan make:igniter-extension Acme.HelloWorld ``` -> We strongly recommend that you follow the [TastyIgniter coding standards](../resources/php-coding-guidelines.md) when creating your own extensions. It is a requirement for any changes to the TastyIgniter core code. +> We strongly recommend that you follow the [TastyIgniter coding standards](../resources/php-coding-guidelines) when creating your own extensions. It is a requirement for any changes to the TastyIgniter core code. ### Extension manifest (composer.json) @@ -87,18 +87,18 @@ A `composer.json` file is essential for storing metadata about the extension. } ``` -| Field | Description | -| --------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **name** | The Composer package's name in vendor/package format, **required**. You should use a vendor name that is unique to you, such as your GitHub username. You should prefix the package part with ti-ext- to indicate that your package is intended for use with TastyIgniter. | -| **type** | MUST be set to tastyigniter-package, ensures that your extension will be installed as such when someone "requires" it, **required**. | -| **description** | A one-sentence summary of what the extension does, **required**. (max. char: 130) | -| **authors** | An object to specify the name of the extension author, **required**. | -| **require** | Defines other TastyIgniter extensions your extension depends on, **optional**. In the example above, **acme.helloworld** extension depends on the **tastyigniter/ti-ext-local** extension. | -| **extra.tastyigniter-extension** | Holds TastyIgniter-specific extension metadata, such as your extension's display name and icon style, **required**. | -| **extra.tastyigniter-extension.code** | The extension unique identifier code, **required**. | -| **extra.tastyigniter-extension.name** | Specifies the extension name, **required**. The value is used as the extension display name. | -| **extra.tastyigniter-extension.icon** | An object that defines the icon for your extension. The **name** property is the name of a [Font Awesome icon class](https://fontawesome.com/icons). All other properties are used as the style attribute for your extension's icon. | -| **extra.tastyigniter-extension.homepage** | Specifies the extension website URL, **optional**. | +| Field | Description | +|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **name** | The Composer package's name in vendor/package format, **required**. You should use a vendor name that is unique to you, such as your GitHub username. You should prefix the package part with ti-ext- to indicate that your package is intended for use with TastyIgniter. | +| **type** | MUST be set to tastyigniter-package, ensures that your extension will be installed as such when someone "requires" it, **required**. | +| **description** | A one-sentence summary of what the extension does, **required**. (max. char: 130) | +| **authors** | An object to specify the name of the extension author, **required**. | +| **require** | Defines other TastyIgniter extensions your extension depends on, **optional**. In the example above, **acme.helloworld** extension depends on the **tastyigniter/ti-ext-local** extension. | +| **extra.tastyigniter-extension** | Holds TastyIgniter-specific extension metadata, such as your extension's display name and icon style, **required**. | +| **extra.tastyigniter-extension.code** | The extension unique identifier code, **required**. | +| **extra.tastyigniter-extension.name** | Specifies the extension name, **required**. The value is used as the extension display name. | +| **extra.tastyigniter-extension.icon** | An object that defines the icon for your extension. The **name** property is the name of a [Font Awesome icon class](https://fontawesome.com/icons). All other properties are used as the style attribute for your extension's icon. | +| **extra.tastyigniter-extension.homepage** | Specifies the extension website URL, **optional**. | See [the composer.json schema](https://getcomposer.org/doc/04-schema.md) documentation for information about other properties you can add to composer.json. @@ -144,7 +144,7 @@ The following methods are supported in the extension class: | **register()** | register method, called when the plugin is first registered. | | **boot()** | boot method, called right before the request route. | | **registerNavigation()** | registers admin navigation menu items for this extension, see below for example. | -| **registerPermissions()** | registers any [staff permissions](../extend/permissions.md#registering-permissions) supplied by this extension. | +| **registerPermissions()** | registers any [staff permissions](../extend/permissions#registering-permissions) supplied by this extension. | | **registerSettings()** | registers any [admin settings page](../extend/extensions#registering-settings-navigation-link) supplied by this extension. | | **registerDashboardWidgets()** | registers any [admin dashboard widgets](../extend/widgets#using-dashboard-widget), supplied by this extension. | | **registerFormWidgets()** | registers any [admin form widgets](../extend/widgets#using-form-widget) supplied by this extension. | diff --git a/extend/lists.md b/extend/lists.md index 8dc930f..b575fe5 100644 --- a/extend/lists.md +++ b/extend/lists.md @@ -269,7 +269,7 @@ For each column can specify these options (where applicable): There are various column types that can be used to control how the list column is displayed. - [Text](../extend/lists#text) -- [Switch](../extend/lists.md#switch-1) +- [Switch](../extend/lists#switch-1) - [Money](../extend/lists#money) - [Currency](../extend/lists#currency) - [Date](../extend/lists#date-1) diff --git a/extend/widgets.md b/extend/widgets.md index 7696c9a..b710776 100644 --- a/extend/widgets.md +++ b/extend/widgets.md @@ -210,7 +210,7 @@ public function registerFormWidgets() ### Loading form data -The primary function of a form widget is to interact with your model, by loading and saving data to the database. When a form widget is rendered, it retrieves its stored value using the `getLoadValue` method. Additionally, the `getId` and `getFieldName` methods provide a unique identifier and the name for a HTML element used in the form. These values are typically passed to the widget partial at the time of rendering. +The primary function of a form widget is to interact with your model, by loading and saving data to the database. When a form widget is rendered, it retrieves its stored value using the `getLoadValue` method. Additionally, the `getId` and `getFieldName` methods provide a unique identifier and the name for an HTML element used in the form. These values are typically passed to the widget partial at the time of rendering. Here's how you might implement this in the `render` method: diff --git a/installation.md b/installation.md index 584b8b3..381cb02 100644 --- a/installation.md +++ b/installation.md @@ -73,7 +73,7 @@ for the database configuration, application URL and administrator details. Some setup require an unattended mode so that the application can easily be built into automated infrastructure pipelines and build tools, e.g. Docker. -To run this, its similar to the above command, just instead we provide all of the option values up-front within the +To run this, it is similar to the above command, just instead we provide all the option values up-front within the projects `.env` and pass the `--no-interaction` flag to the installation script: diff --git a/resources/code-of-conduct.md b/resources/code-of-conduct.md index 8098e2d..868122d 100644 --- a/resources/code-of-conduct.md +++ b/resources/code-of-conduct.md @@ -6,7 +6,7 @@ sortOrder: 400 One of our main goals, as an expanding community is to include as many contributors from various backgrounds and areas. We want every single member of the TastyIgniter community to get as much out of it as possible. Therefore, we don't want to scare people off and want to make it a place where all people can co-exist regardless of religion, socio-economic status, ethnicity, ability, sexual orientation or gender. -Whether you are using the TastyIgniter forum, GitHub, Discord chat or an alternative means of communication outside of our community, this code of conduct is applicable. +Whether you are using the TastyIgniter forum, GitHub, Discord chat or an alternative means of communication outside our community, this code of conduct is applicable. ### Always exercise patience and have a friendly attitude diff --git a/resources/contribution-guide.md b/resources/contribution-guide.md index d28e2a3..4d7a8d9 100644 --- a/resources/contribution-guide.md +++ b/resources/contribution-guide.md @@ -7,7 +7,7 @@ sortOrder: 410 Interested in contributing to the development of TastyIgniter? All contributions are appreciated and welcome: from opening a bug report to creating a pull request. -Before contributing, please read the [code of conduct](code-of-conduct.md). +Before contributing, please read the [code of conduct](../resources/code-of-conduct). To order to learn a little more about how TastyIgniter operates, we suggest that you read the documentation, if you're just beginning. @@ -80,7 +80,7 @@ Follow these steps: - Run ./vendor/bin/phpunit to **test** your code - Run ./vendor/bin/pint to **fix** any code style issues - **Commit** your code with a descriptive message. -- Submit in the **pull request** on Github +- Submit in the **pull request** on GitHub ## Development tools @@ -104,7 +104,7 @@ contribute. Here's how styling perfect TastyIgniter documentation pages is done: - Try not to use H1 headers. - A TOC list would be generated automatically for each page with at least one H2 header. The TOC would have links to all - of the page's H2 headers. + of all the page's H2 headers. - The introductory text would be displayed below the TOC. - Try to use only H2 and H3 headers. - Each H2 and H3 header could have a link defined as `` or have it generated automatically. @@ -113,7 +113,7 @@ contribute. Here's how styling perfect TastyIgniter documentation pages is done: - Use the inline code tags for all code-related - variable names, function names, syntax examples, etc. - Don't hesitate to make cross-links to other documentation articles. There is no need to add links to the same article in the same paragraph. -- For your reference, see the [pages.md](https://github.com/tastyigniter/docs/blob/master/customize/pages.md) - or [themes.md](https://github.com/tastyigniter/docs/blob/master/customize/themes.md) files. +- For your reference, see the [pages](https://github.com/tastyigniter/docs/blob/master/customize/pages.md) + or [themes](https://github.com/tastyigniter/docs/blob/master/customize/themes.md) files. > For more information on contributing, read the guide here \ No newline at end of file diff --git a/resources/php-coding-guidelines.md b/resources/php-coding-guidelines.md index 4789091..589967d 100644 --- a/resources/php-coding-guidelines.md +++ b/resources/php-coding-guidelines.md @@ -37,7 +37,7 @@ public string|null $variable; #### Void return types -If a method returns nothing, it should be indicated with void. This makes it more clear to the users of your code what +If a method returns nothing, it should be indicated with void. This makes it clearer to the users of your code what your intention was when writing it. ```php @@ -116,7 +116,7 @@ Also, follow naming conventions accepted by Laravel community: ### Jobs -A job's name should describe its action and an optional `Job` suffix.. +A job's name should describe its action and an optional `Job` suffix. Example: `CreateUser` or `PerformDatabaseCleanupJob` @@ -522,7 +522,7 @@ $greeting = 'Hi, I am ' . $name . '.'; ### Bracket position -Always use curly brackets, except its a one line if condition +Always use curly brackets, except it is a one line if condition **Good:** @@ -736,7 +736,7 @@ public function handle() } ``` -When the main function of a result is processing items, consider adding output inside of the loop, so progress can be +When the main function of a result is processing items, consider adding output inside the loop, so progress can be tracked. Put the output before the actual process. If something goes wrong, this makes it easy to know which item caused the error. diff --git a/upgrade-guide.md b/upgrade-guide.md index 60a9ca5..d14418b 100644 --- a/upgrade-guide.md +++ b/upgrade-guide.md @@ -11,7 +11,7 @@ every part of the codebase. ## Backing Up The Database -Use this command to backup your MySQL database. For example, if the username is `root` and the database is called +Use this command back up your MySQL database. For example, if the username is `root` and the database is called `database_name`. You will then be prompted to enter the password. ```bash From 4bdd19e7d125b92147e6ffb0053ed907b9971633 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Sat, 27 Apr 2024 14:04:24 +0100 Subject: [PATCH 07/14] update --- advanced/ajax-request.md | 2 ++ customize/markup-guide.md | 12 ++++++------ extend/forms.md | 2 ++ extend/lists.md | 1 + installation.md | 3 +-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/advanced/ajax-request.md b/advanced/ajax-request.md index 03ea42e..20e3395 100644 --- a/advanced/ajax-request.md +++ b/advanced/ajax-request.md @@ -124,6 +124,7 @@ The `$.request` object supports additional options for customizing AJAX requests Some of the common options include: +{.grid-2} - [update](../advanced/ajax-request#update) - [confirm](../advanced/ajax-request#confirm) - [data](../advanced/ajax-request#data) @@ -341,6 +342,7 @@ The AJAX framework triggers several events on the updated elements, the triggeri Here are some of the global AJAX events that you can listen to: +{.grid-2} - [ajaxBeforeSend](../advanced/ajax-request#ajaxbeforesend) - [ajaxBeforeUpdate](../advanced/ajax-request#ajaxbeforeupdate) - [ajaxUpdate](../advanced/ajax-request#ajaxupdate) diff --git a/customize/markup-guide.md b/customize/markup-guide.md index 102f7f4..cdb06a7 100644 --- a/customize/markup-guide.md +++ b/customize/markup-guide.md @@ -29,7 +29,7 @@ Directives are a unique feature to Laravel Blade and are prefixed with `@` chara > **Note:** The Blade directives provided by TastyIgniter are not the same as the Laravel Blade directives. The Blade directives provided by TastyIgniter are specific to TastyIgniter and are not compatible with Laravel. -### @themePage +### `@themePage` The `@themePage` tag renders the contents of a page into a layout template. The directive has no parameters. @@ -37,7 +37,7 @@ The `@themePage` tag renders the contents of a page into a layout template. The @themePage ``` -### @themePartial +### `@themePartial` The `@themePartial` directive renders a partial template file located under the `_partials` subdirectory of a theme. If you are rendering blade views from the other subdirectory of a theme, use Blade's `@include` directive instead. @@ -73,7 +73,7 @@ If you need to render the first partial that exists from a given array of partia @themePartialFirst(['custom.partial-name', 'partial-name'], ['status' => 'complete']) ``` -### @themeComponent +### `@themeComponent` The `@themeComponent` directive renders a Theme component. The directive has a single required parameter - the name of the component. To render a Livewire component, use the `@livewire` directive instead. @@ -107,7 +107,7 @@ If you need to render the first component that exists from a given array of comp @themeComponentFirst(['componentNameExtended', 'componentName'], ['status' => 'complete']) ``` -### @themeContent +### `@themeContent` The `@themeContent` directive renders the contents of a static template file located under the `_content` subdirectory of a theme. If you are rendering blade views from the other subdirectory of a theme, use Blade's `@include` directive instead. @@ -118,7 +118,7 @@ The directive has a single required parameter - the name of the content template @themeContent('content-name') ``` -### @themeStyles +### `@themeStyles` The `@themeStyles` directive renders all stylesheets that are defined during the rendering of the page. This includes all `.css` files registered within the `resources/meta/assets.json` manifest file, as well as stylesheets injected using the controller's `addCss` method. The directive has no parameters. @@ -132,7 +132,7 @@ The `@themeStyles` directive renders all stylesheets that are defined during the ``` -### @themeScripts +### `@themeScripts` The `@themeScripts` directive renders all scripts that are defined during the rendering of the page. This includes all `.js` files registered within the `resources/meta/assets.json` manifest file, as well as scripts injected using the controller's `addJs` method. The directive has no parameters. diff --git a/extend/forms.md b/extend/forms.md index 95f800b..ecd04fd 100644 --- a/extend/forms.md +++ b/extend/forms.md @@ -211,6 +211,7 @@ The following options are available for form fields (where applicable): The following native field types are available for form fields. For more advanced form fields, a [form widget](../extend/forms#form-widgets) can be used instead. +{.grid-3} - [Text](../extend/forms#text) - [Number](../extend/forms#number) - [Money](../extend/forms#money) @@ -569,6 +570,7 @@ Options for checkbox lists also support secondary descriptions using the array f TastyIgniter includes several form widgets, although it is common for extensions to provide their own custom form widgets. For a deeper dive into how these widgets work and how you can implement or modify them, you can refer to the [Form Widgets](../extend/widgets#using-form-widget) article. +{.grid-2} - [Code editor](../extend/forms#code-editor) - [Color picker](../extend/forms#color-picker) - [Components](../extend/forms#components) diff --git a/extend/lists.md b/extend/lists.md index b575fe5..cdcf32d 100644 --- a/extend/lists.md +++ b/extend/lists.md @@ -268,6 +268,7 @@ For each column can specify these options (where applicable): There are various column types that can be used to control how the list column is displayed. +{.grid-2} - [Text](../extend/lists#text) - [Switch](../extend/lists#switch-1) - [Money](../extend/lists#money) diff --git a/installation.md b/installation.md index 381cb02..68103a4 100644 --- a/installation.md +++ b/installation.md @@ -4,8 +4,7 @@ section: "getting-started" sortOrder: 10 --- -As of Version 4, TastyIgniter can be installed as a stand-alone application, or as a package inside an existing Laravel -application. +As of Version 4, TastyIgniter can be installed as a [stand-alone](#stand-alone-installation) application, or as a [package](#package-installation) inside an existing Laravel application. ## Stand-alone Installation From 56923a5c978cee5039ae1f59d0a05dbefc1f3721 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Thu, 9 May 2024 13:18:04 +0100 Subject: [PATCH 08/14] improvements --- advanced/mail.md | 75 ++++++++++++++++++++++++++++++++++++-- advanced/validation.md | 2 +- customize/media-manager.md | 27 +++++++++++++- extend/controllers.md | 2 +- extend/forms.md | 30 +++++++-------- extend/lists.md | 4 +- extend/permissions.md | 4 +- extend/widgets.md | 8 ++-- installation.md | 4 +- upgrade-guide.md | 2 + 10 files changed, 126 insertions(+), 32 deletions(-) diff --git a/advanced/mail.md b/advanced/mail.md index 36e93dd..5c5e423 100644 --- a/advanced/mail.md +++ b/advanced/mail.md @@ -6,15 +6,33 @@ sortOrder: 320 ## Introduction -TastyIgniter uses the Laravel Mail component to send emails. The Mail component provides a clean, simple API which allows you to send emails through a variety of drivers, including SMTP, Mailgun, Postmark, Amazon SES. +TastyIgniter uses the Laravel Mail component to send emails. The Mail component provides a clean, simple API which allows you to send emails through a variety of drivers, including SMTP, Mailgun, Postmark and Amazon SES. ### Driver prerequisites -Before using the Mailgun, SparkPost or SES drivers you will need to install [Drivers extension](https://tastyigniter.com/marketplace/item/igniter-drivers). +To use the Mailgun, Postmark and Amazon SES drivers, install the required dependencies via Composer. + +#### Mailgun + +```bash +composer require symfony/mailgun-mailer symfony/http-client +``` + +#### Postmark + +```bash +composer require symfony/postmark-mailer symfony/http-client +``` + +#### Amazon SES + +```bash +composer require aws/aws-sdk-php +``` ## Configuration -The mail configuration file is located at `config/mail.php`. In this file, you may configure the default mail driver, mail sending options, and mail "from" address. Next, verify that your `config/services.php` configuration file contains the required credentials for your mail service. +Next, you can configure your mail settings from the _System > Settings > Mail_ admin settings page or through the mail configuration file located at `config/mail.php`. In this file, you may configure the default mail driver, mail sending options, and mail "from" address. Next, verify that your `config/services.php` configuration file contains the required credentials for your mail service. ## Writing mail @@ -210,6 +228,57 @@ Mail::queueTemplate('vendor.extension::mail.message', $data, function($message) }); ``` +### The `SendsMailTemplate` model trait + +The `SendsMailTemplate` trait provides a convenient way to send mail templates from a model. To use this trait, add it to your model class and define the `mailGetData` method that returns the mail template variables: + +```php +use Igniter\Flame\Mail\SendMailTemplate; + +class Order extends Model +{ + use SendMailTemplate; + + public function mailGetData() + { + return [ + 'customer' => $this->customer, + ]; + } +} +``` + +You can use the `mailGetRecipients` method to define the recipients of the mail message. The `mailGetRecipients` method accepts a single `$recipientType` parameter and returns an array of recipients, where each recipient is an array containing the email address and name of the recipient. + +```php +public function mailGetRecipients($recipientType) +{ + return [ + [$this->customer->email, $this->customer->name], + ]; +} +``` + +You may also customise the reply-to address by defining the `mailGetReplyTo` method: + +```php +public function mailGetReplyTo() +{ + return [$this->customer->email, $this->customer->name]; +} +``` + +To send the mail message, use the `mailSend` method on the model instance, where the first parameter is the mail template code, and the second parameter is the recipient type: + +```php +$order = Order::find(1); + +$order->mailSend('vendor.extension::mail.message', 'customer'); +``` + +Possible values for the recipient type are `customer`, `location` or `admin`. + + ## Registering mail templates, layouts & partials To register mail templates, layouts, and partials in the Extension class, you can use the [`registerMailTemplates`](../extend/extensions#extension-class-methods), [`registerMailLayouts`](../extend/extensions#extension-class-methods), and [`registerMailPartials`](../extend/extensions#extension-class-methods) methods, respectively. These methods allow you to define the mail templates, layouts, and partials that your extension provides, making them available for customization via the admin interface: diff --git a/advanced/validation.md b/advanced/validation.md index 48652b4..898ebf8 100644 --- a/advanced/validation.md +++ b/advanced/validation.md @@ -166,7 +166,7 @@ In the example above, the `validate` method will return an array containing the Form requests provide a convenient way to validate incoming HTTP requests in TastyIgniter. By defining validation rules and error messages in a single location, you can maintain and reuse the validation logic across multiple controller actions. This approach helps to keep your controller actions clean and readable by moving the validation logic out of the controller and into a separate class. -Form Requests are typically stored in the extension's `src/Http/Requests` directory. +Form Requests are typically stored in the `src/Http/Requests` directory of an extension. ### Creating a form request diff --git a/customize/media-manager.md b/customize/media-manager.md index 5368748..fd809d5 100644 --- a/customize/media-manager.md +++ b/customize/media-manager.md @@ -6,9 +6,32 @@ sortOrder: 170 ## Introduction -TastyIgniter provides a flexible and configurable media management system. The Media Manager allows you to upload, organize, and manage media files. By default, Media Manager works with the `storage/app/public/media` directory. It is possible to use external storages such as Amazon S3 or Rackspace CDN. +TastyIgniter provides a flexible and configurable media management system. The Media Manager allows you to upload, organize, and manage media files. By default, Media Manager works with the `storage/app/public/media` directory. It is possible to use external storages such as Amazon S3. -> The [Drivers extension](https://tastyigniter.com/marketplace/item/igniter-drivers) must be installed to use external storage drivers. +## Configuring external storage + +To use the S3 driver, install the required dependencies via Composer. + +```bash +composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies +``` + +Configure the S3 driver using the `.env` file. + +```dotenv +FILESYSTEM_DISK=s3 +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false +``` + +Using S3 compatible storage services like DigitalOcean Spaces, configure the driver using the `.env` file. + +```dotenv +AWS_ENDPOINT=https://nyc3.digitaloceanspaces.com +``` ## Media configuration options diff --git a/extend/controllers.md b/extend/controllers.md index 520ca04..d83c597 100644 --- a/extend/controllers.md +++ b/extend/controllers.md @@ -8,7 +8,7 @@ sortOrder: 210 TastyIgniter Admin implements the MVC pattern. Controllers manage admin pages and implement various features like forms and lists. This article describes how to develop admin controllers and how to configure controller methods. -Controllers are typically stored in the extension's `src/Http/Controllers` directory. Controller views are `.blade.php` blade views that reside in the `resources/views` extension's directory. The controller view directory name matches the controller class name written in lowercase. An example of a controller directory structure: +Controllers are typically stored in the `src/Http/Controllers` directory of an extension. Controller views are `.blade.php` blade views that reside in the `resources/views` directory of an extension. The controller view directory name matches the controller class name written in lowercase. An example of a controller directory structure: ```yaml author/ diff --git a/extend/forms.md b/extend/forms.md index ecd04fd..42d0e67 100644 --- a/extend/forms.md +++ b/extend/forms.md @@ -50,7 +50,7 @@ The following fields are optional in the form configuration: ### Form definition file -The form definition file is typically located in the extension's `resources/models` directory. The form definition file should return a `form` array of [toolbar buttons](../extend/lists#toolbar-button-options) and [form fields](../extend/lists#scope-options). For example: +The form definition file is typically stored in the `resources/models` directory of an extension. The form definition file should return a `form` array of [toolbar buttons](../extend/lists#toolbar-button-options) and [form fields](../extend/lists#scope-options). For example: ```php return [ @@ -597,7 +597,7 @@ TastyIgniter includes several form widgets, although it is common for extensions ], ``` -The following options are available for the `codeeditor` field type: +The following options are available for the `codeeditor` form widget type: - `mode`: The programming language to use for syntax highlighting. Default is `css`. - `theme`: The color theme option passed to the CodeMirror JS library. Default is `material`. @@ -613,7 +613,7 @@ The following options are available for the `codeeditor` field type: ], ``` -The following options are available for the `colorpicker` field type: +The following options are available for the `colorpicker` form widget type: - `availableColors`: An array of colors to display in the color picker for quick color selection. @@ -633,7 +633,7 @@ The following options are available for the `colorpicker` field type: ], ``` -The following options are available for the `components` field type: +The following options are available for the `components` form widget type: - `form`: The form definition for the component fields. - `prompt`: The prompt text to display when no component is selected. @@ -664,7 +664,7 @@ The following options are available for the `components` field type: ], ``` -The following options are available for the `connector` field type: +The following options are available for the `connector` form widget type: - `form`: The form definition for creating and managing related records. Either a reference to the [form definition file](../extend/forms#form-definition-file) or an array of fields. - `formName`: The form name to use for the record editor popup. Default is `Record`. @@ -700,7 +700,7 @@ The following options are available for the `connector` field type: ], ``` -The following options are available for the `datatable` field type: +The following options are available for the `datatable` form widget type: - `columns`: An array of columns to display in the table. Each column should have a `title` definition. - `defaultSort`: The default column to sort by. Example `name asc`. @@ -726,7 +726,7 @@ The following options are available for the `datatable` field type: ], ``` -The following options are available for the `datepicker` field type: +The following options are available for the `datepicker` form widget type: - `mode`: The date picker mode. Options are `date`, `time`, `datetime`. Default is `date`. - `dateFormat`: The date format to use when displaying the date. Default is `Y-m-d`. @@ -745,7 +745,7 @@ The following options are available for the `datepicker` field type: ], ``` -The following options are available for the `markdown` field type: +The following options are available for the `markdown` form widget type: - `mode`: The editor view mode. Options are `tab` or `split`. Default is `tab`. @@ -760,7 +760,7 @@ The following options are available for the `markdown` field type: ], ``` -The following options are available for the `mediafinder` field type: +The following options are available for the `mediafinder` form widget type: - `mode`: The media finder view mode. Options are `grid`, `inline`. Default is `grid`. - `prompt`: The prompt text to display when no media is selected. @@ -792,7 +792,7 @@ The following options are available for the `mediafinder` field type: ], ``` -The following options are available for the `recordeditor` field type: +The following options are available for the `recordeditor` form widget type: - `modelClass`: The model class to use for fetching records. - `form`: The form definition for creating and managing records. Either a reference to the [form definition file](../extend/forms#form-definition-file) or an array of fields. @@ -828,7 +828,7 @@ The following options are available for the `addonRight` and `addonLeft` buttons ], ``` -The following options are available for the `relation` field type: +The following options are available for the `relation` form widget type: - `relationFrom`: The relation name to use for fetching related records, if different from the field name. - `nameFrom`: The model attribute name to use for displaying the related label. @@ -860,7 +860,7 @@ The following options are available for the `relation` field type: ], ``` -The following options are available for the `repeater` field type: +The following options are available for the `repeater` form widget type: - `form`: The form definition for the fields to repeat. Either a reference to the [form definition file](../extend/forms#form-definition-file) or an array of fields. - `prompt`: The text to display for the create button. Default is `Add item`. @@ -881,7 +881,7 @@ The following options are available for the `repeater` field type: ], ``` -The following options are available for the `richeditor` field type: +The following options are available for the `richeditor` form widget type: - `size`: The size of the editor. Options are `small`, `large`. Default is `large`. - `toolbarButtons`: The buttons to display in the editor toolbar. @@ -911,7 +911,7 @@ The following options are available for the `richeditor` field type: ], ``` -The following options are available for the `statuseditor` field type: +The following options are available for the `statuseditor` form widget type: - `form`: The form definition for creating and managing status and assignee. Either a reference to the [form definition file](../extend/forms#form-definition-file) or an array of fields. - `formTitle`: The title of the popup window. Default is `Add %s`. @@ -1128,7 +1128,7 @@ public function edit($recordId, $context = null) ### Overriding form views -You can override the form views by creating a new view file in the extension's `resources/views` directory. The view file should have the same name as the form view file you want to override. For example, to override the `create.blade.php` view file rendered from `MyController`, create a new view file in the `resources/views/mycontroller` directory with the same name. Here is an example adding a sidebar to the form **create** page: +You can override the form views by creating a new view file in the `resources/views` directory of an extension. The view file should have the same name as the form view file you want to override. For example, to override the `create.blade.php` view file rendered from `MyController`, create a new view file in the `resources/views/mycontroller` directory with the same name. Here is an example adding a sidebar to the form **create** page: ```blade
diff --git a/extend/lists.md b/extend/lists.md index cdcf32d..538028e 100644 --- a/extend/lists.md +++ b/extend/lists.md @@ -45,7 +45,7 @@ The configuration options listed below are optional. ### List definition file -The list definition file is typically located in the extension's `resources/models` directory. The list definition file should return a `list` array of [toolbar buttons](../extend/lists#toolbar-button-options), [filter scopes](../extend/lists#scope-options) and [lists columns](../extend/lists#column-options) definitions. For example: +The list definition file is typically stored in the `resources/models` directory of an extension. The list definition file should return a `list` array of [toolbar buttons](../extend/lists#toolbar-button-options), [filter scopes](../extend/lists#scope-options) and [lists columns](../extend/lists#column-options) definitions. For example: ```php return [ @@ -484,7 +484,7 @@ public function index() ### Overriding views -You can override the list views by creating a new view file in the extension's `resources/views` directory. The view file should have the same name as the list view file you want to override. For example, to override the `index.blade.php` view file rendered from `MyController`, create a new view file in the `resources/views/mycontroller` directory with the same name. Here is an example adding a sidebar to the list: +You can override the list views by creating a new view file in the `resources/views` directory of an extension. The view file should have the same name as the list view file you want to override. For example, to override the `index.blade.php` view file rendered from `MyController`, create a new view file in the `resources/views/mycontroller` directory with the same name. Here is an example adding a sidebar to the list: ```blade
diff --git a/extend/permissions.md b/extend/permissions.md index d93f58a..d0fa578 100644 --- a/extend/permissions.md +++ b/extend/permissions.md @@ -95,12 +95,12 @@ Here an example using the `hasPermission` method in the controller code: ```php // Check if the user has any permission within the 'Author.Extension' scope -if ($this.user.hasPermission('Author.Extension.*')) { +if ($user->hasPermission('Author.Extension.*')) { // } // Check if the user has both 'ManagePages' and 'ManageMenus' permissions -if ($this.user.hasPermission([ +if ($user->hasPermission([ 'Author.Extension.ManagePages', 'Author.Extension.ManageMenus' ], true)) { diff --git a/extend/widgets.md b/extend/widgets.md index b710776..42b09a0 100644 --- a/extend/widgets.md +++ b/extend/widgets.md @@ -12,7 +12,7 @@ In TastyIgniter, widgets are self-contained blocks of functionality used to perf Widgets in TastyIgniter are the admin equivalent of frontend [components](../customize/components). The major difference is that admin widgets use PHP arrays for configuration and are linked specifically to admin pages. -Widget classes reside in the extension's `src/Widgets` directory. Widgets may include assets and partials to enhance functionality. Here's an example of a typical widget directory structure: +Widget classes reside in the `src/Widgets` directory of an extension. Widgets may include assets and partials to enhance functionality. Here's an example of a typical widget directory structure: ```yaml author/ @@ -51,7 +51,7 @@ class MyWidget extends \Igniter\Admin\Classes\BaseWidget } ``` -The widget class must implement a `render()` method that returns the widget's markup. In this example, the `makePartial()` method will scan the extension's `resources/views/widgets` or `resources/views` directory to render the `mywidget.blade.php` view file. The `$vars` property is used to pass data to the view file. Alternatively you may pass the variables to the second parameter of the `makePartial()` method: +The widget class must implement a `render()` method that returns the widget's markup. In this example, the `makePartial()` method will scan the `resources/views/widgets` or `resources/views` directory of an extension to render the `mywidget.blade.php` view file. The `$vars` property is used to pass data to the view file. Alternatively you may pass the variables to the second parameter of the `makePartial()` method: ```php return $this->makePartial('mywidget', ['var' => 'value']); @@ -110,7 +110,7 @@ Once a widget is bound to a backend controller in TastyIgniter, you can access i Form widgets in TastyIgniter allow you to introduce new control types to admin forms. To use form widgets, they must first be registered in the [Extension class](../extend/extensions#extension-class). -Form widget classes are located in the extension's `src/FormWidgets` directory. Form widgets can also include assets and partials. Here's an example: +Form widget classes are located in the `src/FormWidgets` directory of an extension. Form widgets can also include assets and partials. Here's an example: ```yaml author/ @@ -259,7 +259,7 @@ public function getSaveValue($value) Dashboard widgets in TastyIgniter are used to display information on the admin dashboard. They are similar to form widgets but are designed to be used on the dashboard page. Dashboard widgets can be registered in the [Extension class](../extend/extensions#extension-class). -Dashboard widget classes are located in the extension's `src/DashboardWidgets` directory. Similarly to all form widgets, dashboard widgets can also include assets and partials. Here's an example: +Dashboard widget classes are located in the `src/DashboardWidgets` directory of an extension. Similarly to all form widgets, dashboard widgets can also include assets and partials. Here's an example: ```yaml author/ diff --git a/installation.md b/installation.md index 68103a4..4fcb867 100644 --- a/installation.md +++ b/installation.md @@ -25,7 +25,7 @@ composer. To install the platform, use the `create-project` command in the t below creates a new project in the directory `mytasty`. ```bash -composer create-project tastyigniter/tastyigniter mytasty +composer create-project tastyigniter/tastyigniter:v4.x-dev mytasty ``` From here, you can move on to the [Setting up TastyIgniter](#setting-up-tastyigniter) step. @@ -46,7 +46,7 @@ To install TastyIgniter as a package from your command line, run the following c directory: ```bash -composer require tastyigniter/core +composer require tastyigniter/core:dev-master ``` From here, you can move on to the [Setting up TastyIgniter](#setting-up-tastyigniter) step. diff --git a/upgrade-guide.md b/upgrade-guide.md index d14418b..3c90d85 100644 --- a/upgrade-guide.md +++ b/upgrade-guide.md @@ -139,3 +139,5 @@ This eliminates the need to create these view files for your custom controller a Sending registered mail templates now uses Laravel's Mailable classes instead of custom logic. This provides a more standardized and maintainable approach to sending emails. +#### Notification system +The notification system has been refactored to use Laravel's notification system. This provides a more standardized and maintainable approach to sending notifications. From abc7590db36efc1e81b0f0bbfdc56cd6f3d06353 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Wed, 22 May 2024 10:49:19 +0100 Subject: [PATCH 09/14] Update docs --- advanced/localization.md | 12 +- advanced/mail.md | 4 +- customize/components.md | 235 +++++++++++++++++++++++++-------------- customize/themes.md | 4 +- extend/extensions.md | 2 +- 5 files changed, 163 insertions(+), 94 deletions(-) diff --git a/advanced/localization.md b/advanced/localization.md index 1b5587a..540a528 100644 --- a/advanced/localization.md +++ b/advanced/localization.md @@ -137,7 +137,7 @@ If you want to display the integer value passed to the `trans_choice` function, ## Overriding language strings -You can customize all application language strings from the **System > Languages > Edit > Translations** admin page. +You can customize all application language strings from the _Manage > Settings > Languages > Edit > Translations_ admin page. Some TastyIgniter extensions, themes and Laravel packages come with their own language files. If you need to customize these strings without modifying the package's core files, you can override them by placing files in the `lang/vendor/{package}/{locale}` directory. @@ -163,13 +163,13 @@ return [ ## Making your site multilingual -In this section, we'll guide you through the steps required to make your TastyIgniter site multilingual. There are two main ways to install additional languages: directly from the **System > Languages** page in the admin interface, or manually downloading a language pack from the TastyIgniter translations Crowdin project page. +In this section, we'll guide you through the steps required to make your TastyIgniter site multilingual. There are two main ways to install additional languages: directly from the _Manage > Settings > Languages_ page in the admin interface, or manually downloading a language pack from the TastyIgniter translations Crowdin project page. ### Installing a language pack -TastyIgniter comes with a default language pack for the English language. You can install additional language packs from the **System > Languages** page of the admin interface. +TastyIgniter comes with a default language pack for the English language. You can install additional language packs from the _Manage > Settings > Languages_ page of the admin interface. -- Navigate to the **System > Languages** page in the admin interface. +- Navigate to the _Manage > Settings > Languages_ page in the admin interface. - Using the searchbar at the top of the page, search for the language you wish to install. For example, let's search for **Spanish (ES)**. - Click on the language you wish to install, then click the **Add Language** button. - Once installed, you can enable the language by toggling the **Status** switch to `Enabled`. @@ -203,7 +203,7 @@ lang/ ### Configuring the default language -You may want to set the installed language pack as the default language for new users and visitors. You can do this on the **System > Languages** page of the admin interface, by clicking the **Set as Default** button next to the language you want to use as the default. +You may want to set the installed language pack as the default language for new users and visitors. You can do this on the _Manage > Settings > Languages_ page of the admin interface, by clicking the **Set as Default** button next to the language you want to use as the default. ### Enabling language detection @@ -220,6 +220,6 @@ TastyIgniter comes with built-in support for language negotiation, offering vari ## Translating third-party extensions -Language packs downloaded from the **System > Languages** page in the admin interface typically include translations for all TastyIgniter recommended extensions. However, it's important to note that they may be missing translations for other extensions you've installed. +Language packs downloaded from the _Manage > Settings > Languages_ page in the admin interface typically include translations for all TastyIgniter recommended extensions. However, it's important to note that they may be missing translations for other extensions you've installed. Developers of TastyIgniter extensions are responsible for providing and maintaining translations for their extensions. Before installing a third-party extension, ensure that it includes translations for each language pack you have installed. If you find that an extension doesn't support a language you need, please contact the developer directly to arrange for the necessary translations to be added. \ No newline at end of file diff --git a/advanced/mail.md b/advanced/mail.md index 5c5e423..b291d3d 100644 --- a/advanced/mail.md +++ b/advanced/mail.md @@ -32,11 +32,11 @@ composer require aws/aws-sdk-php ## Configuration -Next, you can configure your mail settings from the _System > Settings > Mail_ admin settings page or through the mail configuration file located at `config/mail.php`. In this file, you may configure the default mail driver, mail sending options, and mail "from" address. Next, verify that your `config/services.php` configuration file contains the required credentials for your mail service. +Next, you can configure your mail settings from the _Manage > Settings > Mail_ admin settings page or through the mail configuration file located at `config/mail.php`. In this file, you may configure the default mail driver, mail sending options, and mail "from" address. Next, verify that your `config/services.php` configuration file contains the required credentials for your mail service. ## Writing mail -In TastyIgniter, you can send mail messages using either mail templates or mail views. Mail templates can be managed through the **Design > Mail templates** admin page. On the other hand, mail views supplied by the application or extension are stored in the `resources/views` directory within the extension's directory. +In TastyIgniter, you can send mail messages using either mail templates or mail views. Mail templates can be managed through the _Design > Mail templates_ admin page. On the other hand, mail views supplied by the application or extension are stored in the `resources/views` directory within the extension's directory. Optionally, you can [register mail views in the Extension class](../advanced/mail#registering-mail-templates-layouts--partials) with the `registerMailTemplates` method. This enables automatic generation of mail templates for easy customization via the admin interface. diff --git a/customize/components.md b/customize/components.md index c930c82..6353615 100644 --- a/customize/components.md +++ b/customize/components.md @@ -6,11 +6,11 @@ sortOrder: 140 ## Introduction -Components implements content and features that extend your TastyIgniter website. They can be added, removed, and rearranged from **Design > Themes > Editor** in the Administration Panel. +Components implements content and features that extend your TastyIgniter website. They can be added, removed, and rearranged from _Design > Themes > Editor_ in the admin area. -Other than displaying HTML markup on a page, components can implement the handling of [AJAX requests](../advanced/ajax-request). +Other than displaying HTML markup on a page, components can handle [AJAX requests](../advanced/ajax-request). -In this section, you'll learn the basics of building, registering and rendering both [Igniter](../customize/components#theme-component) and [Livewire](#livewire-component) components within a TastyIgniter application. Starting with version 4, Livewire components are not fully supported. You can register these using the `registerComponents` method and attach them into your site via the Admin Interface, just like the Theme components. +In this section, you'll learn the basics of building, registering and rendering both [Igniter](../customize/components#theme-component) and [Livewire](#livewire-component) components within a TastyIgniter application. Starting with version 4, you can use Livewire components within your theme layouts or pages. You can register both Igniter and Livewire components using the `registerComponents` method and attach them into your pages or layouts via the Admin Interface. ## Livewire Component @@ -35,27 +35,40 @@ vendor/ To begin, you can either use your preferred file manager to create files and directory for the **HelloBlock** component. -The component class file should extend the `\Livewire\Component` base class, implement `\Igniter\System\Contracts\SupportsLivewireComponent` interface and its methods, and define the properties of the component. The following is an example defines the `HelloBlock` component: +The component class file should extend the `\Livewire\Component` base class, add `\Igniter\Main\Traits\ConfigurableComponent` trait and define method `componentMeta`. The following is an example defines the `acme.hello-world::hello-block` component: ```php namespace Acme\HelloWorld\Livewire; -class HelloBlock extends \Livewire\Component implements \Igniter\System\Contracts\SupportsLivewireComponent +class HelloBlock extends \Livewire\Component { + use \Igniter\Main\Traits\ConfigurableComponent; + public int $maxItems = 5; - - public function alerts(): array + + public function componentMeta(): array { - return ['Success Alert', 'Warning Alert', 'Danger Alert']; + return [ + 'code' => 'acme.hello-world::hello-block', + 'name' => 'Name of the hello block component', + 'description' => 'Description of the hello block component', + ]; } public function render() { - return view('igniter.helloworld::livewire.default'); + return view('acme.helloworld::livewire.hello-block'); + } + + public function alerts(): array + { + return ['Success Alert', 'Warning Alert', 'Danger Alert']; } } ``` +The `componentMeta` method should return an array with the component code, name, and description. The `code` key is used to reference the component within blade views. The `name` and `description` keys are used to describe the component in the Admin Interface. This method is required for the component to be registered and available in the admin area. + The component properties and methods will automatically be made available to the component's view. For example, you will be able to access its `alerts` method and `$maxItems` property from the `resources/views/livewire/hello-block.blade.php` blade view. For example: ```blade @@ -67,40 +80,48 @@ The component properties and methods will automatically be made available to the ### Component registration -Components must be registered by overriding the `registerComponents` method within the [Extension registration class](../extend/extensions#extension-class). This lets the app know about the component and so it can be attached through the Admin Interface. To register the `HelloBlock` component with the default alias name **hello-block**, you may override the `registerComponents` method: +After defining the component with the `componentMeta` method implemented, you can register the component by overriding the `registerComponents` method within the [Extension registration class](../extend/extensions#extension-class). This lets the app know about the component and so it can be attached and properties managed through the Admin Interface. To register the `acme.hello-world::hello-block` component, you may override the `registerComponents` method of the extension class: ```php public function registerComponents(): array { return [ - \Acme\HelloWorld\Livewire\HelloBlock::class => [ - 'code' => 'hello-block', - 'name' => 'Name of the hello block component', - 'description' => 'Description of the hello block component', - ], + \Acme\HelloWorld\Livewire\HelloBlock::class, ]; } ``` ### Component properties -Components can be configured using properties defined for each component using class properties. Let's define a **maxItems** property to limit the number of alerts allowed - -If you want to manage your component's properties through the Admin Interface, you can use `#[DefineProperty]` attribute. +Components can be configured using class properties. Let's define a **maxItems** property to limit the number of alerts allowed. ```php namespace Acme\HelloWorld\Livewire; -use Igniter\System\Attributes\DefineProperty; - -class HelloBlock extends \Livewire\Component implements \Igniter\System\Contracts\SupportsLivewireComponent +class HelloBlock extends \Livewire\Component { - #[DefineProperty(label: 'Max items', type: 'number', default: 5)] + use \Igniter\Main\Traits\ConfigurableComponent; + public int $maxItems = 5; // ... } ``` + +To manage your component's properties through the admin area, you must implement the `defineProperties` method. The method should return an array with the property keys as indexes and the property configuration as values. The property keys must match the class property names. + +```php +public function defineProperties(): array +{ + return [ + 'maxItems' => [ + 'label' => 'Max items', + 'type' => 'number', + ] + ]; +} +``` + | Key | Description | |-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **label** | required, the property label, it is used by the component Selector in the Admin Interface. | @@ -113,47 +134,42 @@ class HelloBlock extends \Livewire\Component implements \Igniter\System\Contract The **options** property key can be static or dynamic. Using the `maxItems` property, let's define static options: ```php -namespace Acme\HelloWorld\Livewire; - -class HelloBlock extends \Livewire\Component implements \Igniter\System\Contracts\SupportsLivewireComponent +public function defineProperties(): array { - #[DefineProperty(label: 'Max items', type: 'select', options: [ - 20 => '20 Per page', - 50 => '50 Per page' - ])] - public int $maxItems = 20; - - // ... + return [ + 'maxItems' => [ + 'label' => 'Max items', + 'type' => 'select', + 'options' => [ + 20 => '20 Per page', + 50 => '50 Per page' + ] + ] + ]; } ``` -Dynamically, the options can be fetched by omitting the `options` key from the property definition and defining a method that returns the list of options. The method name should be the studly cased name of the property. For example, `getPropertyOptions` where **Property** is the name of the property. In this example, we'll define a method for the `maxItems` property. +Dynamically, the options can be fetched by omitting the `options` key from the property definition and defining a static method that returns the list of options. The method name should be the studly cased name of the property. For example, `getPropertyOptions` where **Property** is the name of the property. In this example, we'll define a method for the `maxItems` property. ```php -namespace Acme\HelloWorld\Livewire; - -class HelloBlock extends \Livewire\Component implements \Igniter\System\Contracts\SupportsLivewireComponent +public static function getMaxItemsOptions(): array { - #[DefineProperty(label: 'Max items', type: 'select')] - public int $maxItems = 20; - - public function getMaxItemsOptions(): array - { - return [ - 20 => '20 Per page', - 50 => '50 Per page' - ]; - } + return [ + 20 => '20 Per page', + 50 => '50 Per page' + ]; } ``` +#### Accessing component properties + Reading the property value from within the **component class**: ```php $maxItems = $this->maxItems; ``` -Accessing the property value from a **component partial**: +Accessing the property value from a **component blade view**: ```php {{ $maxItems }} @@ -174,7 +190,7 @@ public function onAddItem() } ``` -The action can be triggered from the blade view as follows: +The action can be triggered from the component's blade view as follows: ```blade @@ -209,7 +225,27 @@ Use the admin interface to display components on pages and layouts. You can also The **acme.hello-world** prefix in the above example presents the code of the extension that registers the component. -You can pass variables to components by defining them as attributes on the component tag. For example: +#### Passing data into components + +To pass data to a Livewire component rendered on a page or layout, you can define the data within the front-matter section of the page or layout template file. Here is an example passing the `maxItems` property to the `acme.helloworld::hello-block` component within a page: + +```blade +--- +title: My first page +permalink: "/page" + +'[acme.helloworld::hello-block]': + maxItems: 20 +--- + +

Page content

+ + +``` + +> Keep the indentation consistent when defining component properties in the front-matter section. + +You can pass data to components by defining them as attributes on the component tag. For example: ```blade @@ -233,6 +269,32 @@ You can access variables within the component like any other markup variable: For more information, reference the [Rendering components section of the Livewire documentation](https://livewire.laravel.com/docs/components#rendering-components). +#### Rendering multiple instances of the same component + +To render multiple instances of the same component on a page or layout, you can assign each instance a unique alias. For example: + +```blade + + +``` + +The `:alias` property behaves different from [Livewire's wire:key attribute](https://livewire.laravel.com/docs/components#adding-wirekey-to-foreach-loops) and should not be used as a substitute. + +You can pass data to each instance of the component by defining the data within the front-matter section of the page or layout template file. For example: + +```yaml +--- +title: My first page +permalink: "/page" + +'[acme.helloworld::hello-block]': + maxItems: 20 + +'[acme.helloworld::hello-block unique-key]': + maxItems: 5 +--- +``` + ### Inject page assets Use the `Assets::addCss` and `Assets::addJs` methods to add assets to the pages the components are attached to: @@ -328,10 +390,10 @@ public function defineProperties(): array { return [ 'maxItems' => [ - 'title' => 'Max items', - 'description' => 'The most number of alert items allowed', - 'default' => 10, - 'type' => 'text', + 'title' => 'Max items', + 'description' => 'The most number of alert items allowed', + 'default' => 10, + 'type' => 'text', ] ]; } @@ -357,7 +419,7 @@ public function defineProperties(): array return [ 'maxItems' => [ ... - 'type' => 'select', + 'type' => 'select', 'options' => [ '20' => '20 Per page', '50' => '50 Per page' @@ -375,12 +437,12 @@ public function defineProperties(): array return [ 'maxItems' => [ ... - 'type' => 'select', + 'type' => 'select', ] ]; } -public function getMaxItemsOptions(): array +public static function getMaxItemsOptions(): array { return [ '20' => '20 Per page', @@ -389,6 +451,8 @@ public function getMaxItemsOptions(): array } ``` +#### Accessing component properties + Reading the property value from within the **component class**: ```php @@ -421,6 +485,23 @@ The following methods are supported in the component class: | **onRender()** | override to handle specific logic before rendering the default partial of the component. | | **renderPartial()** | render a specified component partial or shared partial. | +### Component AJAX handlers + +Components class can define AJAX event handlers as methods prefixed with `on` followed by the event name. For example, to handle an AJAX request with the event name `onAddItem`, define a method in the component class as follows: + +```php +public function onAddItem() +{ + $value1 = post('value1'); + $value2 = post('value2'); + $this->page['result'] = $value1 + $value2; +} +``` + +If the alias for this component was `helloBlock` this handler can be accessed by `helloBlock::onAddItem`. + +> Please see the [Handling AJAX Requests](../advanced/ajax-request) article for more details. + ### Component partials Besides the default partial, components can also provide additional partials which can be used within other template files or in the default partial itself. @@ -490,23 +571,6 @@ These handlers are executed in the following sequence: - `onEnd` page function - `onEnd` layout function -### Defining AJAX handlers - -Components class can define AJAX event handlers as methods prefixed with `on` followed by the event name. For example, to handle an AJAX request with the event name `onAddItem`, define a method in the component class as follows: - -```php -public function onAddItem() -{ - $value1 = post('value1'); - $value2 = post('value2'); - $this->page['result'] = $value1 + $value2; -} -``` - -If the alias for this component was `helloBlock` this handler can be accessed by `helloBlock::onAddItem`. - -> Please see the [Handling AJAX Requests](../advanced/ajax-request) article for more details. - ### Rendering the component Use the admin interface to attach components to pages and layouts. You can also attach a component to a page or layout manually using a file editor by following the example below: @@ -523,15 +587,15 @@ permalink: "/page" The **helloBlock** component in the above example initializes the property **maxItems** with value **20**. -When you attach a component, a page variable that matches the component name is automatically created (`$helloBlock` in the previous example). - Render components HTML markup on a page or layout as follows: ```blade @themeComponent('helloBlock') ``` -**Component variables** +#### Component variables + +When you attach a component, a page variable that matches the component name is automatically created (`$helloBlock` in the previous example). The `@themeComponent('helloBlock')` tag accepts an array of variables as its second parameter. The specified variables will be available at the time of rendering and will explicitly override the component property values: @@ -539,24 +603,29 @@ The `@themeComponent('helloBlock')` tag accepts an array of variables as its sec @themeComponent('helloBlock', ['maxItems' => 100]) ``` -**Rendering multiple instances of the same component** +#### Rendering multiple instances of the same component If two components with the same name are assigned to a page and layout together, the page component overrides any properties of the layout component. You can render multiple instances of the same components by assigning it an *alias*: ```blade -'[helloBlock helloBlockA]': - maxItems: 1 +title: My first page +permalink: "/page" -'[helloBlock helloBlockB]': - maxItems: 5 +'[helloBlock helloBlockA]: + maxItems: 1 + +'[helloBlock helloBlockB]: + maxItems: 5 --- @themeComponent('helloBlockA') @themeComponent('helloBlockB') ``` +> Keep the indentation consistent when defining component properties in the front-matter section. + ### Inject page assets Use the `addCss` and `addJs` controller methods to add assets to the pages or layouts the components are attached to: @@ -565,9 +634,9 @@ Use the `addCss` and `addJs` controller methods to add assets to the pages or la public function onRun() { // Assets path that begins with a slash (/) is relative to the website root directory - $this->addJs('acme.helloworld::/js/block.js', 'helloworld-block); + $this->addJs('acme.helloworld::/js/block.js', 'helloworld-block'); // Paths that does not begin with a slash is relative to the component directory - $this->addJs('js/block.js', 'helloworld-block); + $this->addJs('js/block.js', 'helloworld-block'); } ``` diff --git a/customize/themes.md b/customize/themes.md index 115f3aa..e03a829 100644 --- a/customize/themes.md +++ b/customize/themes.md @@ -10,7 +10,7 @@ TastyIgniter themes are files that work together to create a TastyIgniter websit Themes typically contains all the [pages](../customize/pages), [partials](../customize/partials), [layouts](../customize/layouts), assets files and an optional theme PHP file (`theme.php`). Additionally, a theme can have a manifest file (`theme.json`) and a meta directory (`_meta`) that contains the assets manifest file (`assets.json`) and a fields file (`fields.php`) for the Theme settings feature through the Admin Interface. -Activating a theme can be done through the **Design > Themes** Admin page with the Theme Selector or by running this command: +Activating a theme can be done through the _Design > Themes_ Admin page with the Theme Selector or by running this command: ```bash php artisan igniter:util set theme --theme=your-theme @@ -261,7 +261,7 @@ To render the `includes/sidebar.blade.php` blade view from the [directory struct ## Theme settings -The theme settings feature in TastyIgniter allows you to customize the appearance and behavior of your theme directly from the admin interface. This feature is available by default for enabled TastyIgniter themes from the **Design > Themes** Admin page. +The theme settings feature in TastyIgniter allows you to customize the appearance and behavior of your theme directly from the admin interface. This feature is available by default for enabled TastyIgniter themes from the _Design > Themes_ Admin page. To enable theme settings, you need to register form fields using the `resources/meta/fields.php` file in your theme directory. This file should return an array of form fields that will be displayed in the theme settings interface. diff --git a/extend/extensions.md b/extend/extensions.md index dd583dc..bfd0962 100644 --- a/extend/extensions.md +++ b/extend/extensions.md @@ -342,7 +342,7 @@ $cartSessionTtl = Config::get('acme.helloworld::settings.cartSessionTtl', 120); #### Registering settings navigation link -An example showing how to register a system settings item which links to a settings model. Registered settings will appear on the **System > Settings** admin page. +An example showing how to register a system settings item which links to a settings model. Registered settings will appear on the _Manage > Settings_ admin page. ```php public function registerSettings(): array From b9fbb1c661b1a74f2635dc3e5069158bfdb3043c Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Wed, 22 May 2024 11:22:47 +0100 Subject: [PATCH 10/14] Fix spelling mistakes --- advanced/ajax-request.md | 36 +++++++++++++++++++++++++++++- advanced/localization.md | 28 +++++++++++------------ advanced/mail.md | 9 ++++---- advanced/scheduling-tasks.md | 4 ++-- advanced/validation.md | 9 ++++---- customize/components.md | 27 +++++++++++----------- customize/layouts.md | 5 ++--- customize/markup-guide.md | 1 - customize/media-manager.md | 31 +++++++++++++------------ customize/pages.md | 5 ++--- customize/partials.md | 8 +++---- customize/themes.md | 15 +++++++------ extend/controllers.md | 6 ++--- extend/extensions.md | 19 ++++++++-------- extend/forms.md | 11 ++++----- extend/widgets.md | 2 +- installation.md | 3 ++- resources/contribution-guide.md | 5 ++--- resources/js-coding-guidelines.md | 4 ++-- resources/php-coding-guidelines.md | 8 +++---- upgrade-guide.md | 5 ++++- 21 files changed, 137 insertions(+), 104 deletions(-) diff --git a/advanced/ajax-request.md b/advanced/ajax-request.md index 20e3395..740c2c1 100644 --- a/advanced/ajax-request.md +++ b/advanced/ajax-request.md @@ -10,7 +10,7 @@ TastyIgniter provides a simple and easy way to make AJAX requests to the server In this guide, you'll learn how to make AJAX requests using the `$.request` object, handle AJAX requests on the server, and customize AJAX requests using options. -Alternatively, you can use [Livewire's Event Listeners](https://livewire.laravel.com/docs/actions#event-listeners) to make AJAX requests. +Alternatively, you can use [Livewire's Event Listeners](https://livewire.laravel.com/docs/actions#event-listeners) to make AJAX requests. ## How AJAX requests work @@ -144,6 +144,7 @@ Some of the common options include: _(Object)_ Specifies a list of partials and page elements to be updated with the response data. The key is the partial name, and the value is the CSS selector of the target element to be updated. **JavaScript:** + ```javascript $.request('onSave', { update: { @@ -152,7 +153,9 @@ $.request('onSave', { } }); ``` + **Data attribute** + ```html ``` @@ -164,12 +167,15 @@ $.request('onSave', { _(string)_ Specifies a confirmation message that will be displayed to the user before sending the request. If the user confirms the request, the request will be sent; otherwise, the request will be canceled. **JavaScript:** + ```javascript $.request('onSave', { confirm: 'Are you sure?' }); ``` + **Data attribute:** + ```html ``` @@ -179,6 +185,7 @@ $.request('onSave', { _(Object)_ Specifies the data to be sent with the request. The data should be an object containing key-value pairs of the request data. **JavaScript:** + ```javascript $.request('onSave', { data: { @@ -187,7 +194,9 @@ $.request('onSave', { } }); ``` + **Data attribute:** + ```html ``` @@ -197,12 +206,15 @@ $.request('onSave', { _(string)_ Specifies the URL to redirect to after the request is completed. **JavaScript:** + ```javascript $.request('onSave', { redirect: '/success' }); ``` + **Data attribute:** + ```html ``` @@ -212,6 +224,7 @@ $.request('onSave', { _(Object)_ Specifies additional headers to be sent with the request. **JavaScript:** + ```javascript $.request('onSave', { headers: { @@ -225,6 +238,7 @@ $.request('onSave', { _(string)_ Specifies the CSS selector to add to the target element while the request is loading. The attribute value is optional, if not provided, the target element will be disabled. **Data attribute:** + ```html ``` @@ -234,6 +248,7 @@ _(string)_ Specifies the CSS selector to add to the target element while the req _(string)_ Specifies the CSS selector to replace on the target element while the request is loading. **Data attribute:** + ```html ``` @@ -243,6 +258,7 @@ _(string)_ Specifies the CSS selector to replace on the target element while the _(function)_ Specifies a callback function or Javascript code to be executed before updating the target element with the response. **JavaScript:** + ```javascript $.request('onSave', { beforeUpdate: function(data) { @@ -250,7 +266,9 @@ $.request('onSave', { } }); ``` + **Data attribute** + ```html ``` @@ -260,6 +278,7 @@ $.request('onSave', { _(function)_ Specifies a callback function or Javascript code to be executed after the request is successful. **JavaScript:** + ```javascript $.request('onSave', { success: function(data) { @@ -267,7 +286,9 @@ $.request('onSave', { } }); ``` + **Data attribute** + ```html ``` @@ -277,6 +298,7 @@ $.request('onSave', { _(function)_ Specifies a callback function or Javascript code to be executed when an error occurs during the request. **JavaScript:** + ```javascript $.request('onSave', { error: function(xhr, status, error) { @@ -284,7 +306,9 @@ $.request('onSave', { } }); ``` + **Data attribute** + ```html ``` @@ -294,6 +318,7 @@ $.request('onSave', { _(function)_ Specifies a callback function or Javascript code to be executed after the request is completed. **JavaScript:** + ```javascript $.request('onSave', { complete: function(xhr, status) { @@ -301,7 +326,9 @@ $.request('onSave', { } }); ``` + **Data attribute** + ```html ``` @@ -311,12 +338,15 @@ $.request('onSave', { When set to `true`, the form will be submitted using the default form submission method. **JavaScript:** + ```javascript $.request('onSave', { submit: true }); ``` + **Data attribute** + ```html ``` @@ -326,12 +356,15 @@ $.request('onSave', { _(CSS Selector)_ Specifies the form element to be submitted. Useful when the request is triggered by a button outside the form. **JavaScript:** + ```javascript $.request('onSave', { form: '#myForm' }); ``` + **Data attribute** + ```html ``` @@ -343,6 +376,7 @@ The AJAX framework triggers several events on the updated elements, the triggeri Here are some of the global AJAX events that you can listen to: {.grid-2} + - [ajaxBeforeSend](../advanced/ajax-request#ajaxbeforesend) - [ajaxBeforeUpdate](../advanced/ajax-request#ajaxbeforeupdate) - [ajaxUpdate](../advanced/ajax-request#ajaxupdate) diff --git a/advanced/localization.md b/advanced/localization.md index 540a528..0596fa8 100644 --- a/advanced/localization.md +++ b/advanced/localization.md @@ -16,8 +16,8 @@ Here is an example of how the **lang** directory might be structured: ```yaml lang/ - en/ <=== Language directory - custom.php <=== Language file + en/ <=== Language directory + custom.php <=== Language file es/ <=== Language directory custom.php <=== Language file ``` @@ -33,13 +33,13 @@ All language files return an array of keyed language strings. For example: return [ 'sample_key' => 'This is a sample language string.', - 'alert' => [ // Namespacing for alerts language strings + 'alert' => [ // Namespacing for alerts language strings 'success' => 'This is a success alert' ] ]; ``` -## Accessing language strings +## Accessing language strings You can use the `Lang` facade, `@lang` Blade directive, `__` helper function, or `lang` helper function to retrieve strings from language files. For instance, to retrieve the `sample_key` language string from the `lang/en/custom.php` language file, you can use any of these methods. @@ -103,13 +103,13 @@ return [ Pluralization can be a complex issue due to the various rules across different languages. However, Laravel provides a solution to translate strings differently based on your defined pluralization rules. You can distinguish between singular and plural forms of a string using the `|` character, like this: -``` +```php 'apples' => 'There is one apple|There are many apples', ``` You can create even more complex pluralization rules, specifying translation strings for multiple value ranges: -``` +```php 'apples' => '{0} There are none|[1,19] There are some|[20,*] There are many', ``` @@ -121,7 +121,7 @@ Once you've defined a translation string with pluralization options, you can use You can also define placeholder attributes in pluralization strings. These placeholders can be replaced by passing an array as the third argument to the `trans_choice` function: -``` +```php 'minutes_ago' => '{1} :value minute ago|[2,*] :value minutes ago', {{ trans_choice('custom.minutes_ago', 5, ['value' => 5]) }} // 5 minutes ago @@ -129,7 +129,7 @@ You can also define placeholder attributes in pluralization strings. These place If you want to display the integer value passed to the `trans_choice` function, you can use the built-in `:count` placeholder: -``` +```php 'apples' => '{0} There are none|{1} There is one|[2,*] There are :count', {{ trans_choice('custom.minutes_ago', 5, ['value' => 5]) }} // There are 5 @@ -141,7 +141,7 @@ You can customize all application language strings from the _Manage > Settings > Some TastyIgniter extensions, themes and Laravel packages come with their own language files. If you need to customize these strings without modifying the package's core files, you can override them by placing files in the `lang/vendor/{package}/{locale}` directory. -For instance, if you want to modify the language string `override_key` in `custom.php` for an extension named `acme.helloworld`, you should create a language file `lang/vendor/acme-helloworld/en/custom.php` within the root of your TastyIgniter installation. +For instance, if you want to modify the language string `override_key` in `custom.php` for an extension named `acme.helloworld`, you should create a language file `lang/vendor/acme-helloworld/en/custom.php` within the root of your TastyIgniter installation. ```yaml lang/ @@ -157,20 +157,20 @@ In this file, define only the language strings you want to change. Any strings y 'This is an overidden language string.', + 'sample_key' => 'This is an overridden language string.', ]; ``` ## Making your site multilingual -In this section, we'll guide you through the steps required to make your TastyIgniter site multilingual. There are two main ways to install additional languages: directly from the _Manage > Settings > Languages_ page in the admin interface, or manually downloading a language pack from the TastyIgniter translations Crowdin project page. +In this section, we'll guide you through the steps required to make your TastyIgniter site multilingual. There are two main ways to install additional languages: directly from the _Manage > Settings > Languages_ page in the admin interface, or manually downloading a language pack from the TastyIgniter translations Crowdin project page. ### Installing a language pack TastyIgniter comes with a default language pack for the English language. You can install additional language packs from the _Manage > Settings > Languages_ page of the admin interface. - Navigate to the _Manage > Settings > Languages_ page in the admin interface. -- Using the searchbar at the top of the page, search for the language you wish to install. For example, let's search for **Spanish (ES)**. +- Using the searchbox at the top of the page, search for the language you wish to install. For example, let's search for **Spanish (ES)**. - Click on the language you wish to install, then click the **Add Language** button. - Once installed, you can enable the language by toggling the **Status** switch to `Enabled`. @@ -184,7 +184,7 @@ php artisan igniter:language-install es Follow these steps to manually download a community translated language pack. -- Join our translations Crowdin project page. +- Join our translations Crowdin project page. - Choose the language you wish to install. For example, let's choose **Spanish (ES)**. - Download and unzip the language pack. To download, you need to click on the button at the top right of the Crowdin language page. - The extracted language pack should have a specific folder and file structure. Copy the files and folders within the `Namespaced` directories into your TastyIgniter `lang` directory, _see below_. If you don't have a `lang` directory in your application root, create a new one. @@ -222,4 +222,4 @@ TastyIgniter comes with built-in support for language negotiation, offering vari Language packs downloaded from the _Manage > Settings > Languages_ page in the admin interface typically include translations for all TastyIgniter recommended extensions. However, it's important to note that they may be missing translations for other extensions you've installed. -Developers of TastyIgniter extensions are responsible for providing and maintaining translations for their extensions. Before installing a third-party extension, ensure that it includes translations for each language pack you have installed. If you find that an extension doesn't support a language you need, please contact the developer directly to arrange for the necessary translations to be added. \ No newline at end of file +Developers of TastyIgniter extensions are responsible for providing and maintaining translations for their extensions. Before installing a third-party extension, ensure that it includes translations for each language pack you have installed. If you find that an extension doesn't support a language you need, please contact the developer directly to arrange for the necessary translations to be added. diff --git a/advanced/mail.md b/advanced/mail.md index b291d3d..2955b89 100644 --- a/advanced/mail.md +++ b/advanced/mail.md @@ -36,7 +36,7 @@ Next, you can configure your mail settings from the _Manage > Settings > Mail_ a ## Writing mail -In TastyIgniter, you can send mail messages using either mail templates or mail views. Mail templates can be managed through the _Design > Mail templates_ admin page. On the other hand, mail views supplied by the application or extension are stored in the `resources/views` directory within the extension's directory. +In TastyIgniter, you can send mail messages using either mail templates or mail views. Mail templates can be managed through the _Design > Mail templates_ admin page. On the other hand, mail views supplied by the application or extension are stored in the `resources/views` directory within the extension's directory. Optionally, you can [register mail views in the Extension class](../advanced/mail#registering-mail-templates-layouts--partials) with the `registerMailTemplates` method. This enables automatic generation of mail templates for easy customization via the admin interface. @@ -66,10 +66,10 @@ Thank you for your order. The **configuration** section sets the mail view parameters. The following configuration parameters are supported: -| Parameter | Description | +| Parameter | Description | |-------------|---------------------------------------------------------------| -| `subject` | the mail message subject, **required**. | -| `layout` | the mail layout code, **optional**. Default value is default. | +| `subject` | the mail message subject, **required**. | +| `layout` | the mail layout code, **optional**. Default value is default. | The **plain text** section is optional, while the **configuration** and **HTML markup** sections are required. @@ -278,7 +278,6 @@ $order->mailSend('vendor.extension::mail.message', 'customer'); Possible values for the recipient type are `customer`, `location` or `admin`. - ## Registering mail templates, layouts & partials To register mail templates, layouts, and partials in the Extension class, you can use the [`registerMailTemplates`](../extend/extensions#extension-class-methods), [`registerMailLayouts`](../extend/extensions#extension-class-methods), and [`registerMailPartials`](../extend/extensions#extension-class-methods) methods, respectively. These methods allow you to define the mail templates, layouts, and partials that your extension provides, making them available for customization via the admin interface: diff --git a/advanced/scheduling-tasks.md b/advanced/scheduling-tasks.md index 7aaf4f9..5b94db3 100644 --- a/advanced/scheduling-tasks.md +++ b/advanced/scheduling-tasks.md @@ -6,7 +6,7 @@ sortOrder: 330 ## Introduction -TastyIgniter's task scheduler is a powerful feature that allows you to define your command schedule within the application itself. It is built on top of the Laravel's task scheduling system, providing a fluent and expressive interface for defining your schedule. +TastyIgniter's task scheduler is a powerful feature that allows you to define your command schedule within the application itself. It is built on top of the Laravel's task scheduling system, providing a fluent and expressive interface for defining your schedule. When using the scheduler, only a single Cron entry is needed on your server. This eliminates the need for multiple Cron entries and allows you to keep your schedule of tasks in source control. For more detailed information, you can refer to the [Laravel Task Scheduling documentation](https://laravel.com/docs/scheduling). @@ -33,7 +33,7 @@ public function registerSchedule($schedule) In this example, a closure is scheduled to run at midnight every day. Inside the closure, you can define the logic for your task, such as executing a database query to clear a table. -In addition to scheduling closure calls, you may also schedule [console commands](https://laravel.com/docs/artisan), [queued jobs](https://laravel.com/docs/queues) and operating system commands. For example, to schedule a console command, you can use the `command` method: +In addition to scheduling closure calls, you may also schedule [console commands](https://laravel.com/docs/artisan), [queued jobs](https://laravel.com/docs/queues) and operating system commands. For example, to schedule a console command, you can use the `command` method: ```php $schedule->command('cache:clear')->daily(); diff --git a/advanced/validation.md b/advanced/validation.md index 898ebf8..74313d9 100644 --- a/advanced/validation.md +++ b/advanced/validation.md @@ -6,7 +6,7 @@ sortOrder: 370 ## Introduction -Validation is an essential part of TastyIgniter. It ensures that the data entered by users is accurate and meets the required criteria. +Validation is an essential part of TastyIgniter. It ensures that the data entered by users is accurate and meets the required criteria. ## Defining validation rules @@ -113,7 +113,7 @@ $failed = $validator->failed(); You can also handle validation errors by throwing Laravel's `\Illuminate\Validation\ValidationException`. This exception automatically returns the appropriate HTTP response based on the type of request. -For a traditional HTTP request, it triggers a redirect response to the previous URL, along with the validation errors. If the request is an AJAX request, it instead returns a JSON response that includes the validation errors. +For a traditional HTTP request, it triggers a redirect response to the previous URL, along with the validation errors. If the request is an AJAX request, it instead returns a JSON response that includes the validation errors. ```php $validator = Validator::make($data, $rules); @@ -124,7 +124,7 @@ if ($validator->fails()) { ``` As a shorter way to validate the form similar to the example above, you can use the `validate` method directly. - + ```php $data = Validator::validate($data, $rules); ``` @@ -185,7 +185,7 @@ class RecordRequest extends \Igniter\System\Classes\FormRequest ]; } } -``` +``` ### Applying the form request @@ -279,4 +279,3 @@ public function attributes(): array ]; } ``` - diff --git a/customize/components.md b/customize/components.md index 6353615..f899933 100644 --- a/customize/components.md +++ b/customize/components.md @@ -94,7 +94,7 @@ public function registerComponents(): array ### Component properties Components can be configured using class properties. Let's define a **maxItems** property to limit the number of alerts allowed. - + ```php namespace Acme\HelloWorld\Livewire; @@ -125,7 +125,7 @@ public function defineProperties(): array | Key | Description | |-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **label** | required, the property label, it is used by the component Selector in the Admin Interface. | -| **type** | optional, specifies the property type. The type defines the form field type. Currently supported types are **
text**, **number**, **checkbox**, **radio**, **select** and **selectlist**. Default value: **text**. | +| **type** | optional, specifies the property type. The type defines the form field type. Currently supported types are **text**, **number**, **checkbox**, **radio**, **select** and **selectlist**. Default value: **text**. | | **default** | optional, the default property value. | | **comment** | optional, the property description, it is used by the component Selector in the Admin Interface. | | **placeholder** | optional placeholder for text and select properties. | @@ -213,7 +213,7 @@ Livewire includes a number of lifecycle hooks that allow you to run code at spec | **rendered** | Called after render() is called | | **dehydrate** | Called at the end of every component request | -For more information, reference the [Livewire Component Livecycle Hooks documentation](https://livewire.laravel.com/docs/lifecycle-hooks). +For more information, reference the [Livewire Component Lifecycle Hooks documentation](https://livewire.laravel.com/docs/lifecycle-hooks). ### Rendering the component @@ -342,7 +342,7 @@ namespace Acme\HelloWorld\Components; class HelloBlock extends \Igniter\System\Classes\BaseComponent { - public function defineProperties(): array + public function defineProperties(): array { return []; } @@ -404,13 +404,12 @@ The method should return an array with the property keys as indexes and the prop | Key | Description | |-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **label** | required, the property label, it is used by the component Selector in the Admin Interface. | -| **type** | optional, specifies the property type. The type defines the form field type. Currently supported types are **
text**, **number**, **checkbox**, **radio**, **select** and **selectlist**. Default value: **text**. | +| **type** | optional, specifies the property type. The type defines the form field type. Currently supported types are **text**, **number**, **checkbox**, **radio**, **select** and **selectlist**. Default value: **text**. | | **default** | optional, the default property value. | | **comment** | optional, the property description, it is used by the component Selector in the Admin Interface. | | **placeholder** | optional placeholder for text and select properties. | | **options** | optional array of options for checkbox, radio, select, selectlist properties. | - The **options** property key can be static or dynamic. Using the `maxItems` property, let's define static options: ```php @@ -504,7 +503,7 @@ If the alias for this component was `helloBlock` this handler can be accessed by ### Component partials -Besides the default partial, components can also provide additional partials which can be used within other template files or in the default partial itself. +Besides the default partial, components can also provide additional partials which can be used within other template files or in the default partial itself. Components can share partial files by placing them in the **resources/views/_partials** subdirectory of the extension directory. @@ -514,11 +513,11 @@ vendor/ helloworld/ resources/ views/ - _components/ <=== Components directory - helloBlock/ <=== Component partials directory - default.blade.php <=== Component default partial file - _partials/ <=== Component shared partials directory - shared.blade.php <=== Component shared partial file + _components/ <=== Components directory + helloBlock/ <=== Component partials directory + default.blade.php <=== Component default partial file + _partials/ <=== Component shared partials directory + shared.blade.php <=== Component shared partial file ``` Blade's `@themePartial` directive allows you to include the **helloBlock** component partial from within another component partial: @@ -595,7 +594,7 @@ Render components HTML markup on a page or layout as follows: #### Component variables -When you attach a component, a page variable that matches the component name is automatically created (`$helloBlock` in the previous example). +When you attach a component, a page variable that matches the component name is automatically created (`$helloBlock` in the previous example). The `@themeComponent('helloBlock')` tag accepts an array of variables as its second parameter. The specified variables will be available at the time of rendering and will explicitly override the component property values: @@ -607,7 +606,7 @@ The `@themeComponent('helloBlock')` tag accepts an array of variables as its sec If two components with the same name are assigned to a page and layout together, the page component overrides any properties of the layout component. -You can render multiple instances of the same components by assigning it an *alias*: +You can render multiple instances of the same components by assigning it an _alias_: ```blade title: My first page diff --git a/customize/layouts.md b/customize/layouts.md index 49c69ae..453e945 100644 --- a/customize/layouts.md +++ b/customize/layouts.md @@ -15,8 +15,8 @@ acme/ <=== Theme vendor directory purple/ <=== Theme directory resources/ views/ - _layouts/ <=== Layouts subdirectory - default.blade.php <=== Layout template file + _layouts/ <=== Layouts subdirectory + default.blade.php <=== Layout template file ``` The convention is to have a basic layout called `default.blade.php` and be used by other pages as required. Within the layout file, you should use the `@themePage` tag to display the content of the page. @@ -224,4 +224,3 @@ In order to output the injected assets on pages and layouts use the `@themeStyle ``` > The page output in the above example will also include all assets files registered within the `resources/meta/assets.json` manifest file. - diff --git a/customize/markup-guide.md b/customize/markup-guide.md index cdb06a7..ad23fe6 100644 --- a/customize/markup-guide.md +++ b/customize/markup-guide.md @@ -113,7 +113,6 @@ The `@themeContent` directive renders the contents of a static template file loc The directive has a single required parameter - the name of the content template file without the `.htm` extension. You can specify the name of the subdirectory if you refer a content from a subdirectory `@themeContent('directory.content-name')`. - ```blade @themeContent('content-name') ``` diff --git a/customize/media-manager.md b/customize/media-manager.md index fd809d5..4057c77 100644 --- a/customize/media-manager.md +++ b/customize/media-manager.md @@ -40,21 +40,21 @@ The Media Manager in TastyIgniter can be configured according to your preference The `config/igniter-system.php` configuration file contains several options that allow you to customize the behavior of the Media Manager: - `media`: This section contains the configuration options for the media uploaded files. - - `disk`: This option specifies the storage disk that the Media Manager should use for uploads. By default, it uses the `public` disk. - - `folder`: This option specifies the folder within the storage disk where the media files should be stored. By default, it is set to `media/uploads/`. - - `path`: This option specifies the path to prepend to the file name when generating the file URL. By default, it is set to `media/uploads/`. - - `max_upload_size`: This option specifies the maximum size (in kilobytes) of the files that can be uploaded through the Media Manager. By default, it is set to 1500 (1.5 MB). - - `enable_uploads`: This option allows you to enable or disable file uploads. By default, it is set to `true`. - - `enable_new_folder`: This option allows you to enable or disable the creation of new folders through the Media Manager. By default, it is set to `true`. - - `enable_rename`: This option allows you to enable or disable the renaming of files and folders through the Media Manager. By default, it is set to `true`. - - `enable_move`: This option allows you to enable or disable the moving of files and folders through the Media Manager. By default, it is set to `true`. - - `enable_copy`: This option allows you to enable or disable the copying of files and folders through the Media Manager. By default, it is set to `true`. - - `enable_delete`: This option allows you to enable or disable the deletion of files and folders through the Media Manager. By default, it is set to `true`. + - `disk`: This option specifies the storage disk that the Media Manager should use for uploads. By default, it uses the `public` disk. + - `folder`: This option specifies the folder within the storage disk where the media files should be stored. By default, it is set to `media/uploads/`. + - `path`: This option specifies the path to prepend to the file name when generating the file URL. By default, it is set to `media/uploads/`. + - `max_upload_size`: This option specifies the maximum size (in kilobytes) of the files that can be uploaded through the Media Manager. By default, it is set to 1500 (1.5 MB). + - `enable_uploads`: This option allows you to enable or disable file uploads. By default, it is set to `true`. + - `enable_new_folder`: This option allows you to enable or disable the creation of new folders through the Media Manager. By default, it is set to `true`. + - `enable_rename`: This option allows you to enable or disable the renaming of files and folders through the Media Manager. By default, it is set to `true`. + - `enable_move`: This option allows you to enable or disable the moving of files and folders through the Media Manager. By default, it is set to `true`. + - `enable_copy`: This option allows you to enable or disable the copying of files and folders through the Media Manager. By default, it is set to `true`. + - `enable_delete`: This option allows you to enable or disable the deletion of files and folders through the Media Manager. By default, it is set to `true`. - `attachment`: This section contains the configuration options for the attachment files. - - `disk`: This option specifies the storage disk that the Media Manager should use for attachments. By default, it uses the `public` disk. - - `folder`: This option specifies the folder within the storage disk where the attachment files should be stored. By default, it is set to `media/attachments/`. - - `path`: This option specifies the path to prepend to the file name when generating the file URL. By default, it is set to `media/attachments/`. + - `disk`: This option specifies the storage disk that the Media Manager should use for attachments. By default, it uses the `public` disk. + - `folder`: This option specifies the folder within the storage disk where the attachment files should be stored. By default, it is set to `media/attachments/`. + - `path`: This option specifies the path to prepend to the file name when generating the file URL. By default, it is set to `media/attachments/`. These options provide a high level of control over how media files are handled in your application. You can customize these options according to your application's requirements. @@ -64,7 +64,7 @@ To publish the config file to `config/igniter-system.php` run: php artisan vendor:publish --tag="igniter-config" ``` -For more information on configuring external storage, check out Laravel's filesystem docs. +For more information on configuring external storage, check out Laravel's filesystem docs. ## Defining media fields @@ -124,7 +124,7 @@ class MenuItem extends Model ## Displaying media on your site -To display a media file in a template, you can use the `media` method of the media model. +To display a media file in a template, you can use the `media` method of the media model. For a single media field, you can display the image using the following code: @@ -162,4 +162,3 @@ The `getThumb` method accepts an optional parameter to specify the size of the t 'height' => 200, ]) }}" alt="Gallery Image"> ``` - diff --git a/customize/pages.md b/customize/pages.md index 6a4a107..fe1c14e 100644 --- a/customize/pages.md +++ b/customize/pages.md @@ -15,8 +15,8 @@ acme/ <=== Theme vendor directory purple/ <=== Theme directory resources/ views/ - _pages/ <=== Pages subdirectory - home.blade.php <=== Page template file + _pages/ <=== Pages subdirectory + home.blade.php <=== Page template file ``` A page file consists of three sections: front matter, PHP code (optional), and HTML markup. Here's an example of a page file: @@ -266,4 +266,3 @@ In order to output the injected assets on pages or layouts use the `@themeStyles ``` > The page output in the above example will also include all assets files registered within the `resources/meta/assets.json` manifest file. - diff --git a/customize/partials.md b/customize/partials.md index 546f386..b6a5861 100644 --- a/customize/partials.md +++ b/customize/partials.md @@ -47,13 +47,13 @@ You may pass variables to partials by defining them in the `@include` directive
``` -You can access variables within the partial like any other markup variable: +You can access variables within the partial like any other markup variable: ```blade
    - @foreach($pages as $page) -
  • {{ $page->name }}
  • - @endforeach + @foreach($pages as $page) +
  • {{ $page->name }}
  • + @endforeach
``` diff --git a/customize/themes.md b/customize/themes.md index e03a829..ebdce31 100644 --- a/customize/themes.md +++ b/customize/themes.md @@ -8,7 +8,7 @@ sortOrder: 100 TastyIgniter themes are files that work together to create a TastyIgniter website. Each theme can be different, offering site owners many choices to change their website look instantly. Themes, just like extensions are built on the foundation of Laravel packages. -Themes typically contains all the [pages](../customize/pages), [partials](../customize/partials), [layouts](../customize/layouts), assets files and an optional theme PHP file (`theme.php`). Additionally, a theme can have a manifest file (`theme.json`) and a meta directory (`_meta`) that contains the assets manifest file (`assets.json`) and a fields file (`fields.php`) for the Theme settings feature through the Admin Interface. +Themes typically contains all the [pages](../customize/pages), [partials](../customize/partials), [layouts](../customize/layouts), assets files and an optional theme PHP file (`theme.php`). Additionally, a theme can have a manifest file (`theme.json`) and a meta directory (`_meta`) that contains the assets manifest file (`assets.json`) and a fields file (`fields.php`) for the Theme settings feature through the Admin Interface. Activating a theme can be done through the _Design > Themes_ Admin page with the Theme Selector or by running this command: @@ -47,9 +47,9 @@ acme/ <=== Theme vendor directory theme.php <=== Theme PHP file - Loaded on every theme page request just before running the page code. ``` -TastyIgniter supports a single level subdirectory for layouts, pages and partials files (any structure can be used in the `assets` directory), making it easier to organise large websites. +TastyIgniter supports a single level subdirectory for layouts, pages and partials files (any structure can be used in the `assets` directory), making it easier to organise large websites. -A theme can contain any number of other subdirectories as well. +A theme can contain any number of other subdirectories as well. **Screenshot** @@ -144,6 +144,7 @@ A `resources/meta/assets.json` file looks like this: ] } ``` + > The `$` symbol is a placeholder for the `public` path. Theme assets are published to the `public` directory of the TastyIgniter installation when you install or update the theme or run the `php artisan igniter:theme-vendor-publish --theme=your-theme` command. JavaScript code should be placed in external files whenever possible. Use [`@scripts`](../customize/markup-guide#themescripts) to load your scripts and [`@styles`](../customize/markup-guide#themestyles) to load your styles. @@ -263,7 +264,7 @@ To render the `includes/sidebar.blade.php` blade view from the [directory struct The theme settings feature in TastyIgniter allows you to customize the appearance and behavior of your theme directly from the admin interface. This feature is available by default for enabled TastyIgniter themes from the _Design > Themes_ Admin page. -To enable theme settings, you need to register form fields using the `resources/meta/fields.php` file in your theme directory. This file should return an array of form fields that will be displayed in the theme settings interface. +To enable theme settings, you need to register form fields using the `resources/meta/fields.php` file in your theme directory. This file should return an array of form fields that will be displayed in the theme settings interface. Here's an example of a `resources/meta/fields.php` file: @@ -275,7 +276,7 @@ return [ 'font_family' => [ 'label' => 'Font Family', 'type' => 'text', - 'default' => '"Titillium Web",Arial,sans-serif', + 'default' => '"Inter",Arial,sans-serif', 'comment' => 'The font family to use for the main body text.', 'rules' => 'required|string', ], @@ -284,7 +285,7 @@ return [ ]; ``` -In this example, a text field is defined for customizing the font family. The field has a label, a default value, a comment, and a validation rule. +In this example, a text field is defined for customizing the font family. The field has a label, a default value, a comment, and a validation rule. Once the fields are defined, you can access the values inside any of your theme templates using $this->theme->field_name. For example: @@ -299,4 +300,4 @@ In this example, the font family defined in the theme settings interface is appl - All template files (layouts, pages and partials) should use `.blade.php`. - Use relative paths in your CSS files, for example: `url(../img/bg.png);` - Use lowercase filenames -- Use hyphens `-` **NOT** underscores `_` to separate words in filenames \ No newline at end of file +- Use hyphens `-` **NOT** underscores `_` to separate words in filenames diff --git a/extend/controllers.md b/extend/controllers.md index d83c597..112ebdb 100644 --- a/extend/controllers.md +++ b/extend/controllers.md @@ -152,7 +152,7 @@ public function __construct() ## Controller action classes -Action classes are behaviours that can be attached to controllers to extend their functionality. Action classes are useful for sharing common controller logic across multiple controllers. To attach an action class to a controller, you can set the `$implement` property on the controller class. +Action classes are behaviours that can be attached to controllers to extend their functionality. Action classes are useful for sharing common controller logic across multiple controllers. To attach an action class to a controller, you can set the `$implement` property on the controller class. Here is an example of attaching an action class to a controller: @@ -215,7 +215,7 @@ The AJAX handler can be triggered with the data-request attribute in the view: ## Restricting access -Access to controller actions can be restricted using the `$requiredPermissions` property. This property holds an array of permission keys that determine the access level needed. If an administrator has any of the permissions listed, they are granted access to the controller pages. +Access to controller actions can be restricted using the `$requiredPermissions` property. This property holds an array of permission keys that determine the access level needed. If an administrator has any of the permissions listed, they are granted access to the controller pages. Here is an example of how to restrict access to a controller using permissions: @@ -230,4 +230,4 @@ class MyController extends \Igniter\Admin\Classes\AdminController } ``` -See more about [restricting access to admin pages](../extend/permissions#restricting-access-to-admin-pages) and [restricting access to admin controller actions](../extend/permissions#restricting-access-to-admin-controller-actions). \ No newline at end of file +See more about [restricting access to admin pages](../extend/permissions#restricting-access-to-admin-pages) and [restricting access to admin controller actions](../extend/permissions#restricting-access-to-admin-controller-actions). diff --git a/extend/extensions.md b/extend/extensions.md index bfd0962..e0c46ab 100644 --- a/extend/extensions.md +++ b/extend/extensions.md @@ -6,7 +6,7 @@ sortOrder: 200 ## Introduction -Extensions are the foundation for adding new features to TastyIgniter by extending it. The core of TastyIgniter is designed to be lean and lightweight, to maximize flexibility and minimize code bloat. With extensions, you can add specific set of features or services, such as: +Extensions are the foundation for adding new features to TastyIgniter by extending it. The core of TastyIgniter is designed to be lean and lightweight, to maximize flexibility and minimize code bloat. With extensions, you can add specific set of features or services, such as: - Define components, mail templates and staff permissions - Add, remove or replace navigation items @@ -18,7 +18,7 @@ TastyIgniter extensions are built on the foundation of Laravel packages. They le ### Directory structure -Below is an example of an extension directory structure. +Below is an example of an extension directory structure. ```yaml acme/ <=== Author name (namespace) @@ -40,7 +40,7 @@ code when publishing your extensions on the [TastyIgniter marketplace](https://t Both namespace and extension name must follow these important rules: -- Only letters must be provided. +- Only letters must be provided. - Folder names must be lowercase, as shown in the directory structure example. - Should not contain spaces. - Must be unique. The name of your extension should not be the same with any other extension or theme. @@ -110,7 +110,7 @@ create a **README.md** file in a standardized format in your extension directory ## Extension class -An **Extension.php** file (aka *Extension class*) is an essential part of the TastyIgniter extension for providing methods for extending the TastyIgniter core. +An **Extension.php** file (aka *Extension class*) is an essential part of the TastyIgniter extension for providing methods for extending the TastyIgniter core. The extension class should extend the `\Igniter\System\Classes\BaseExtension` class, which in turn extends Laravel's `Illuminate\Foundation\Support\Providers\EventServiceProvider` class. This allows the Extension class to take advantage of the functionality provided by Laravel's service providers, such as registering services, event subscribers, model observers and listening for events. @@ -233,10 +233,10 @@ acme/ helloworld/ resources/ models/ - settings.php <=== Setting model form fields + settings.php <=== Setting model form fields src/ Models/ - Settings.php <=== Setting model class file + Settings.php <=== Setting model class file ``` By implementing the `\Igniter\System\Actions\SettingsModel` action class and extending the base `\Igniter\Flame\Database\Model` class in a model class, you can create models for storing settings in the `extension_settings` database table. @@ -322,6 +322,7 @@ return [ 'cartSessionTtl' => 120 ]; ``` + To make the configuration file available to the application, you need to register the configuration file in the extension class `register` method. ```php @@ -342,7 +343,7 @@ $cartSessionTtl = Config::get('acme.helloworld::settings.cartSessionTtl', 120); #### Registering settings navigation link -An example showing how to register a system settings item which links to a settings model. Registered settings will appear on the _Manage > Settings_ admin page. +An example showing how to register a system settings item which links to a settings model. Registered settings will appear on the *Manage > Settings* admin page. ```php public function registerSettings(): array @@ -394,7 +395,7 @@ For more information on database migrations, refer to the [Laravel documentation ### Seeders -Seeders are used to populate database tables with sample data. Just like Laravel Packages, seeders are stored in the extension's `database/seeds` directory. +Seeders are used to populate database tables with sample data. Just like Laravel Packages, seeders are stored in the extension's `database/seeds` directory. Here is an example of a `MessagesTableSeeder.php` seeder file located in `acme/helloworld/database/seeds`: @@ -419,7 +420,7 @@ To run the seeder, you can use the `php artisan db:seed --class=Acme\\HelloWorld ### Routes -If your extension includes a `routes/web.php` route file, TastyIgniter will automatically load it, adding any defined routes to the application's routing table. +If your extension includes a `routes/web.php` route file, TastyIgniter will automatically load it, adding any defined routes to the application's routing table. Extensions in TastyIgniter can define routes using the `routes/web.php` file or handle admin routes through admin controllers. diff --git a/extend/forms.md b/extend/forms.md index 42d0e67..3086ca3 100644 --- a/extend/forms.md +++ b/extend/forms.md @@ -256,7 +256,7 @@ The following native field types are available for form fields. For more advance #### Money -`money` renders an input field that takes only numbers and formats the value to two decimal places. +`money` renders an input field that takes only numbers and formats the value to two decimal places. ```php 'price' => [ @@ -459,6 +459,7 @@ The following options are available for the `select` field type: ], ], ``` + Options for checkbox lists also support secondary descriptions using the array format `key => [label, description]`. ```php @@ -547,7 +548,7 @@ Options for checkbox lists also support secondary descriptions using the array f #### Partial -`partial` renders a partial view. The `path` option should be the path to the partial view file otherwise the field name is used as the partial name. +`partial` renders a partial view. The `path` option should be the path to the partial view file otherwise the field name is used as the partial name. ```php 'partial' => [ @@ -1038,7 +1039,7 @@ The following options are available for the `preset` property: - `field`: The name of the other field that this field get its value from. - `type`: The type of preset to apply. Options are `exact`, `slug`, `url`, `camelCase`, and `file`. -- `prefixInput`: The CSS Selector of the input element to get the prefix value from. +- `prefixInput`: The CSS Selector of the input element to get the prefix value from. ### Trigger events @@ -1191,7 +1192,7 @@ public function formExtendFields(Form $widget) ``` Or, you can use the `admin.form.extendFields` event to extend the form fields from another extension. For example: - + ```php Event::listen('admin.form.extendFields', function (Form $widget, $fields) { if ($widget->getController() instanceof MyController) { @@ -1237,4 +1238,4 @@ public function filterFields($widget, &$fields, $context = null) $fields['source_file']['hidden'] = true; } } -``` \ No newline at end of file +``` diff --git a/extend/widgets.md b/extend/widgets.md index 42b09a0..332eedb 100644 --- a/extend/widgets.md +++ b/extend/widgets.md @@ -6,7 +6,7 @@ sortOrder: 220 ## Introduction -In TastyIgniter, widgets are self-contained blocks of functionality used to perform specific tasks within the Admin Interface. Widgets always have a user interface and admin controller, referred to as the widget class. The widget class is responsible for preparing data for the widget and handling AJAX requests that are initiated from the widget's user interface. +In TastyIgniter, widgets are self-contained blocks of functionality used to perform specific tasks within the Admin Interface. Widgets always have a user interface and admin controller, referred to as the widget class. The widget class is responsible for preparing data for the widget and handling AJAX requests that are initiated from the widget's user interface. ## Generic widget diff --git a/installation.md b/installation.md index 4fcb867..751e615 100644 --- a/installation.md +++ b/installation.md @@ -92,6 +92,7 @@ Once TastyIgniter is installed, you must grant the non-root user the necessary p sudo chmod -R 755 /path/to/tastyigniter sudo chown -R www-data:www-data /path/to/tastyigniter ``` + > You should never set any folder or file to permission level **777**, as this permission level allows anyone to access the content of the folder and file regardless of user or group. ### Setting up the task scheduler @@ -180,7 +181,7 @@ the [`.htaccess`](https://github.com/tastyigniter/TastyIgniter/blob/master/publi If you've created a subdirectory, you can specify the subdirectory name as well: ```html -RewriteBase /mysubdirectory/ +RewriteBase /subdirectory/ ``` **Nginx configuration** diff --git a/resources/contribution-guide.md b/resources/contribution-guide.md index 4d7a8d9..ab0bb66 100644 --- a/resources/contribution-guide.md +++ b/resources/contribution-guide.md @@ -71,7 +71,6 @@ in `composer.json` to `dev`. - Run `composer install` to install composer dependencies. - Finally, run `composer update "tastyigniter/*" --prefer-source` to clone TastyIgniter packages into the `vendor` directory for development. - ## Development workflow Follow these steps: @@ -95,7 +94,7 @@ choices. ## Reporting security issues If you wish to contact us about any security vulnerability in TastyIgniter you may find, please send an e-mail to -support@tastyigniter.com + ## Writing documentation @@ -116,4 +115,4 @@ contribute. Here's how styling perfect TastyIgniter documentation pages is done: - For your reference, see the [pages](https://github.com/tastyigniter/docs/blob/master/customize/pages.md) or [themes](https://github.com/tastyigniter/docs/blob/master/customize/themes.md) files. -> For more information on contributing, read the guide here \ No newline at end of file +> For more information on contributing, read the guide here diff --git a/resources/js-coding-guidelines.md b/resources/js-coding-guidelines.md index df110ab..e28bcfc 100644 --- a/resources/js-coding-guidelines.md +++ b/resources/js-coding-guidelines.md @@ -10,7 +10,7 @@ We try to stick to Prettier's defaults, but have a few overrides to keep our Jav The first two rules are actually configured with `.editorconfig`. We use 4 spaces as indentation. -``` +```editorconfig indent_size = 4 ``` @@ -253,4 +253,4 @@ function uploader({ ``` ___ -The above are sections taken from the [Spatie Javascript Code Guidelines](https://spatie.be/guidelines/javascript). \ No newline at end of file +The above are sections taken from the [Spatie Javascript Code Guidelines](https://spatie.be/guidelines/javascript). diff --git a/resources/php-coding-guidelines.md b/resources/php-coding-guidelines.md index 589967d..e4e1ebb 100644 --- a/resources/php-coding-guidelines.md +++ b/resources/php-coding-guidelines.md @@ -150,7 +150,7 @@ $request->session()->get('cart'); $request->input('name'); ``` -### More examples: +### More examples Consider using helpers instead of facades. They can clean up your code. @@ -532,7 +532,7 @@ if ($condition) { $this->doSomethingElse(); } -if ($conidition) +if ($condition) $this->doSomething(); ``` @@ -762,7 +762,7 @@ public function handle() Indent using four spaces. -``` +```blade Open Source @@ -770,7 +770,7 @@ Indent using four spaces. Don't add spaces after control structures. -``` +```blade @if($condition) Something @endif diff --git a/upgrade-guide.md b/upgrade-guide.md index 3c90d85..82b5bcd 100644 --- a/upgrade-guide.md +++ b/upgrade-guide.md @@ -97,7 +97,7 @@ experience for administrators. #### Mail Template Namespaces Mail template namespaces have been renamed for consistency. `admin::` is -now `igniter.admin::`, `main::` is now `igntier.main::`, and `system::` is now `igniter.system::`. +now `igniter.admin::`, `main::` is now `igniter.main::`, and `system::` is now `igniter.system::`. #### Translation String Keys @@ -132,12 +132,15 @@ increasing the length of varchar to 255 on existing columns. ### Low impact changes #### Admin Controller Actions + New base view files have been introduced for common admin controller actions such as index, edit, create, and preview. This eliminates the need to create these view files for your custom controller action. #### Mailable Integration + Sending registered mail templates now uses Laravel's Mailable classes instead of custom logic. This provides a more standardized and maintainable approach to sending emails. #### Notification system + The notification system has been refactored to use Laravel's notification system. This provides a more standardized and maintainable approach to sending notifications. From 1477cfbf84ef66cc464592a3655ad28796d5e9d9 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Sat, 25 May 2024 14:36:48 +0100 Subject: [PATCH 11/14] update docs --- extend/extensions.md | 4 ++-- installation.md | 15 +++++---------- upgrade-guide.md | 3 +-- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/extend/extensions.md b/extend/extensions.md index e0c46ab..68609c3 100644 --- a/extend/extensions.md +++ b/extend/extensions.md @@ -328,7 +328,7 @@ To make the configuration file available to the application, you need to registe ```php public function register() { - $this->mergeConfigFrom(__DIR__.'/config/settings.php', 'acme.helloworld::settings'); + $this->mergeConfigFrom(__DIR__.'/config/settings.php', 'helloworld-settings'); } ``` @@ -338,7 +338,7 @@ Use the `Config` facade to access the configuration values defined in the config use Config; // Get a value and return a default value if it doesn't exist -$cartSessionTtl = Config::get('acme.helloworld::settings.cartSessionTtl', 120); +$cartSessionTtl = Config::get('helloworld-settings.cartSessionTtl', 120); ``` #### Registering settings navigation link diff --git a/installation.md b/installation.md index 751e615..d9049ad 100644 --- a/installation.md +++ b/installation.md @@ -156,11 +156,9 @@ Although CSRF security is enabled by default, you can disable it by updating the TastyIgniter has basic configuration that should be applied to your webserver. Common webservers and their configuration can be found below. -**Apache configuration** +#### Apache configuration -TastyIgniter includes a `.htaccess` file - make sure it's been uploaded correctly. -**There are some extra system requirements if your webserver is running Apache, `mod_rewrite` should be installed and -enabled and the `AllowOverride` option should be switched on.** +TastyIgniter includes a [`.htaccess`](https://github.com/tastyigniter/TastyIgniter/blob/master/public/.htaccess) file - make sure it's been uploaded correctly. The `.htaccess` file is located in the `public` directory of your TastyIgniter installation. There are some extra system requirements if your webserver is running Apache, `mod_rewrite` should be installed and enabled and the `AllowOverride` option should be switched on. ```apache @@ -168,8 +166,7 @@ enabled and the `AllowOverride` option should be switched on.** ``` -You will need to uncomment this line in -the [`.htaccess`](https://github.com/tastyigniter/TastyIgniter/blob/master/public/.htaccess) file in some cases: +You will need to uncomment this line in the `.htaccess` file in some cases: ```html ## !IMPORTANT! You may need to uncomment the following line for some hosting environments, @@ -184,11 +181,9 @@ If you've created a subdirectory, you can specify the subdirectory name as well: RewriteBase /subdirectory/ ``` -**Nginx configuration** +#### Nginx configuration -Make sure that [`.nginx.conf`](https://github.com/tastyigniter/TastyIgniter/blob/v4/.nginx.conf) file included with -TastyIgniter has been uploaded correctly. Then, assuming you have Nginx -setup, add the following to your server's configuration block: +Make sure that the [`.nginx.conf`](https://github.com/tastyigniter/TastyIgniter/blob/master/.nginx.conf) file included with TastyIgniter has been uploaded correctly. The `.nginx.conf` file is located in the root directory of your TastyIgniter installation. Then, assuming you have Nginx setup, add the following to your server's configuration block: ```html include /path/to/tastyigniter/.nginx.conf; diff --git a/upgrade-guide.md b/upgrade-guide.md index 82b5bcd..6faa67e 100644 --- a/upgrade-guide.md +++ b/upgrade-guide.md @@ -120,8 +120,7 @@ See [Blade Directives on Markup guide](customize/markup-guide#directives) for mo #### Extension Configuration -Extension configuration files are no longer merged automatically. Developers must use Laravel's -mergeConfigFrom() method to merge configuration files from extension class `register` method. +Extension configuration files are no longer merged automatically. Developers must use Laravel's `mergeConfigFrom()` method to merge configuration files from extension class `register` method. #### Database Changes From d61258b3cc69081b9c07041a78b17d0f13535fab Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Wed, 29 May 2024 23:14:31 +0100 Subject: [PATCH 12/14] Update mail docs --- advanced/mail.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/advanced/mail.md b/advanced/mail.md index 2955b89..827ab68 100644 --- a/advanced/mail.md +++ b/advanced/mail.md @@ -200,30 +200,30 @@ To embed raw data in your emails, you can use the `embedData` method on the `$me ``` -## Sending mail +## Sending mail templates To send a mail template in TastyIgniter, you can use the `sendTemplate` method on the `Mail` facade. This method accepts the code of the mail template, an array of data to pass to the view, and a closure that receives a message instance which allows you to customize the recipients, subject, and other aspects of the mail message: ```php -use Illuminate\Support\Facades\Mail; +use Igniter\System\Helpers\MailHelper; $data = []; -Mail::sendTemplate('vendor.extension::mail.message', $data, function($message) use ($customer) { +MailHelper::sendTemplate('vendor.extension::mail.message', $data, function($message) use ($customer) { $message->to($customer->email, $customer->name); }); ``` -### Queueing mail +### Queueing mail templates To queue a mail message, you can use the `queueTemplate` method on the `Mail` facade. This method will automatically push the email onto the queue, so it will be sent in the background by a queue worker. This can help to improve the response time of your application by offloading the sending of the email to a background process: ```php -use Illuminate\Support\Facades\Mail; +use Igniter\System\Helpers\MailHelper; $data = []; -Mail::queueTemplate('vendor.extension::mail.message', $data, function($message) use ($customer) { +MailHelper::queueTemplate('vendor.extension::mail.message', $data, function($message) use ($customer) { $message->to($customer->email, $customer->name); }); ``` From d8ae30943679b6e0c01afa1aecbb2635d66f1899 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Tue, 18 Jun 2024 22:20:33 +0100 Subject: [PATCH 13/14] Update custom language paths --- advanced/localization.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/advanced/localization.md b/advanced/localization.md index 0596fa8..0aa7e91 100644 --- a/advanced/localization.md +++ b/advanced/localization.md @@ -139,16 +139,17 @@ If you want to display the integer value passed to the `trans_choice` function, You can customize all application language strings from the _Manage > Settings > Languages > Edit > Translations_ admin page. -Some TastyIgniter extensions, themes and Laravel packages come with their own language files. If you need to customize these strings without modifying the package's core files, you can override them by placing files in the `lang/vendor/{package}/{locale}` directory. +Some TastyIgniter extensions, themes and Laravel packages come with their own language files. If you need to customize these strings without modifying the package's core files, you can override them by placing files in the `lang/vendor/{author}/{package}/{locale}` directory. -For instance, if you want to modify the language string `override_key` in `custom.php` for an extension named `acme.helloworld`, you should create a language file `lang/vendor/acme-helloworld/en/custom.php` within the root of your TastyIgniter installation. +For instance, if you want to modify the language string `override_key` in `custom.php` for an extension named `acme.helloworld`, you should create a language file `lang/vendor/acme/helloworld/en/custom.php` within the root of your TastyIgniter installation. ```yaml lang/ vendor/ - acme-helloworld/ - en/ <=== Language directory - custom.php <=== Language override file + acme/ + helloworld/ + en/ <=== Language directory + custom.php <=== Language override file ``` In this file, define only the language strings you want to change. Any strings you don't override will still be loaded from the original language file. From 5e799dc595302773509a3b138d4eb5a25cc74956 Mon Sep 17 00:00:00 2001 From: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com> Date: Sun, 11 Aug 2024 11:34:27 +0100 Subject: [PATCH 14/14] update install command --- README.md | 4 ++-- advanced/localization.md | 11 +++++------ customize/components.md | 2 +- installation.md | 8 ++++---- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index bab65b9..0be19c3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # TastyIgniter Documentation -You can find the online version of the TastyIgniter documentation at https://tastyigniter.com/docs +You can find the online version of the TastyIgniter documentation at # Contribution Guidelines -If you are submitting documentation for the current stable release, submit it to the `master` branch. \ No newline at end of file +If you are submitting documentation for the current stable release, submit it to the `master` branch. diff --git a/advanced/localization.md b/advanced/localization.md index 0aa7e91..057992d 100644 --- a/advanced/localization.md +++ b/advanced/localization.md @@ -139,17 +139,16 @@ If you want to display the integer value passed to the `trans_choice` function, You can customize all application language strings from the _Manage > Settings > Languages > Edit > Translations_ admin page. -Some TastyIgniter extensions, themes and Laravel packages come with their own language files. If you need to customize these strings without modifying the package's core files, you can override them by placing files in the `lang/vendor/{author}/{package}/{locale}` directory. +Some TastyIgniter extensions, themes and Laravel packages come with their own language files. If you need to customize these strings without modifying the package's core files, you can override them by placing files in the `lang/vendor/{author}-{package}/{locale}` directory. -For instance, if you want to modify the language string `override_key` in `custom.php` for an extension named `acme.helloworld`, you should create a language file `lang/vendor/acme/helloworld/en/custom.php` within the root of your TastyIgniter installation. +For instance, if you want to modify the language string `override_key` in `custom.php` for an extension named `acme.helloworld`, you should create a language file `lang/vendor/acme-helloworld/en/custom.php` within the root of your TastyIgniter installation. ```yaml lang/ vendor/ - acme/ - helloworld/ - en/ <=== Language directory - custom.php <=== Language override file + acme-helloworld/ + en/ <=== Language directory + custom.php <=== Language override file ``` In this file, define only the language strings you want to change. Any strings you don't override will still be loaded from the original language file. diff --git a/customize/components.md b/customize/components.md index f899933..1ca95de 100644 --- a/customize/components.md +++ b/customize/components.md @@ -532,7 +532,7 @@ Partials rendered from outside the component must use their fully qualified name @themePartial('componentName::component-partial') ``` -**Overriding component partials** +#### Overriding component partials All component partials can be overridden by creating theme partials. A component defined with alias **helloBlock** can have its **default.blade.php** partial overridden by creating a theme partial called **_partials/helloBlock/default.blade.php** diff --git a/installation.md b/installation.md index d9049ad..0d9e42b 100644 --- a/installation.md +++ b/installation.md @@ -20,12 +20,12 @@ These are the requirements to run TastyIgniter as a stand-alone application: ### Installing TastyIgniter -TastyIgniter manages its dependencies and extensions using -composer. To install the platform, use the `create-project` command in the terminal to create a project. The command +TastyIgniter manages its dependencies and extensions using composer. +To install the platform, use the `create-project` command in the terminal to create a project. The command below creates a new project in the directory `mytasty`. ```bash -composer create-project tastyigniter/tastyigniter:v4.x-dev mytasty +composer create-project tastyigniter/tastyigniter:^v4.0@beta mytasty ``` From here, you can move on to the [Setting up TastyIgniter](#setting-up-tastyigniter) step. @@ -46,7 +46,7 @@ To install TastyIgniter as a package from your command line, run the following c directory: ```bash -composer require tastyigniter/core:dev-master +composer require tastyigniter/core:^v4.0@beta ``` From here, you can move on to the [Setting up TastyIgniter](#setting-up-tastyigniter) step.