# Overview

Welcome to TomatoPhp, the cutting-edge framework designed to revolutionize the way you build web applications.

<figure><img src="/files/9yyTLRSzNevxfXsMVs2L" alt=""><figcaption></figcaption></figure>

Our framework is built with PHP and utilizes the power of Laravel, the leading PHP framework, as its main backbone. In addition, we have integrated the awesome package Splade.dev, which brings even more versatility and enhancements to your development experience.

With TomatoPhp, you can experience accelerated development, as we have combined the most repetitive tasks into a comprehensive package that makes application generation a breeze. Not only that, but you can also customize your workflow and CRUD with ease, thanks to our dozens of ready-made add-ons and the integration of Splade.dev.

Get ready to say goodbye to the tedious and time-consuming tasks of web development, and hello to a new era of efficiency and customization. Our framework is your secret weapon to build the next generation of web applications with ease. Don't wait any longer, download TomatoPhp now and start your journey to effortless web development today!

>

### Gold Sponsors

<figure><img src="/files/VUDbPNm8ZCcLkhR5ruGR" alt="" width="375"><figcaption></figcaption></figure>

<figure><img src="/files/OGKCSLGckcCasaryh2Uw" alt="" width="375"><figcaption></figcaption></figure>

<figure><img src="/files/EAP95RmrIFpZVNUs0WI9" alt=""><figcaption></figcaption></figure>

### Overview

**TomatoPHP** is built to make it easy to develop web apps and API by generating files of CRUD operations and support helpers of tonnes of functions to make it easy to manage and use framework services.

### Back-End Tech Space

1. [Laravel](https://laravel.com/)
2. [Splade](https://splade.dev)
3. [Breeze Starter Kit](https://splade.dev/docs/breeze)

### Front-End Tech Space

please review these packages before starting development.

1. [VueJs](https://vuejs.org/)
2. [TailwindCSS](https://tailwindcss.com/)
3. [ViteJS](https://vitejs.dev/)
4. [inertiaJS](https://inertiajs.com)

### Features

* SPA App With Blade
* CRUD Generator Web / API [Web](https://github.com/tomatophp/docs/blob/master/broken-reference/README.md) / [API](/plugins/tomato-api)
* Support [HMVC](https://nwidart.com/laravel-modules/v6/introduction) Architecture
* [Authentication & User Manager](/plugins/tomato-roles)
* Responsive UI Using [Filament Template](https://github.com/tomatophp/docs/blob/master/broken-reference/README.md)
* RTL/Dark Mode Support
* Ready to Use Breeze Tool Kit Support RTL/Dark Mode
* Ready to Use Arabic / English Translations
* Easy To use [Menu With Provider](/tomato-admin/menu)

### Credits

TomatoPHP uses some open-source third-party libraries/packages internally, many thanks to the web community, it will be perfect if you review it before start using our framework:

* [**Laravel**](https://laravel.com/) Main Framework
* [**InertiaJS**](https://inertiajs.com/) VueJs Framework
* [**TailwindCSS**](https://tailwindcss.com/) Style Kit
* [**VueJs**](https://vuejs.org/) Javascript framework
* [**Splade**](https://splade.dev) The magic of Inertia.js with the simplicity of Blade
* [**Filament**](https://filamentphp.com/) It's a very creative admin panel for TALL stack
* [**Laravel Sanctum**](https://laravel.com/docs/8.x/sanctum) APIs Token Auth
* [**Laravel Permission**](https://spatie.be/docs/laravel-permission/v4/introduction) User ACL
* [**Laravel Module**](https://nwidart.com/laravel-modules/v6/introduction) MVC Modular Arch
* [**Laravel Excel**](https://laravel-excel.com/) Import & Export Excel
* [**Laravel Sitemap**](https://github.com/spatie/laravel-sitemap) Sitemap Generator
* [**Laravel Translatable**](https://github.com/spatie/laravel-translatable) Translation UI
* [**Laravel Media Library**](https://github.com/spatie/laravel-medialibrary) Media & Upload
* [**Laravel Backup**](https://github.com/spatie/laravel-backup) Backup

### Contributors

* [Fady Mondy](https://github.com/3x1io)
* [Khaled Abodaif](https://github.com/khaledAbodaif)
* [Ahmed Elbanna](https://github.com/Ahmed-Elbanna-Git)
* [Mohamed Ibrahem](https://github.com/marious)

### License

The MIT License (MIT). Please see [License File](https://github.com/queents/vilt/blob/master/LICENSE.md) for more information.


# Support

## Developers Support

we have a good community to support your issues to can join our Discord Server to fix your bugs in real time [join now](https://discord.com/invite/VZc8nBJ3ZU)

## Sponsoring

TomatoPHP is meant to be free, forever. Having a good companion for developing real-time applications locally and in production should not involve any third party and having a reliable app easy to deploy on a server makes TomatoPHP a compelling option for many applications.

Of course, like many open-source software solutions, development is done by investing volunteer time into the project. Therefore, all donations are greatly appreciated. You can sponsor the development via [Github Sponsors](https://github.com/sponsors/3x1io).

<figure><img src="/files/JQXCTgs9VIwgmHWaoyvi" alt=""><figcaption></figcaption></figure>


# Contributing

All contributions to ToamtoPHP are highly appreciated. Please consider [CONTRIBUTING](#contributing) for more information on making contributions. In addition, you may review our current development plans and tasks for the current and upcoming versions via [GitHub Projects](https://github.com/orgs/tomatophp/projects/1).

We make every effort to give all contributors credit for their contribution in release notes, etc.

### Stargazers

We really appreciate how this project turned out to be such a great success. It will always remain open-source, free, and maintained. This is real-time as it should be.

## Contributing

Contributions are **welcome** and will be fully **credited**.

Please read and understand the contribution guide before creating an issue or pull request.

### Etiquette

This project is open source, and as such, the maintainers give their free time to build and maintain the source code held within. They make the code freely available in the hope that it will be of use to other developers. It would be extremely unfair for them to suffer abuse or anger for their hard work.

Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the world that developers are civilized and selfless people.

It's the duty of the maintainer to ensure that all submissions to the project are of sufficient quality to benefit the project. Many developers have different skill sets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used.

### Viability

When requesting or submitting new features, first consider whether it might be useful to others. Open source projects are used by many developers, who may have entirely different needs to your own. Think about whether or not your feature is likely to be used by other users of the project.

### Procedure

Before filing an issue:

* Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
* Check to make sure your feature suggestion isn't already present within the project.
* Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
* Check the pull requests tab to ensure that the feature isn't already in progress.

Before submitting a pull request:

* Check the codebase to ensure that your feature doesn't already exist.
* Check the pull requests to ensure that another person hasn't already submitted the feature or fix.

### Requirements

If the project maintainer has any additional requirements, you will find them listed here.

* [**PSR-4 Coding Standard**](https://www.php-fig.org/psr/) - The easiest way to apply the conventions is to install [SonarLint](https://www.sonarsource.com/products/sonarlint).
* **Add tests!** - Your patch won't be accepted if it doesn't have tests.
* **Document any change in behavior** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
* **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.

**Happy coding**!


# Screenshots

Screenshots form the admin panel and some plugins

## Login Screen

<figure><img src="/files/KyATtuCYYOIREWztwr4I" alt=""><figcaption></figcaption></figure>

## Dashboard Dark Mode

<figure><img src="/files/SoVEsAtdU6OaSxMXUVSs" alt=""><figcaption></figcaption></figure>

## Dashboard Dark Mode RTL

<figure><img src="/files/NBsFL50cBUkvXnV6yjpv" alt=""><figcaption></figcaption></figure>

## Dashboard Light Mode

<figure><img src="/files/GHEG5pouDwPJ8GQl4cBw" alt=""><figcaption></figcaption></figure>

## Table View Light Mode

<figure><img src="/files/FIeoKQzUMI2EwKUIKPRr" alt=""><figcaption></figcaption></figure>

## Table View Dark Mode

<figure><img src="/files/Pj17fmdEQsX53sEhLKZa" alt=""><figcaption></figcaption></figure>

## SlideOver Form

<figure><img src="/files/SOPSV6IZaXADMieleAsc" alt=""><figcaption></figcaption></figure>

## Settings Page

<figure><img src="/files/Ty3OeJ4GRygE44smhHNR" alt=""><figcaption></figcaption></figure>

## Roles Edit Page

<figure><img src="/files/oNKzrisp4wW5KphUgsv4" alt=""><figcaption></figcaption></figure>

## Profile Page

<figure><img src="/files/aFMG25SAuuJPFE4ERx2Q" alt=""><figcaption></figcaption></figure>


# Environment Setup

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-type="content-ref"></th><th data-type="content-ref"></th></tr></thead><tbody><tr><td>Laravel Valet</td><td></td><td></td><td><a href="/pages/bUV6xqQVs9syhwGmkVxH">/pages/bUV6xqQVs9syhwGmkVxH</a></td><td></td></tr><tr><td>PHPMyAdmin</td><td></td><td></td><td><a href="/pages/vdn0Y8qTd0h1HVudVkHJ">/pages/vdn0Y8qTd0h1HVudVkHJ</a></td><td></td></tr><tr><td>Configuring Server</td><td></td><td></td><td></td><td><a href="/pages/vCzeAXfFAItCLTYWgUEi">/pages/vCzeAXfFAItCLTYWgUEi</a></td></tr></tbody></table>


# Configuring the server

we are recommending using our environment to make the project work will we are using ubuntu Linux and laravel valet +

### Install BackBox Linux

we are like to use [BackBox](https://www.backbox.org/download/) Linux it has a lot of tools and supports our environment, so from the link we keep downloading the ISO image and putting it in USB using [Rufus](https://rufus.ie/en/) and then booting your computer into it

***

### Install dependencies packages

let's start by opening our terminal and updating the system to the last one, and after that install some packages

```bash
sudo add-apt-repository -y ppa:nginx/stable
sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
```

```bash
sudo apt-get upgrade
```

after it finished reboot your computer and after that run this command

```bash
sudo apt-get install network-manager libnss3-tools jq xsel
```

***

### Install PHP & its extensions

```bash
sudo apt install php8.2-fpm
```

```bash
sudo apt install php8.2-cli php8.2-common php8.2-curl php8.2-mbstring php8.2-opcache php8.2-readline php8.2-xml php8.2-zip php8.2-mysql php8.2-gd
```

### Install MySql Server

```bash
sudo apt-get -y install mysql-server
```

```bash
sudo mysql_secure_installation
```

use `0` for the password and use any password something like `12345678`

after the installation is finished, start MySQL server

```bash
sudo mysql
```

and on the MySQL server console use this command

```sql
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '12345678';
```

```sql
mysql> FLUSH PRIVILEGES;
```

```sql
mysql> exit;
```

***

### Install Composer

```bash
sudo apt install curl
```

```bash
curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
```


# Install Valet

```bash
composer global require genesisweb/valet-linux-plus
```

no, you need to export Valet use

```bash
PATH="$PATH:$HOME/.composer/vendor/bin"
```

Or use the following

```bash
PATH="$PATH:$HOME/.config/composer/vendor/bin"
```

and now it will be easy to start installing valet

```bash
valet install
```

it will ask you for a password input `12345678`


# Install PHPMyAdmin

the valet has been installed now, let's go and install PHPMyAdmin and link it with the .test subdomain using valet first of all, create a folder for your sites on the home directory \~

```bash
cd ~
mkdir Sites
cd Sites
```

now we are on the Sites path, let's park this directory to be the directory of our projects

```bash
valet park
```

now any project on this directory will be auto-linked with subdomain .test, let's download PHPMyAdmin from this [link](https://www.phpmyadmin.net/) and unzip the file inside the Sites directory and rename the folder to PHPMyAdmin, after that go inside the folder and use this command

```bash
cp config.sample.inc.php config.sample.php
nano config.sample.php
```

change the line to

```php
$cfg['blowfish_secret'] = 'YK07LhNSe50vrj,HwBfb.l3gpbv;u8b7',
```

now use CTRL + x and say Y now we will use valet to link PHPMyAdmin and secure the link with SSL

```bash
valet link
valet secure
valet open
```

now you can see the PHPMyAdmin working and you can use root as the user and the password you created to MySQL to login


# Install

<figure><img src="/files/KCe4HRVzfAHaOCr8QMwr" alt=""><figcaption></figcaption></figure>

you can create a new project with our kit or use this package [Tomat Admin](/tomato-admin/get-started)

```
composer create-project tomatophp/tomato
```

create a new database and add your database credentials to .env file

```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=tomato-kit
DB_USERNAME=root
DB_PASSWORD=26111995
```

change the main URL in .env file

```
APP_URL=https://tomato-kit.test
APP_HOST=tomato-kit.test
```

clear cache of config

```
php artisan config:cache
```

and run the migration

```
php artisan migrate
```

install frontend packages

```
yarn
yarn build
```

now your app is ready to login `admin/login`

you can use `admin@admin.com` and `password` as a username and password for admin.

enjoy it 🍅

## Using Docker? no problem

if you are using docker as your development env you can up the project in a very easy way by just using this command

```bash
bin/serve
```

The `bin/serve` script is for installing the dependencies and setting up the local environment.\
The only requirement beforehand is that Docker/Docker Desktop is installed.

### Run WebSocket

you can run your socket server just by running this command without any config

```bash
php artisan websocket:serve
```

### Ubuntu Auto Install Script

if you have a fresh install Ubuntu OS you can install all needs for Tomato by just using 1 line

```
ubuntu-22-install-script
```

it will start the install script and ask you for your root password.

### Allow Spatie Media Library inside your app

if you want to use media features inside your app you need to complete setup of Spatie Media Library, it's easy just publish the migration and migrate it.

```bash
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider"
```

now run your migration

```bash
php artisan migrate
```

now it's time to allow modules on your app by just adding this line to composer.json

```json
"autoload": {
    "psr-4": {
        ...
        "Modules\\" : "Modules/"
    }
},
```

### Installed Plugins

* [Tomato Splade](https://splade.dev/)
* [Tomato Admin](https://github.com/tomatophp/tomato-admin)
* [Tomato Roles](/plugins/tomato-roles)
* [Tomato Translations](/plugins/tomato-translations)
* [Tomato Logs](/plugins/tomato-logs)
* [Tomato Backup](/plugins/tomato-backup)

### More Plugins

* [Tomato Plugins](https://docs.tomatophp.com/plugins)

to install this package you can use this command line

```
php artisan tomato:plugins
```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Credits

* [Fady Mondy](https://github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato/blob/master/LICENSE.md) for more information.


# Start Your First CRUD

you can build a CRUD after you make a migration for your table, let's say you need to build a customer's table through this migration.

you can create a new migration

```bash
php artisan make:migration create_customers_table
```

and after that, you can build your customer table schema.

```php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCustomersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('customers', function (Blueprint $table) {
            $table->id();
            $table->string('name')->index();
            $table->longText('bio')->nullable();
            $table->string('email')->unique()->index();
            $table->string('phone');
            $table->text('address')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('customers');
    }
}
```

run migration to create the table

```bash
php artisan migrate
```

now you need to install our Generator Plugin Tomato PHP so please use this command to install it

```bash
composer require tomatophp/tomato-php
```

and here is the tomato step just use this command

```bash
php artisan tomato:generate
```

it will ask you about the table name you generate a migration for it, and if you like to use Laravel Modules, you can just say `y` on the next ask.

now you need to add a menu item to the `AppServiceProvier boot()` function like this

```php
use TomatoPHP\TomatoAdmin\Facade\TomatoMenu;
use TomatoPHP\TomatoAdmin\Services\Contracts\Menu;

... 

public function boot()
{
    TomatoMenu::register(
        Menu::make()
            ->group('Resources')
            ->label('Users')
            ->route('admin.customers.index')
            ->icon('bx bx-user')
    );
}
```

This facade accepts an array or just 1 Menu class so you can use it as you like

make sure that your view is clean by using this command

```bash
php artisan optimize:clear
```

BOM.. your CRUD is ready.


# Get Started

🍅 Tomato Admin Dashboard Build With FilamentPHP Theme for Laravel Splade

<figure><img src="/files/9yyTLRSzNevxfXsMVs2L" alt=""><figcaption></figcaption></figure>

This package has some features you can use on your Splade project

* [FilamentPHP](https://filamentphp.com/) v2 Admin panel Theme Clone
* Menu  Facade to attach new items to the menu from anywhere on the code
* Support TomatoPHP CRUD generator
* Ready To Use RTL support \[Arabic]
* Ready To Use Dark Mode
* Tons of Ready Components
* Requests Facade to make it easy to make CRUDs, with support of Laravel-media-library
* Widget Facade to help you add new Widgets to the home page of the dashboard
* Response Helper to make it easy to return the same response to every API call

### Credits

* [Splade](https://splade.dev/)
* [Breeze Starter Kit](https://splade.dev/docs/breeze)
* [FilamentPHP](https://filamentphp.com/)


# Install

<figure><img src="/files/WvQczReioKnHbBLchlvp" alt=""><figcaption></figcaption></figure>

{% embed url="<https://www.youtube.com/watch?v=MdJPtoFn2xc>" %}

to install this package you use this command

```
composer require tomatophp/tomato-admin
```

### Use Install Command

you can use the install command to build your admin panel

**NOTE**

before installing if you are not using `MacOS` please change the `Yarn` path of config on the [console-helper](/helpers/laravel-console-helpers) package after publishing the config file

```
php artisan tomato-admin:install
```

After Tomato installs everything run your npm

```
yarn
yarn build
```

### Allow Spatie Media Library inside your app

if you want to use media features inside your app you need to complete setup of Spatie Media Library, it's easy just publish the migration and migrate it.

```bash
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider"
```

now run your migration

```bash
php artisan migrate
```

now it's time to allow modules on your app by just adding this line to composer.json

```json
"autoload": {
    "psr-4": {
        ...
        "Modules\\" : "Modules/"
    }
},
```

### Create New User

you can create a new user to access the dashboard by using this command

```bash
php artisan tomato:user
```


# Generate CRUD

#### !Note

thanks for [Tomato PHP](/tomato-php/get-started) generator plugin so you now can generate a full CRUD, you need to install it first to use this feature

### Create Migration

first, make a migration like

```bash
php artisan make:migration create_customer_table
```

after you fill migration with your schema run migration

```bash
php artisan migrate
```

### Generate CRUD

it's straightforward to use our package by just creating a new migration and migrating it after your table and schema are ready to use this command

```
php artisan tomato:generate
```

it will ask you to input the table name and bingo you get the full CRUD ready.

### What is the file we are generating?

you build a full CRUD with some files like

* Controller \[app\Http\Controllers\Admin]
* Table \[app\Tables]
* Model \[app\Models]
* Views \[resources\views\admin\TABLE]
* Routes \[routes\web.php]


# Slots

as we like to add more customization to our dashboard we added a new Facade Class TomatoSlot it's used to attach a view to anywhere on the dashboard from any service provider, which means you can create a package to add a button in every single view on the app.

### Use

on your service provider just add

```php
use TomatoPHP\TomatoAdmin\Facade\TomatoSlot;

public function boot()
{        
   TomatoSlot::layoutButtons('core::buttons');
}
```

### Methods

```php
 * @method static navAfterUserDropdown(string $navAfterUserDropdown)
 * @method static navBeforeUserDropdown(string $navBeforeUserDropdown)
 * @method static navLeftSide(string $navLeftSide)
 * @method static sidebarTop(string $sidebarTop)
 * @method static sidebarBottom(string $sidebarBottom)
 * @method static footer(string $footer)
 * @method static dashboardBottom(string $dashboardBottom)
 * @method static dashboardTop(string $dashboardTop)
 * @method static layoutButtons(string $layoutButtons)
 * @method static layoutTitle(string $layoutTitle)
 * @method static layoutTop(string $layoutTop)
 * @method static layoutBottom(string $layoutBottom)
 * @method static layoutButtoms(string $layoutButtoms)
 * @method static logoSection(string $logoSection)
```


# Widgets

we built a widget Facade service to make it easy to register a widget to the dashboard home page from any provider, so you can use it on your package or on your AppServiceProvider as well.

## Registering a widget

you can go to any service provider `boot()` method and register your widget like this:

```php
use TomatoPHP\TomatoAdmin\Facade\TomatoWidget;
use TomatoPHP\TomatoAdmin\Services\Contracts\Widget;

public function boot()
{
    TomatoWidget::register([
            Widget::make()
                ->title(__('Users'))
                ->icon('bx bxs-user')
                ->counter(User::count()),
            Widget::make()
                ->title(__('Roles'))
                ->icon('bx bx-lock')
                ->counter(Role::count())
        ]);
    }
}
```

and you will see the widget on the homepage of the dashboard directly.

### Widget Component

you can use Widget as a component like this

```html
 <x-tomato-admin-widget 
   :title="__('Total Users')" 
   icon="bx bxs-user" 
   :counter="\App\Models\Users::query()->count()"
 />
```


# Menus

it's a very easy-to-use menu provider by just using this class method on your app service provider

```php
use TomatoPHP\TomatoAdmin\Facade\TomatoMenu;
use TomatoPHP\TomatoAdmin\Services\Contracts\Menu;

public function boot()
{
     TomatoMenu::register([
           Menu::make()
            ->group(__('ALC'))
            ->label(__('Users'))
            ->icon('bx bx-user')
            ->route('admin.users.index'),
           Menu::make()
            ->group(__('ALC'))
            ->label(__('Roles'))
            ->icon('bx bx-lock')
            ->route('admin.roles.index')
    ]);
}
```

and the menu will auto registered to your sidebar of the admin dashboard

you can order the groups or hide a group using this method

```php
use TomatoPHP\TomatoAdmin\Facade\TomatoMenu;

public function boot()
{
    TomatoMenu::groups([
        __('ALC') => true,
        __('Settings') => false, //Hidden
    ]);
}
```


# Requests


# Index Request

this method returns view or JsonResponse based on the request type. and we get the request type by check if the route has `splade` middleware or not.

this method accept some arguments:

* `request` the request object
* `model` the model you want to get
* `view` the view you want to return
* `table` the table class you want to use
* `data` the data you want to pass to the view
* `api` if you want to return JsonResponse or not
* `resource` resource class to resource your returned data
* `query` if you want to add some query to the model
* `filters` if you want to add some filters to the table

```php
public function index(Request $request): View|JsonResponse
{
    return Tomato::index(
        request: $request, //Required
        model: $this->model, //Required
        view: 'users.index', 
        table: \App\Tables\UserTable::class,
        data: [
            'name' => 'john doe',
        ],
        api: true,
        resource: UserResource::class,
        query: User::query()->where('is_activated',true),
        filters: [
            'is_activated',
        ],
    );
}
```


# JSON Request

this method return only json response of the model to make it easy to access it with `x-splade-select` or `x-tomato-admin-select`

this method accept some arguments:

* `request` the request object
* `model` the model you want to get
* `data` the data you want to pass to the view
* `paginate` if you want to paginate the response or not
* `query` if you want to add some query to the model
* `filters` if you want to add some filters to the table

```php
public function api(Request $request): JsonResponse
{
    return Tomato::json(
        request: $request, //Required
        model: \App\Models\User::class, //Required
        data: [
            'name' => 'john doe',
        ],
        paginate: 10,
        query: User::query()->where('is_activated',true),
        filters: [
            'is_activated',
        ],
    );
}
```


# Get Request

this method returns view or JsonResponse based on the request type. and we get the request type by check if the route has `splade` middleware or not.

this method accept some arguments:

* `model` the model you want to get
* `view` the view you want to return
* `data` the data you want to pass to the view
* `hasMedia` if you want to get the media of the model or not
* `collection [array]` the media collection you want to get as array take true if it's multi or false if it's single
* `attach [array]` to attach some data to the model
* `api` if you want to return JsonResponse or not
* `resource` resource class to resource your returned data
* `query` if you want to add some query to the model

```php
public function show(\App\Models\User $model): View|JsonResponse
{
    return Tomato::get(
        model: $model, //Required
        view: 'users.show', //Required
        data: [
            'name' => 'john doe',
        ],
        hasMedia: true,
        collection: [
            'avatar' => false,
            'gallery' => true
        ],
        attach: [
            'roles' => $model->roles,
        ],
        api: true,
        resource: UserResource::class,
        query: User::query()->where('is_activated',true)
    );
}
```


# Store Request

this method returns RedirectResponse or JsonResponse based on the request type. and we get the request type by check if the route has `splade` middleware or not.

this method accept some arguments:

* `request` the request object
* `model` the model you want to get
* `validation` the validation rules you want to use
* `message` the message you want to return with the response
* `validationError` the message you want to return if the validation failed
* `redirect` the redirect route you want to redirect to
* `hasMedia` if you want to get the media of the model or not
* `collection [array]` the media collection you want to get as array take true if it's multi or false if it's single
* `api` if you want to return JsonResponse or not

```php
public function store(Request $request): RedirectResponse|JsonResponse
{
    $response = Tomato::store(
        request: $request, //Required
        model: \App\Models\User::class, //Required
        validation: [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
        ],
        message: __('User created successfully'),
        validationError: __('Error When Try To Store User'),
        redirect: 'admin.users.index',
        hasMedia: true,
        collection: [
            'avatar' => false,
            'gallery' => true
        ],
        api: true,
    );

    if($response instanceof JsonResponse){
        return $response;
    }

    return $response->redirect;
}
```


# Update Request

this method returns RedirectResponse or JsonResponse based on the request type. and we get the request type by check if the route has `splade` middleware or not.

this method accept some arguments:

* `request` the request object
* `model` the model you want to get
* `validation` the validation rules you want to use
* `message` the message you want to return with the response
* `validationError` the message you want to return if the validation failed
* `redirect` the redirect route you want to redirect to
* `hasMedia` if you want to get the media of the model or not
* `collection [array]` the media collection you want to get as array take true if it's multi or false if it's single
* `api` if you want to return JsonResponse or not

```php
public function update(Request $request, \App\Models\User $model): RedirectResponse|JsonResponse
{
    $response = Tomato::update(
        request: $request, //Required
        model: $model, //Required
        validation: [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
        ],
        message: __('User updated successfully'),
        redirect: 'admin.users.index',
        hasMedia: true,
        collection: [
            'avatar' => false,
            'gallery' => true
        ],
        api: true,
    );

     if($response instanceof JsonResponse){
         return $response;
     }

     return $response->redirect;
}
```


# Destroy Request

this method returns RedirectResponse or JsonResponse based on the request type. and we get the request type by check if the route has `splade` middleware or not.

this method accept some arguments:

* `model` the model you want to get
* `message` the message you want to return with the response
* `redirect` the redirect route you want to redirect to
* `api` if you want to return JsonResponse or not

```php
public function destroy(\App\Models\User $model): RedirectResponse|JsonResponse
{
    $response = Tomato::destroy(
        model: $model, //Required
        message: __('User deleted successfully'), //Required
        redirect: 'admin.users.index',
    );

    if($response instanceof JsonResponse){
        return $response;
    }

    return $response->redirect;
}
```


# Inputs


# Rich Text Editor

<figure><img src="/files/3bJVxcmSOnYMIKCliiJr" alt=""><figcaption></figcaption></figure>

you can use a full Rich Text Editor on your project by using this component like

```html
<x-tomato-admin-rich 
    id="description" 
    name="description" 
    label="Description" 
    required
/>
```

this component is uses [vue3-editor](https://www.npmjs.com/package/vue3-editor) package to build this editor


# Phone Editor

<figure><img src="/files/X8pqD0NBiNspKDtjphSq" alt=""><figcaption></figcaption></figure>

you can make an easy phone with country code and flag by using this component

```html
<x-tomato-admin-tel 
    id="contact_phone" 
    name="contact_phone" 
    label="Contact Phone" 
    required
/>
```

this component uses [vue3-tel-input](https://www.npmjs.com/package/vue3-tel-input)


# Color Switcher

<figure><img src="/files/vcPwIJAtqSczz2cSw7PY" alt=""><figcaption></figcaption></figure>

you can use a color switcher selector by using this component

```html
<x-tomato-admin-color 
    id="theme_color" 
    name="theme_color" 
    label="Theme Color" 
    required
/>
```

this component used [vue3-swatches](https://www.npmjs.com/package/vue3-swatches)


# Inputs Repeater

<figure><img src="/files/C8ypyzzDxIELnkW0qUWB" alt=""><figcaption></figcaption></figure>

if you have a JSON object and you want to fill it with data with a selected type of input? it can be easy to use Repeater Components.

this component has 2 types, repeater/schema, the repeater builds an array of JSON but schema builds just 1 JSON Object

```html
:options="['label']"
```

this attribute must have a field of your JSON object and you can access these fields by using v-model  like this&#x20;

```html
repeater.main[key].label
```

where the label is the name of the field, and here is an example for your repeater.

```html
<x-tomato-admin-repeater 
    :options="['label']" 
    type="repeater" 
    id="site_menu" 
    name="site_menu" 
    label="Site Menu" 
    required
>
    <x-splade-input 
        class="my-2" 
        v-model="repeater.main[key].label" 
        type="text" 
        placeholder="label"   
        required  
    />
</x-tomato-admin-repeater>
```


# Draggable

<figure><img src="/files/FfI73VsMTxCikV7CRMVm" alt=""><figcaption></figcaption></figure>

everyone needs a draggable input on a project, but it's very hard to handle, for this, we created a very easy component to make it easy to handle draggable objects and make it very easy to store and sort them on the database.

you can start using this like this

```markup
<x-tomato-admin-draggable  
    :levels="3" 
    :options="$menusItems->toArray()" 
    url="{{route('admin.menus.item.all', $menu->id)}}" 
    order-by="order"
>
     <div>@{{ drag.item.name }}</div>
</x-tomato-admin-draggable>
```

our component works with multi-levels which means you can create a tree of objects just by using this component you can change `:levels` as you like to be the count of levels

and to make this component work you must pass options to it where `:options` is an array of objects you need to sort

and at the end of this, you need to add `:url` and we will hit this your everytime you make a change on sorting inside the dragging area

the last attribute is `:order-by` and we use it to order the objects by it

to store this object and make the ordering successful you can just use this code on your store method

```php
public function itemAll(Request $request, Menu $menu){
    $request->validate([
        "all" => "required|array",
        "orderBy" => "required|string",
    ]);

    $counter = 0;
    foreach($request->get('all') as $key=>$item){
        $menuItem = MenusItem::where('id', $item['id'])->first();
        $menuItem->{$request->get('orderBy')} = $counter;
        $menuItem->save();

        if(isset($item['children']) && count($item['children'])){
            $countChild = 0;
            foreach($item['children'] as $key=>$child){
                $childItem = MenusItem::where('id', $child['id'])->first();
                $childItem->parent_id = $menuItem->id;
                $childItem->{$request->get('orderBy')} = $countChild;
                $childItem->save();

                $countChild++;

                if(isset($child['children']) && count($child['children'])){
                    $this->setChildren($child, $childItem);
                }
            }
        }
        else {
            $menuItem->parent_id = null;
            $menuItem->save();
        }
        $counter++;
    }

    return back();
}
```

this method takes all objects on the draggable and sorting it

this component used [vue-draggable-next](https://github.com/SortableJS/vue.draggable.next)


# Code Editor

<figure><img src="/files/iJpGdM5hBtxHNB2zr8TS" alt=""><figcaption></figcaption></figure>

you can get a code editor like any input on splade by just use this code

```markup
<x-tomato-admin-code 
    label="Content"
    name="content" 
    ex="txt" 
/>
```

where `:ex` is the excitation of the file

this component used [codemirror-editor-vue3](https://www.npmjs.com/package/codemirror-editor-vue3)


# Select Input

<figure><img src="/files/waMw89leLMWIiuvZDBvJ" alt=""><figcaption></figcaption></figure>

because of some limits of `x-splade-select` you develop a new component using [vue-multiselect](https://vue-multiselect.js.org/) this new component has features:

* Load data from APIs
* Search Sync with API
* Pagination support with load more button
* Auto Fill Selected Data from API

you can use this select input like `x-splade-select`

```markup
<x-tomato-admin-select 
    :label="__('Developer id')" 
    :placeholder="__('Developer id')" 
    name="developer_id"
    remote-url="{{route('admin.users.api')}}" 
    remote-root="data" 
    option-label=name.en 
    option-value="id" 
    type="relation" 
    query-by="name" 
    paginated
/>
```

`:type` is the type of select it can be select / relation

`:query-by` is the name of the request key sent when searching

`:paginated` is a bool for options of pagination


# Submit

<figure><img src="/files/LQkljv9KjC3i8HYTboUv" alt=""><figcaption></figcaption></figure>

this component is a FilamentPHP button Primary Style for submitting any form support spinning on submit and disabled you can use it like this

```html
<x-tomato-admin-submit 
    label="{{__('Save')}}" 
    :spinner="true"
/>
```


# Items

<figure><img src="/files/uWQ7VPN02Eri7crLOxsv" alt=""><figcaption></figcaption></figure>

items component can be used on your invoice like a [Inputs Repeater](/tomato-admin/inputs/inputs-repeater) but it's support calculation operations for qty and price and total and vat.

you can use it like this&#x20;

```html
<x-tomato-items :options="['item'=>'', 'price'=>0, 'discount'=>0, 'tax'=>0, 'qty'=>1,'total'=>0, 'options' =>(object)[]]" name="items">
    <div class="grid-cols-12 gap-4 border-b py-4 my-4 hidden lg:grid">
        <div class="col-span-4">
            {{__('Item')}}
        </div>
        <div>
            {{__('Price')}}
        </div>
        <div>
            {{__('Discount')}}
        </div>
        <div>
            {{__('Tax')}}
        </div>
        <div>
            {{__('QTY')}}
        </div>
        <div class="col-span-2">
            {{__('Total')}}
        </div>
    </div>
    <div class="block border-b py-4 mb-4 lg:hidden">
        {{__('Items')}}
    </div>
    <div class="flex flex-col gap-4">
        <div class="grid grid-cols-12 gap-4" v-for="(item, key) in items.main">
            <div class="col-span-12 lg:col-span-4 flex justify-between gap-4">
                <x-tomato-search
                    @change="
                                items.main[key].price = items.main[key].item?.price;
                                items.main[key].discount = items.main[key].item?.discount;
                                items.main[key].tax = items.main[key].item?.vat;
                                items.updateTotal(key)
                            "
                    :remote-url="route('admin.orders.product')"
                    option-label="name?.{{app()->getLocale()}}"
                    remote-root="data"
                    v-model="items.main[key].item"
                    placeholder="{{__('Select Item')}}"
                    label="{{__('Product')}}"
                />
            </div>
            <x-splade-input
                class="col-span-12 lg:col-span-1"
                type="number"
                placeholder="Price"
                v-model="items.main[key].price"
                @input="items.updateTotal(key)"
            />
            <x-splade-input
                class="col-span-12 lg:col-span-1"
                type="number"
                placeholder="Item Name"
                v-model="items.main[key].discount"
                @input="items.updateTotal(key)"
            />
            <x-splade-input
                disabled
                class="col-span-12 lg:col-span-1"
                type="number"
                placeholder="Tax"
                v-model="items.main[key].tax"
                @input="items.updateTotal(key, data.discount_type)"
            />
            <x-splade-input
                class="col-span-12 lg:col-span-1"
                type="number"
                placeholder="QTY"
                v-model="items.main[key].qty"
                @input="items.updateTotal(key)"
            />
            <x-splade-input
                disabled
                class="col-span-12 lg:col-span-2"
                type="text"
                placeholder="Item Name"
                v-model="items.main[key].total"
                @input="items.updateTotal(key)"
            />
            <button @click.prevent="items.addItem" class="col-span-12 lg:col-span-1 filament-button inline-flex items-center justify-center py-1 gap-1 font-medium rounded-lg border transition-colors focus:outline-none focus:ring-offset-2 focus:ring-2 focus:ring-inset dark:focus:ring-offset-0 min-h-[2.25rem] px-4 text-sm shadow-sm focus:ring-white filament-page-button-action bg-primary-600 hover:bg-primary-500 focus:bg-primary-700 focus:ring-offset-primary-700 text-white border-transparent">
                <i class="bx bx-plus"></i>
            </button>
            <button @click.prevent="items.removeItem(item)" class="col-span-12 lg:col-span-1 filament-button inline-flex items-center justify-center py-1 gap-1 font-medium rounded-lg border transition-colors focus:outline-none focus:ring-offset-2 focus:ring-2 focus:ring-inset dark:focus:ring-offset-0 min-h-[2.25rem] px-4 text-sm shadow-sm focus:ring-white filament-page-button-action bg-danger-600 hover:bg-danger-500 focus:bg-danger-700 focus:ring-offset-danger-700 text-white border-transparent">
                <i class="bx bx-trash"></i>
            </button>
            <div class="col-span-12 lg:col-span-4" v-if="items.main[key].item.has_options" v-for="(option, optionIndex) in items.main[key].item.product_metas[0].value">
                <div>
                    <label for="">
                        @{{ optionIndex.charAt(0).toUpperCase() + optionIndex.slice(1) }}
                    </label>
                    <x-splade-select class="w-full" v-model="items.main[key].options[optionIndex]">
                        <option v-for="(value, valueIndex) in option" :value="value">
                            @{{ value.charAt(0).toUpperCase() + value.slice(1) }}
                        </option>
                    </x-splade-select>
                </div>
            </div>
        </div>
        <div v-if="form.errors.inventory"
             class="text-danger-500 mt-2 text-xs font-chakra flex gap-2 mb-[6px]">
            <p v-text="form.errors.inventory"> </p>
        </div>
    </div>
    <div class="flex flex-col gap-4 mt-4">
        <div class="flex justify-between gap-4 py-4 border-b">
            <div>
                {{__('Tax')}}
            </div>
            <div>
                @{{ items.tax }}
            </div>
        </div>
        <div class="flex justify-between gap-4 py-4 border-b">
            <div>
                {{__('Sub Total')}}
            </div>
            <div>
                @{{ items.price }}
            </div>
        </div>
        <div class="flex justify-between gap-4 py-4 border-b">
            <div>
                {{__('Discount')}}
            </div>
            <div>
                @{{ items.discount }}
            </div>
        </div>
        <div class="flex justify-between gap-4 py-4 border-b">
            <div>
                {{__('Total')}}
            </div>
            <div>
                @{{ items.total }}
            </div>
        </div>
    </div>
</x-tomato-items>
```


# Search

<figure><img src="/files/EjloU99Vq8It0uK7yraL" alt=""><figcaption></figcaption></figure>

on some views we need to get data from APIs and view it as Object!, and that's what this component does when you search it does a query on the remote URL and returns with an array of objects that you can select any object and it's filled with the object not just the ID

you can use it like this

```markup
<x-tomato-search
    :remote-url="route('admin.orders.user')"
    remote-root="data"
    name="account_id"
    placeholder="{{__('Select Account')}}"
    label="{{__('Account')}}"
/>
<div v-if="form.errors.account_id"
     class="text-danger-500 mt-2 text-xs font-chakra flex gap-2 mb-[6px]">
    <p v-text="form.errors.account_id"> </p>
</div>
<div v-if="form.account_id">
    <div class="text-lg font-bold mt-2">
        @{{form.account_id.name}}
    </div>
    <div class="text-sm">
        @{{form.account_id.email}}
    </div>
    <div class="text-sm">
        @{{form.account_id.phone}}
    </div>
    <div class="text-sm">
        @{{form.account_id.address}}
    </div>
    <div class="text-sm">
        @{{form.account_id.zip}} @{{form.account_id.city}}
    </div>
    <div class="text-sm">
        @{{form.account_id.country?form.account_id.country.name:''}}
    </div>
</div>
```


# Icon

<figure><img src="/files/tJsArjviYj81CYhP02LV" alt=""><figcaption></figcaption></figure>

as we see it's a Box Icons Selector you can search and view all Box Icons and select the icon then it will go to form as a string you can use it like this

```markup
<x-tomato-admin-icon label="{{__('Icon')}}" placeholder="{{__('Icon')}}" name="icon" />
```


# Components


# Relation Manager

<figure><img src="/files/L9kDG6uNlcAccKOFKnH8" alt=""><figcaption></figcaption></figure>

as we clone FilamentPHP Theme we get some VIP components, here is the relation manager component, The component is used to manage the relation between models, for example, if you have a user model and you want to show the roles of this user, you can use this component to do that.

### Use

you can use it like this

```html
<x-tomato-admin-relations-group :relations="['groups', 'locations']">
    <x-tomato-admin-relations
        :model="$model"
        name="groups"
        :table="\TomatoPHP\TomatoCrm\Tables\GroupTable::class"
    />
    <x-tomato-admin-relations
            :model="$model"
            name="locations"
            :table="\TomatoPHP\TomatoCrm\Tables\LocationTable::class"
            :show="true"
            :edit="true"
            :delete="true"
            :path="/admin/locations"
            :view="tomato-admin::components.relations"
    />
</x-tomato-admin-relations-group>
```

as you see you can group the relations table with `x-tomato-admin-relations-group` component and you can add as many relations tables as you want inside this group, and you can use `x-tomato-admin-relations` component to add a relation table.


# Container

<figure><img src="/files/Jbl7PMruRjXMIiwXpLS6" alt=""><figcaption></figcaption></figure>

we build a container component to make it easy to merge between page and model view, so this container converts any page to work as a page and model at the same time.

### Use

you can use it like

```html
<x-tomato-admin-container 
    label="{{__('Create User')}}"
>
    <!-- Your Content Here -->
</x-tomato-admin-container>
```

you can access this page as a direct page or using `modal` on the `x-splade-link` or `x-tomato-admin-button` like this

```html
<x-tomato-admin-button 
    modal
    :href="route('admin.users.create')"
>
    {{ __('Create User') }}
</x-tomato-admin-button>
```

### Slots

this container has 2 slots you can use to custom your view

```html
<x-slot:buttons>
    <!-- Your Buttons Here -->
</x-slot:buttons>
```

this slot is used to attach more buttons on the top left side of the page

```html
<x-slot:body>
    <!-- Your Content Here -->
</x-slot:body>
```

this slot is used to add content after the card.


# View Row

<figure><img src="/files/7X2R1OS4rsO09LRW3RQR" alt=""><figcaption></figcaption></figure>

we all need to get a ready-to-use view item for our model, so we built this component to make it easy to use and customize.

### Use

you can use it like this

```html
<x-tomato-admin-row 
    :label="__('Name')" 
    :value="$model->name" 
    type="text" 
/>
```

or you can use it as a link like

```html
<x-tomato-admin-row 
    :label="__('Name')" 
    :value="$model->name" 
    :href="route('admin.users.index')" 
    icon="bx bx-user" 
    color="#fff" 
    type="badge" 
/>
```

and it's accepted on value just string value and you can use this types:

* text
* string
* rich
* number
* email
* tel
* badge `this type accept icon and color and href`
* date
* datetime
* time
* image
* images
* icon
* color
* bool
* copy
* password


# Widget

<figure><img src="/files/ke8bZWvmEyj2M6rUdFyb" alt=""><figcaption></figcaption></figure>

as we get the Widget Facade service to register the widgets to the dashboard homepage, we get this component to register the same widgets anywhere.

### Use

you can use it like this

```html
<x-tomato-admin-widget
    :counter="300"
    :title="__('Projects')"
    icon="bx bx-category"
/>
```

or you can just pass a direct model and we will count it

```html
<x-tomato-admin-widget
    model="User::class"
    :title="__('Projects')"
    icon="bx bx-category"
/>
```

and you can change the query like this

```html
<x-tomato-admin-widget
    model="User::class"
    :query="[
        'is_activated' => true
    ]"
    :title="__('Projects')"
    icon="bx bx-category"
/>
```


# Button

<figure><img src="/files/XrwanhwL69YofHrHSl8X" alt=""><figcaption></figcaption></figure>

we are using buttons everywhere on the dashboard so we do 1 component to manage button types and button multi-style

## Use

you can add a new button like this

```html
<x-tomato-admin-button 
    :modal="true" 
    :href="route('admin.community-events.create')" 
    type="link"
>
    {{ __('Create User') }}
</x-tomato-admin-button>
```

or you can use it as an icon button inside a table like this

<figure><img src="/files/MzFKRY5SXboWW3dAb5ku" alt=""><figcaption></figcaption></figure>

```html
<x-tomato-admin-button 
    success 
    type="icon" 
    label="{{trans('tomato-admin::global.crud.view')}}" 
    modal 
    :href="route('admin.users.show', $item->id)"
>
    <x-heroicon-s-eye class="h-6 w-6"/>
</x-tomato-admin-button>
```

<figure><img src="/files/j5I2g4Sqs8z7AFh90ibR" alt=""><figcaption></figcaption></figure>

and the button works as well as the `x-splade-link` so you can create a delete button like this

```html
<x-tomato-admin-button 
    danger 
    type="icon" 
    label="{{trans('tomato-admin::global.crud.delete')}}" 
    :href="route('admin.bills.destroy', $item->id)"
    confirm="{{trans('tomato-admin::global.crud.delete-confirm')}}"
    confirm-text="{{trans('tomato-admin::global.crud.delete-confirm-text')}}"
    confirm-button="{{trans('tomato-admin::global.crud.delete-confirm-button')}}"
    cancel-button="{{trans('tomato-admin::global.crud.delete-confirm-cancel-button')}}"
    method="delete"
>
    <x-heroicon-s-trash class="h-6 w-6"/>
</x-tomato-admin-button>
```


# Menu

<figure><img src="/files/kMzh8eSk7qI5xi3FK47S" alt=""><figcaption></figcaption></figure>

as you know on the config page you can use a custom menu view for the sidebar of the dashboard so we build a component to make it easy to add a new menu with groups to this custom view

### Use

you can use it like this

```html
<x-menu-group 
    key="users" 
    label="{{__('ALC')}}"
>
    <x-menu-item 
        url="{{ route('admin.users.index') }}" 
        icon="bx bxs-user"
        badge="10"
    >
        {{__('Users')}}
    </x-menu-item>
    <x-menu-item 
        url="{{ route('admin.roles.index') }}" 
        icon="bx bx-lock" 
    >
        {{__('Roles')}}
    </x-menu-item>
</x-menu-group>
```

the group component used to group items together, but you can use menu items direct without a group


# Tooltip

<figure><img src="/files/mjkN2nce3Fk2fa5gPWHx" alt=""><figcaption></figcaption></figure>

you can use a tooltip component to shop a tooltip over any div like this

```markup
<x-tomato-admin-tooltip :text="__('Your Text Here')">
    <button>Welcome Here!</button>
</x-tomato-admin-tooltip>
```

this component used [tippyjs](https://atomiks.github.io/tippyjs/)


# ©️ Clipboard

<figure><img src="/files/pvIAQ6FtZjoVLvrpN8XV" alt=""><figcaption></figcaption></figure>

as we know we need to copy some string when we click on buttons like IPs or domains or just product links like this

```markup
<x-tomato-admin-copy :text="__('Copy Me')">
    <i class="bx bx-copy"></i>
</x-tomato-admin-copy>
```

this component uses [vueuse](https://vueuse.org/)


# Slider

<figure><img src="/files/xWPGkseHCCMhlDw7xr9M" alt=""><figcaption></figcaption></figure>

we are using Swiper to build this slider so all Swiper functions can be applied to the slider using native js buy use `<x-splade-script>` tag and you can use the slider like this&#x20;

```markup
<x-tomato-admin-slider
    class="w-full h-80"
    :images="$imagesTM ?? []"
    :horizontal="false"
    :items="1"
    :navigation="false"
>
    @foreach($images as $image)
        <x-tomato-admin-slider-item zoom>
            <div class="flex justify-center">
                <div class=" w-80 h-80">
                    <img src="{{$image}}"  class="object-contain" />
                </div>
            </div>
        </x-tomato-admin-slider-item>
    @endforeach
</x-tomato-admin-slider>
```

this component uses [Swiper](https://swiperjs.com/vue)


# Action Buttons

<figure><img src="/files/mLpYyCSolZvBffXqWnJ0" alt=""><figcaption></figcaption></figure>

this component is used to make it easy to add action buttons with some features you can use it like this

```markup
<x-tomato-admin-action-buttons 
    table="users" 
    :item="$item" 
    :view="true" 
    :edit="true" 
    :delete="true"
/>
```

where `table` is the table name of current CRUD


# Application Logo

<figure><img src="/files/5L7NKKoUgmcZjkfoXiUo" alt=""><figcaption></figcaption></figure>

this component is used to print the Tomato Logo everywhere and you can change it with your logo for your project you can use it like this

```markup
<x-tomato-application-logo class="w-16 h-16" />
```


# Dropdown

<figure><img src="/files/CNLzYASrHi9yVVO0BS2I" alt=""><figcaption></figcaption></figure>

you can use this component to create a dropdown like this

```markup
<x-tomato-admin-dropdown icon="bx bx-cog" class="bg-primary-600 hover:bg-primary-500 text-white rounded-full flex flex-col items-center justify-center p-2">
        <x-tomato-admin-dropdown-item
            type="link"
            :href="route('admin.products.toggle', $item->id) . '?action=is_activated'"
            :label="$item->is_activated ? __('Hide Product') : __('Show Product')"
            :success="!$item->is_activated"
            :danger="$item->is_activated"
            :icon="$item->is_activated ? 'bx bx-hide' : 'bx bx-show'"
        />
        <x-tomato-admin-dropdown-item
            black
            modal
            type="link"
            :href="route('admin.products.edit', $item->id)"
            :label="__('Edit Product')"
            icon="bx bx-edit"
        />
</x-tomato-admin-dropdown>
```


# Paginator

<figure><img src="/files/Wuf8EAMVRG1HrRfWT5ER" alt=""><figcaption></figcaption></figure>

if you try to use the default Laravel paginator you will find out that it does not have an SPA links component so we create another one with the replacement of \<a> tages to be \<x-splade-link> you can use it like this

```markup
{!! $users->links('tomato-admin::components.pagination') !!}
```


# Table

as we know the Splade Table is a magical component, but it has its limitations and we removed this limitation and added more options to make the table more power components.


# Bulk Actions

<figure><img src="/files/lgkdrUb35tJxolACZifs" alt=""><figcaption></figcaption></figure>

as we know [Splade](https://splade.dev/docs/table-bulk-actions) has its Bulk action function we added more features to this action.

## Modal Bulk Action

you can use bulk action to open the modal and we send selected IDs on the requests with, sprit so you can extract it and use it inside your modal or form to confirm an action.

you can use it like this

```php
$table->bulkAction(
    label: __('Attach to group'),
    type: 'modal',
    href: route('admin.accounts.groups'),
    style: "primary"
);
```

you can see there are 3 new attributes on the `bulkAction()` method, type it can be modal or bulk, and href to the route of modal, and style of the bulk action button


# Filters

<figure><img src="/files/MDrKXvJr2zSDzeyhWyCt" alt=""><figcaption></figcaption></figure>

there is a limitation on a filtering table inside [Splade table](https://splade.dev/docs/table-query-builder) so we added more features to the filters inside Splade Table

## Boolean Filter

I think we all need a filter with a boolean inside our tables to get active users or any boolean value filter, so we added a new filter method to Splade Table&#x20;

you can use it like this

```php
->boolFilter(
    key: 'is_active',
    label: __('Activated')
);
```

## Date Filter

as we go we need to filter a table by date range from to, so we add auto data filter to filter your records by created\_at filed form, to. just in one line

```php
->dataFilter();
```

you can custom it by using another like updated\_at

```php
->dateFilter(
    key: 'updated_at', 
    label: __('Updated At')
);
```

## Select Filter With Remote Data

is the feature we all need to get data from the remote URL inside the table filter, we make this happen we adding a new method to the table with more features.

you can use this selected like this

```php
->selectFilter(
    key: 'account_id',
    label: __('Account'),
    remote_root: 'data',
    remote_url: route('admin.accounts.index'),
    option_label: 'name',
    option_value: 'id',
);
```

## Override Filter Auto Query

as we know when we change the table filter it does the magic of filtering without any logic for this filter, but sometimes we need to do some extra custom query when the filter changes, so we add a new attribute inside all types of filters to do this.

you can use it like this.

```php
->selectFilter(
    key: 'account_id',
    label: __('Account'),
    remote_root: 'data',
    remote_url: route('admin.accounts.index'),
    option_label: 'name',
    option_value: 'id',
    applyQuery: false
);

```


# Slots

<figure><img src="/files/VISsBmRJEEdnT2JU6ffN" alt=""><figcaption></figcaption></figure>

The Splade table is a magical component inside the Splade system, but we need some extra slots inside.

## Actions Slot

we add a new slot inside the table to add more actions to the actions button, like import, export or more links to other tables or direct filters

you can use it like this

```html
<x-slot:actions>
    <x-tomato-admin-table-action secondary href="{{route('admin.types.accounts.type.index')}}" label="{{__('Accounts Types')}}" icon="bx bx-category" />
</x-slot:actions>
```

## Header Slot

sometimes you need to add a widget inside the table to change their data when the filter or pagination changes inside the table you can do that by using the header slot

you can use it like this

```markup
<x-slot:header>
    @if(config('tomato-crm.features.groups'))
        <div class="grid grid-cols-1 lg:grid-cols-4 gap-4 mb-3">
            @foreach($groups as $group)
                <div class="relative border border-gray-200 dark:bg-gray-800 dark:border-gray-700 p-4 rounded-lg bg-white @if(isset(request()->get('filter')['group_id']) && request()->get('filter')['group_id'] == $group->id) ring-2 ring-primary-500 @endif">
                    <x-splade-link :href="route('admin.groups.edit', $group->id)" modal class="absolute top-3 rtl:right-3 ltr:left-3 text-warning-500">
                        <i class="bx bx-edit"></i>
                    </x-splade-link>

                    <div @click.prevent="table.updateQuery('filter[group_id]', @js($group->id))" class="flex flex-col items-center justify-center cursor-pointer">
                        <i class="{{$group->icon}} bx-lg" style="color: {{$group->color}}"></i>
                        <h1 class="font-bold text-2xl">{{$group->name}}</h1>
                        <h1 class="text-gray-400 text-sm">{{$group->accounts()->count()}} {{__('Customer')}}</h1>
                    </div>
                </div>
            @endforeach
            <x-splade-link modal :href="route('admin.groups.create')" class="border border-gray-200 dark:border-gray-700 px-4 py-8 rounded-lg bg-primary-500 text-white flex flex-col items-center justify-center">
                <i class="bx bx-plus-circle bx-lg"></i>
                <h1 class="font-bold text-xl">{{__('Create New Group')}}</h1>
            </x-splade-link>
        </div>
    @endif
</x-slot:header>
```


# Jetstream & Fortify

<figure><img src="/files/a3DjyE7Wh0v5JR8XvaOG" alt=""><figcaption></figcaption></figure>

we now integrate Jetstream & Fortify inside our Tomato-Admin plugin so, we can use all features of Jetstream inside your app now.


# Upgrade

you can upgrade tomato-admin by using this command after using the composer update

```bash
php artisan tomato-admin:upgrade
```

after upgrade please use `yarn` to rebuild the frontend assets


# Get Started

Tomato PHP is a Full CRUD Generator for Splade & Breeze Starter Kit

## Install

to install this package you must have a full setup  [Splade](https://splade.dev/) package and it's [Breeze Starter Kit](https://splade.dev/docs/breeze)

```bash
composer require tomatophp/tomato-php
```

### Publish Config

you can publish config to change subs path

```
php artisan vendor:publish --tag=tomato-config 
```

and to publish the stubs folder you can use

```
php artisan vendor:publish --tag=tomato-stubs
```


# Use

it's straightforward to use our package by just creating a new migration and migrating it after your table and schema are ready to use this command

```
php artisan tomato:generate
```

it will ask you to input the table name and bingo you get the full CRUD ready.

### What is the file we are generating?

you build a full CRUD with some files like

* Controller \[app\Http\Controllers\Admin]
* Table \[app\Tables]
* Model \[app\Models]
* Views \[resources\views\admin\TABLE]
* Routes \[routes\web.php]


# Get Started

Plugins installer for Tomato PHP framework, and plugin generator

<figure><img src="/files/Buwaxxn9YuE2nfpKXsaX" alt=""><figcaption></figcaption></figure>

### Installation

```
composer require tomatophp/tomato-plugins
```

### Using

you can run this command to get all plugins from the Tomato Framework

```
php artisan tomato:plugins
```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-plugins/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Security

Please see [SECURITY](https://github.com/tomatophp/tomato-plugins/blob/master/SECURITY.md) for more information about the security.

### Credits

* [Fady Mondy](https://www.github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-plugins/blob/master/LICENSE.md) for more information.<br>


# Create New Plugin

from v1.2 you can create a new plugin by just using GUI it will generate a new module for you with a module.json file ready to use for our plugins system, and you can use our plugin generator feature to build a full migration and CRUD operation with GUI! without any code.

### Plugin Generator

to use the plugin generator feature make sure that you have install [`doctrine/dbal` ](https://github.com/doctrine/dbal)

### Add Required Plugins

you can add required plugins to make the plugin active only if the other module is active you can do that by adding the `required` to `module.json` file like this

```json
{
    "required": ['EcommerceTheme']
}
```


# Tomato Roles

ACL Roles / Permissions for TomatoPHP build with Splade build with Laravel-permission

<figure><img src="/files/q2nFB58zweHdX5KMAfpD" alt=""><figcaption></figcaption></figure>

{% embed url="<https://youtu.be/uXCIvN0Cszk>" %}

### Installation

```
composer require tomatophp/tomato-roles
```

or as Module

```
composer require tomatophp/tomato-roles-module
```

to make your model accept roles you must add this trait to it

```php
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;
}
```

after installation use this command to install the package and publish assets

```
php artisan tomato-roles:install
```

now you can access the `/admin` by using&#x20;

```bash
email: admin@admin.com
password: password
```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-roles/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Credits

* [Fady Mondy](https://www.github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-roles/blob/master/LICENSE.md) for more information.


# Use

### Using

you can use the package by GUI and you can generate new permission by setting the permission name to the route name after that use `tomato-roles.php` config to set the custom permission you need for this route when you add a new one you will get the new permission when you edit the role or add a new and the package will auto-create the permission for you.

if you need to build full resource permission when you use [Tomato Admin](https://github.com/queents/tomato-admin) you can use this command and it will auto-generate it for you

```bash
php artisan tomato:roles
```

and just gave it the name of the table.


# Developer Gate

we have a developer gate to ensure that only trusted developers can access the feature, it can be used to make some features only for the developer.

## How to use

we added some helpers to make it easy, so in your controller method you can use this helper to check if the user is a developer or not

```php
public function index(Request $request)
{
   if(is_developer()){
    //Do THIS
   }
   
   return developer_redirect();
}
```

and it will redirect it to enter the password of the developer and you change this password just from the config file.


# Register Permission

you can register any permission you need in the `AppServiceProvider` in the `register` method, it will be auto-registered when you open the create/edit role page.

```php
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        if(class_exists(TomatoRoles::class)){
            //Register Permission For Settings
            TomatoRoles::register(Permission::make()
                ->name('admin.settings.notifications.index')
                ->guard('web')
                ->group('settings')
            );
            TomatoRoles::register(Permission::make()
                ->name('admin.settings.notifications.store')
                ->guard('web')
                ->group('settings')
            );
        }
    }
}
```


# Config

you can publish a config file by using this command

```
php artisan vendor:publish --tag="tomato-roles-config"
```

you can publish views file by using this command

```
php artisan vendor:publish --tag="tomato-roles-views"
```

you can publish languages file by using this command

```
php artisan vendor:publish --tag="tomato-roles-lang"
```

you can publish migrations file by using this command

```
php artisan vendor:publish --tag="tomato-roles-migrations"
```

## Config File

```php
<?php

return [
    /*
     * Select Default Guard
     */
    "defaults" => [
        "guard" => "web",
    ],
    
    /*
     * Add Custom Permissions
     */
    "custom" => [
        "admin" => [
            "admin",
            "admin.lang",
            "admin.profile.edit",
            "admin.profile.update",
            "admin.profile.password",
            "admin.verification.notice",
            "admin.verification.verify",
            "admin.password.confirm",
            "admin.password.confirm.post",
            "admin.password.update",
            "admin.logout",
        ]
    ],
    
    /*
     * Set Developer Gate Password
     */
    'developer_password' => env('DEVELOPER_PASSWORD', "QTS@2022"),
];

```


# Tomato Locations

Database seeds for Locations plugin for TomatoPHP

<figure><img src="/files/Z0pLOyi9kVgUFITgRO22" alt=""><figcaption></figcaption></figure>

### Installation

```
composer require tomatophp/tomato-locations
```

or as Module

```
composer require tomatophp/tomato-locations-module
```

after install use this command to publish assets and generate permissions

```
php artisan tomato-locations:install
```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-locations/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Security

Please see [SECURITY](https://github.com/tomatophp/tomato-locations/blob/master/SECURITY.md) for more information about the security.

### Credits

* [Fady Mondy](https://www.github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-locations/blob/master/LICENSE.md) for more information.


# APIs

### Areas Endpoints

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/areas" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/areas/{model}" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

### Cite Endpoints

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/cities" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/cities/{model}" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

### Country Endpoints

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/countires" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/countires/{model}" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}


# Tomato Settings

Full Settings Generator / Manager with GUI for TomatoPHP build with Splade build with Laravel-settings

<figure><img src="/files/NXhGMZzkvYymq7dg1Ixh" alt=""><figcaption></figcaption></figure>

### Installation

```
composer require tomatophp/tomato-settings
```

or as Module

```
composer require tomatophp/tomato-settings-module
```

after installation use this command to install the package and publish assets

```
php artisan tomato-settings:install
```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-settings/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Credits

* [Queen Tech Solutions](https://github.com/queents)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-settings/blob/master/LICENSE.md) for more information.


# Use

you can generate a new setting for this package by using this command

```
php artisan tomato:setting
```

it will ask you for the setting name and if you like to put it inside a module as HMVC.

after running the command you must register the menu on the `tomato-admin` config or Module provider.


# Config

you can publish a config file by using this command

```
php artisan vendor:publish --tag="tomato-settings-config"
```

you can publish views file by using this command

```
php artisan vendor:publish --tag="tomato-settings-views"
```

you can publish languages file by using this command

```
php artisan vendor:publish --tag="tomato-settings-lang"
```

you can publish migrations file by using this command

```
php artisan vendor:publish --tag="tomato-settings-migrations"
```


# Tomato Notifications

Laravel Notifications Channel with GUI to send notifications with templates for TomatoPHP build with Splade

<figure><img src="/files/6x2PzlyRCbc3NLW6EYv2" alt=""><figcaption></figcaption></figure>

we are building a full notification system for you with multi-provider like mail, firebase, pusher, discord, slack, Messagebird and open the way to add more all of this working on the queue and have a lot of helpers to make it easy to use this notification on your system

### Installation

```bash
composer require tomatophp/tomato-notifications
```

or as Module

```
composer require tomatophp/tomato-notifications-module
```

after installation use this command to install the package and publish assets

```bash
php artisan tomato-notifications:install
```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-notifications/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Credits

* [Fady Mondy](https://github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-notifications/blob/master/LICENSE.md) for more information.


# Use

to set up any model to get notifications you

```php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
use TomatoPHP\TomatoNotifications\Traits\InteractWithNotifications;

class User extends Authenticatable
{
    use HasApiTokens;
    use HasFactory;
    use HasProfilePhoto;
    use Notifiable;
    use TwoFactorAuthenticatable;
    use HasRoles;
    use InteractWithNotifications;
    ...
```

and you must set the settings for FCM to get real-time notification

### Queue

the notification is run on queue, so you must run the queue worker to send the notifications

```bash
php artisan queue:work
```


# Notification Service

to create a new template you can use template CRUD and make sure that the template key is unique because you will use it on every single notification.

### Send Notification

to send a notification you must use our helper SendNotification::class like

```php
SendNotification::make($template->providers)
    ->template($template->key)
    ->findTitle($matchesTitle)
    ->replaceTitle($titleFill)
    ->findBody($matchesBody)
    ->replaceBody($titleBody)
    ->model(User::class)
    ->id(User::first()->id)
    ->privacy('private')
    ->fire();
```

where `$template` is selected of the template by key and $matchesTitle and $matchesBody is an array of matches to replace the template and $titleFill and $titleBody are an array of values to replace the matches


# Config

you can publish a config file by using this command

```
php artisan vendor:publish --tag="tomato-notifications-config"
```

you can publish views file by using this command

```
php artisan vendor:publish --tag="tomato-notifications-views"
```

you can publish languages file by using this command

```
php artisan vendor:publish --tag="tomato-notifications-lang"
```

you can publish migrations file by using this command

```
php artisan vendor:publish --tag="tomato-notifications-migrations"
```

## Config File

```php
<?php

use App\Models\User;

return [
    /*
     * Notifications types
     */
    'types' => [
        [
            "name" => "Alert",
            "id" => "alert",
            "color" => "#fff",
            "icon" => "bx bxs-user"
        ],
        [
            "name" => "Info",
            "id" => "info",
            "color" => "#fff",
            "icon" => "bx bxs-user"
        ],
        [
            "name" => "Danger",
            "id" => "danger",
            "color" => "#fff",
            "icon" => "bx bxs-user"
        ],
        [
            "name" => "Success",
            "id" => "success",
            "color" => "#fff",
            "icon" => "bx bxs-user"
        ],
        [
            "name" => "Warring",
            "id" => "warring",
            "color" => "#fff",
            "icon" => "bx bxs-user"
        ],
    ],

    /*
     * Main Provider
     */
    'provider' => "pusher",

    /*
     * Models Accept Notifications
     */
    'models' => [
        "Admins" => User::class,
    ],

    /*
     * Providers List
     */
    'providers' => [
        [
            "name" =>'Email',
            "id" => "email"
        ],
        [
            "name" =>'Slack',
            "id" => "slack",
        ],
        [
            "name" => 'Discord',
            "id" => "discord"
        ],
        [
            "name" => 'FCM Web',
            "id" => "fcm-web"
        ],
        [
            "name" => 'FCM Mobile',
            "id" => "fcm-api"
        ],
        [
            "name" => 'Pusher Web',
            "id" => "pusher-web"
        ],
        [
            "name" => 'Pusher Mobile',
            "id" => "pusher-api"
        ],
        [
            "name" => 'SMS MessageBird',
            "id" => "sms-messagebird"
        ]
    ],

    /*
     * Supported Languages
     */
    "lang" => [
        "ar" => "arabic",
        "en" => "english"
    ]
];

```


# APIs

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/notifications" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/notifications/clear" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/notifications/{id}/delete" method="delete" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/notifications/{id}/read" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/notifications/toggle" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}


# Tomato Category

manage category/tags/types for any model with splade/tomato PHP

<figure><img src="/files/S9SOzNlEBKzaisfzgi4y" alt=""><figcaption></figcaption></figure>

### Installation

```
composer require tomatophp/tomato-category
```

or as Module

```
composer require tomatophp/tomato-category-module
```

after installing your package please run this command

```
php artisan tomato-categories:install
```

### Support

you can join our discord server to get support [TomatoPHP](https://discord.gg/VZc8nBJ3ZU)

### Docs

you can check docs of this package on [Docs](https://docs.tomatophp.com/plugins/tomato-category)

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-category/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Security

Please see [SECURITY](https://github.com/tomatophp/tomato-category/blob/master/SECURITY.md) for more information about the security.

### Credits

* [Fady Mondy](https://www.github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-category/blob/master/LICENSE.md) for more information.


# Use

this plugin is a multi-use plugin, you can use a category to group things together and after that make a query with this group, as well as types, we all need types on our projects, like account type or status for orders, so you can just use this plugin to do this.


# Config

you can publish a config file by using this command

```
php artisan vendor:publish --tag="tomato-category-config"
```

you can publish views file by using this command

```
php artisan vendor:publish --tag="tomato-category-views"
```

you can publish languages file by using this command

```
php artisan vendor:publish --tag="tomato-category-lang"
```

you can publish migrations file by using this command

```
php artisan vendor:publish --tag="tomato-category-migrations"
```

## Config File

```php
<?php

return [
    /*
     * Types For
     * 
     * you may need a types for accounts and another for content
     */
    "for" => [
        "accounts"=> [
            "ar" => "الحسابات",
            "en" => "Accounts"
        ],
        "content"=> [
            "ar" => "المحتوي",
            "en" => "Content"
        ]
    ],
    
    /*
     * Types Of Type
     * 
     * it's a sub-type of type like account type or content type
     */
    "types" => [
        "type"=> [
            "ar" => "النوع",
            "en" => "Type"
        ],
        "status"=> [
            "ar" => "الحالة",
            "en" => "Status"
        ],
    ],
    
    
    /*
     * Features
     */
    "features" => [
        "category" => false,
        "types" => true
    ],
    
    /*
     * Category Middleware
     * 
     * you can add a middleware to the category APIs routes
     */
    "middleware" => [],
    
    /*
     * Category Resource
     * 
     * you can custom API resource for categories
     */
    "categories_resource" => null,
    
    /*
     * Types Resource
     * 
     * you can custom API resource for types
     */
    "types_resource" => null,
];

```


# APIs

### Categories Endpoint

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/categories" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/categories/{model}" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

### Types Endpoint

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/types" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/types/{model}" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}


# Tomato Forms

Build a full Forms with Fields on Database and save it to user meta

<figure><img src="/files/r6Y1JbZrqZYazEAB4b3f" alt=""><figcaption></figcaption></figure>

### Installation

<pre><code><strong>composer require tomatophp/tomato-forms
</strong></code></pre>

or as Module

```
composer require tomatophp/tomato-forms-module
```

after installation please run this command

```
php artisan tomato-forms:install
```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-forms/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Security

Please see [SECURITY](https://github.com/tomatophp/tomato-forms/blob/master/SECURITY.md) for more information about the security.

### Credits

* [Fady Mondy](https://www.github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-forms/blob/master/LICENSE.md) for more information.

<details>

<summary></summary>

</details>


# Use

if you have something like services and every service has a custom form, you can use this plugin to attach a form to this service.

or if you need a Contact Us form to view on your frontend website, you can use this plugin to create a form and attach it to a page.

## Tomato Form Component

you can use this component to view your form anywhere in your app like this

```html
 <x-tomato-form :form="$model" :default="['form_id'=>$model->id]" :action="route('admin.form-requests.store')"></x-tomato-form>
```


# Config

you can publish a config file by using this command

```
php artisan vendor:publish --tag="tomato-forms-config"
```

you can publish views file by using this command

```
php artisan vendor:publish --tag="tomato-forms-views"
```

you can publish languages file by using this command

```
php artisan vendor:publish --tag="tomato-forms-lang"
```

you can publish migrations file by using this command

```
php artisan vendor:publish --tag="tomato-forms-migrations"
```

## Config File

```php

<?php

return [
    /*
     * Supported Languages
     */
    "lang" => [
        "en" => "English",
        "ar" => "Arabic"
    ],
    
    
    /*
     * Resources for APIs
     */
    "index_resource" => null,
    "show_resource" => null,
    "requests_index_resource" => null,
    "requests_show_resource" => null,
    
    /*
     * Service Type class
     */
    "service_type" => null
];

```


# APIs

### From Endpoints

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/forms" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/forms/{model}" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

### From Requests Endpoints

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/form-requests" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/form-requests" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/form-requests/{model}" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}


# Tomato Menus

Menus manager to build your menus with json file or database provider

<figure><img src="/files/EDnQwaexO7Sg6XF6lfSK" alt=""><figcaption></figcaption></figure>

### Installation

```
composer require tomatophp/tomato-menus
```

or as Module

```
composer require tomatophp/tomato-menus-module
```

after installing your package please run this command

```
php artisan tomato-menus:install
```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-menus/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Security

Please see [SECURITY](https://github.com/tomatophp/tomato-menus/blob/master/SECURITY.md) for more information about security.

### Credits

* [Fady Mondy](https://github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-menus/blob/master/LICENSE.md) for more information.

<details>

<summary></summary>

</details>

<br>


# Use

you can use the menu provider on anywhere by our menu provider class it will return your menu anywhere on the app just use

```php
use TomatoPHP\TomatoMenus\Services\MenuRenderBase;

MenuRenderBase::menu($key, $by = 'key');
```

or you can use it with your tomato admin panel by setting the config of menu\_provider to be&#x20;

```php
"menu_provider" => TomatoPHP\TomatoMenus\Services\MenuRenderBase::class
```


# Config

### Publish Assets

you can publish a config file by using this command

```
php artisan vendor:publish --tag="tomato-menus-config"
```

you can publish view files by using this command

```
php artisan vendor:publish --tag="tomato-menus-views"
```

you can publish language files by using this command

```
php artisan vendor:publish --tag="tomato-menus-lang"
```

you can publish migration files by using this command

```
php artisan vendor:publish --tag="tomato-menus-migrations"
```


# Tomato CRM

manage category/tags/types for any model with splade/tomato PHP

<figure><img src="/files/ST7Rn3W3fktBLIoSt8Ib" alt=""><figcaption></figcaption></figure>

### Installation

```
composer require tomatophp/tomato-crm
```

or as Module

```
composer require tomatophp/tomato-crm-module
```

after installing your package please run this command

```
php artisan tomato-crm:install
```

Publish Account Model

you can publish your account model to add other relations or implement some interfaces by using this command

```bash
php artisan vendor:publish --tag="tomato-crm-model"
```

now go to your tomato-crm.php config file and change the model value to the new one.

### Add Accounts Guard

now you need to add a new guard to your auth.php config like this

```php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'accounts' => [
            'driver' => 'session',
            'provider' => 'accounts',
        ]
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
        'accounts' => [
            'driver' => 'eloquent',
            'model' => App\Models\Account::class,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expiry time is the number of minutes that each reset token will be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    | The throttle setting is the number of seconds a user must wait before
    | generating more password reset tokens. This prevents the user from
    | quickly generating a very large amount of password reset tokens.
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_reset_tokens',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */

    'password_timeout' => 10800,

];

```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-crm/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Security

Please see [SECURITY](https://github.com/tomatophp/tomato-crm/blob/master/SECURITY.md) for more information about the security.

### Credits

* [Fady Mondy](https://www.github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-crm/blob/master/LICENSE.md) for more information.


# Use

this plugin makes it easy to make a starting point for your app if this app has customers to manage

but here is the problem, every app has a different way of managing customers, so we built a Facade service to control the way you want to manage your customers

### How to use

just install the package and you will get everything working, it supports some features ready to use:

* Accounts
* Groups
* Locations
* Contact Us
* Send Notifications
* Auth APIs
* Send OTP Events

you can activate or deactivate any feature you want from the package config file.

### Use a custom form view to edit or create accounts

you can use your own create / update form for accounts, by just passing the view you when to this facade service method

```php
use TomatoPHP\TomatoCrm\Facades\TomatoCrm;

public function boot()
{
    TomatoCrm::create(form: 'accounts.form');
    TomatoCrm::edit(form: 'accounts.form');
}
```

## Custom create / edit validation

you can custom the validation rules for creating / editing accounts by just passing the rules you want to the facade service method

```php

use TomatoPHP\TomatoCrm\Facades\TomatoCrm;

public function boot()
{
    TomatoCrm::validation(
        create: [
            'email' => 'unique:accounts,email',
            'type_id' => 'required|integer|exists:types,id',
        ],
        edit: [
            'email' => 'sometimes|unique:accounts,email',
            'type_id' => 'sometimes|integer|exists:types,id',
        ],
        api_create: [
            'email' => 'unique:accounts,email',
            'type_id' => 'required|integer|exists:types,id',
        ],
        api_edit: [
            'email' => 'sometimes|unique:accounts,email',
            'type_id' => 'sometimes|integer|exists:types,id',
        ]
    );

}
```

by using this method you can custom the validation rules for creating / editing accounts on the web and APIs

## Attach New Field To Accounts

you can attach a new field to the accounts table by just passing the field name and the field type to the facade service method

```php

use TomatoPHP\TomatoCrm\Facades\TomatoCrm;

public function boot()
{
    TomatoCrm::attach(
        key: 'birthday',
        label: __('Birthday'),
        type: 'date',
        show_on_create: false,
        show_on_edit: false
    );
}
```

## Publish Model

you can publish the account model to your app by just running this command

```bash
php artisan vendor:publish --tag=tomato-crm-model
```


# Auth Builder

you can build multi-auth using the same accounts table in a very easy way, so we created a Facade class to help you do that.

### How to use

you just need to create 2 controllers `AuthController`, `ProfileController`

```php

use TomatoPHP\TomatoCrm\Services\Traits\Auth\Login;
use TomatoPHP\TomatoCrm\Services\Traits\Auth\Register;
use TomatoPHP\TomatoCrm\Services\Traits\Auth\Otp;
use TomatoPHP\TomatoCrm\Services\Traits\Auth\ResetPassword;

class AuthController extends Controller
{
    use Login;
    use Register;
    use Otp;
    use ResetPassword;
    
    public string $guard = 'web';
    public bool $otp = true;
    public string $model = Account::class;
    public string $loginBy = 'email';
    public string $loginType = 'email';
    public ?string $resource = null;

    public function __construct()
    {
        $this->guard = config('tomato-crm.guard');
        $this->otp = config('tomato-crm.required_otp');
        $this->model = config('tomato-crm.model');
        $this->loginBy = config('tomato-crm.login_by');
        $this->loginType = config('tomato-crm.login_by');
        $this->resource = config('tomato-crm.resource', null);
    }
```

and on your profile controller, you just need to use `Profile` traits

```php
use TomatoPHP\TomatoCrm\Services\Traits\Auth\Profile\User;
use TomatoPHP\TomatoCrm\Services\Traits\Auth\Profile\Update;
use TomatoPHP\TomatoCrm\Services\Traits\Auth\Profile\Delete;
use TomatoPHP\TomatoCrm\Services\Traits\Auth\Profile\Logout;

class ProfileController extends Controller
{
    use User;
    use Update;
    use Delete;
    use Logout;

    public string $guard = 'web';
    public bool $otp = true;
    public string $model = Account::class;
    public string $loginBy = 'email';
    public string $loginType = 'email';
    public ?string $resource = null;

    public function __construct()
    {
        $this->guard = config('tomato-crm.guard');
        $this->otp = config('tomato-crm.required_otp');
        $this->model = config('tomato-crm.model');
        $this->loginBy = config('tomato-crm.login_by');
        $this->loginType = config('tomato-crm.login_by');
        $this->resource = config('tomato-crm.resource', null);
    }
}
```


# Events

we have added a lot of events to the package, so you can listen to them and do what you want.

### OTP Event

```php
use TomatoPHP\TomatoCrm\Events\SendOTP;
use TomatoPHP\TomatoNotifications\Services\SendNotification;

public function register()
{
    Event::listen([
        SendOTP::class
    ], function ($data) {
        $user = $data->model::find($data->modelId);

        SendNotification::make(['email'])
            ->title('OTP')
            ->message('Your OTP is ' . $user->otp_code)
            ->type('info')
            ->database(false)
            ->model(Account::class)
            ->id($user->id)
            ->privacy('private')
            ->icon('bx bx-user')
            ->url(url('/'))
            ->fire();
    });
}
```

### Account Success Login Event

When the user logs in successfully, we fire this event.

```php
use TomatoPHP\TomatoCrm\Events\AccountLogged;

public function register()
{
    Event::listen([
        AccountLogged::class
    ], function ($data) {
        $user = $data->model::find($data->modelId);
        if($user->meta('is_admin_approve') !== 'yes'){
            return response()->json([
                "status" => false,
                "message" => __('your Account is activated. but you cannot login till admin approve.'),
            ], 400)->send();
        }
    });
}
```

### Account Registered Event

When the user registers successfully, we fire this event.

```php
use TomatoPHP\TomatoCrm\Events\AccountLogged;

public function register()
{
    Event::listen([
        AccountRegistered::class
    ], function ($data) {
        $user = $data->model::find($data->modelId);
        $user->last_login = Carbon::now();
        $user->save();
    });
}
```


# Config

you can publish a config file by using this command

```
php artisan vendor:publish --tag="tomato-crm-config"
```

you can publish views file by using this command

```
php artisan vendor:publish --tag="tomato-crm-views"
```

you can publish languages file by using this command

```
php artisan vendor:publish --tag="tomato-crm-lang"
```

you can publish migrations file by using this command

```
php artisan vendor:publish --tag="tomato-crm-migrations"
```

## Config File

```php
<?php

use Modules\Base\Transformers\AccountLoginResource;

return [
    /*
     * Features of Tomato CRM
     *
     * accounts: Enable/Disable Accounts Feature
     */
    "features" => [
        "accounts" => true,
        "groups" => true,
        "locations" => false,
        "contacts" => false,
        "activites" => false,
        "notifications" => true,
        "apis" => true,
        "send_otp" => true
    ],

    /*
     * Accounts Configurations
     *
     * resource: User Resource Class
     */
    "resource" => AccountLoginResource::class,

    /*
     * Accounts Configurations
     *
     * login_by: Login By Phone or Email
     */
    "login_by" => "email",

    /*
     * Accounts Configurations
     *
     * required_otp: Enable/Disable OTP Verification
     */
    "required_otp" => true,

    /*
     * Accounts Configurations
     *
     * model: User Model Class
     */
    "model" => \App\Models\Account::class,

    /*
     * Accounts Configurations
     *
     * guard: Auth Guard
     */
    "guard" => "accounts",


    "views" => [
        "accounts" => [
            "buttons" => null,
            "actions" => "base::accounts-actions",
        ]
    ],


    /*
     * Attachment Relations
     *
     * You can use this config to attach relation manager to the view accounts
     *
     * Example:
     *
     [
         "name" => "groups",
         "label" => [
           "ar" => "Group",
           "en" => "Group"
         ],
         "table" => \TomatoPHP\TomatoCrm\Tables\GroupTable::class,
         "view" => "tomato-crm::components.relations",
         "show" => true,
         "edit" => true,
         "delete" => true,
         "path" => "groups"
     ]
     */
    "relations" => [
        [
            "name" => "properties",
            "label" => [
                "ar" => "Properties",
                "en" => "Properties"
            ],
            "table" => \Modules\Unites\Tables\PropertyTable::class,
            "view" => null,
            "show" => true,
            "edit" => true,
            "delete" => true,
            "path" => "properties"
        ]
    ]
];
```


# APIs

you can show the APIs Endpoints here

you can activate this feature or stop it from the config file and use your own routes or your own controllers.

to make this endpoint work fine you need to add a custom gruid inside `/config/auth.php` to be like this

```php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'accounts' => [
            'driver' => 'session',
            'provider' => 'accounts',
        ]
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
        'accounts' => [
            'driver' => 'eloquent',
            'model' => \TomatoPHP\TomatoCrm\Models\Account::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expiry time is the number of minutes that each reset token will be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    | The throttle setting is the number of seconds a user must wait before
    | generating more password reset tokens. This prevents the user from
    | quickly generating a very large amount of password reset tokens.
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_reset_tokens',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */

    'password_timeout' => 10800,

];

```

### Auth Endpoints

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/login" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/register" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/reset" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/resend" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/otp" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/otp-check" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/password" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

### Profile Endpoints

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/profile" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/profile" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/profile/password" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/profile/destroy" method="delete" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/profile/logout" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}


# Tomato Wallet

Account Wallet Manager & Payment Integrations For TomatoPHP and TomatoCRM

<figure><img src="/files/OM0kbEPrI5wIGYMtzh3u" alt=""><figcaption></figcaption></figure>

## Installation

```bash
composer require tomatophp/tomato-wallet
```

or as Module

```
composer require tomatophp/tomato-wallet-module
```

after installing your package please run this command

```bash
php artisan tomato-wallet:install
```

## Changelog

Please see [CHANGELOG](https://github.com/tomatophp/docs/blob/master/plugins/tomato-wallet/CHANGELOG.md) for more information on what has changed recently.

## Security

Please see [SECURITY](https://github.com/tomatophp/docs/blob/master/plugins/tomato-wallet/SECURITY.md) for more information about security.

## Credits

* [Tomatophp](mailto:info@3x1.io)

## License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/docs/blob/master/plugins/tomato-wallet/LICENSE.md) for more information.


# Use

you can start using your wallet very easily by checking these [docs](https://github.com/bavix/laravel-wallet).

## Start using Payments

> you can create your own custom drivers if it does not exist in the list, read the `Create custom drivers` section.

In the config file, you can set the `default driver` to use for all your payments. But you can also change the driver at runtime.

Choose what gateway you would like to use in your application. Then make that as the default driver so that you don't have to specify that everywhere. But, you can also use multiple gateways in a project.

```php
// Eg. if you want to use zarinpal.
'default' => 'zarinpal',
```

Then fill the credentials for that gateway in the drivers array.

```php
'drivers' => [
    'zarinpal' => [
        // Fill in the credentials here.
        'apiPurchaseUrl' => 'https://www.zarinpal.com/pg/rest/WebGate/PaymentRequest.json',
        'apiPaymentUrl' => 'https://www.zarinpal.com/pg/StartPay/',
        'apiVerificationUrl' => 'https://www.zarinpal.com/pg/rest/WebGate/PaymentVerification.json',
        'merchantId' => '',
        'callbackUrl' => 'http://yoursite.com/path/to',
        'description' => 'payment in '.config('app.name'),
    ],
    ...
]
```

your `Invoice` holds your payment details, so initially we'll talk about `Invoice` class.

#### Working with invoices

before doing any thing you need to use `Invoice` class to create an invoice.

In your code, use it like the below:

```php
// At the top of the file.
use TomatoPHP\TomatoWallet\Invoice;
...

// Create new invoice.
$invoice = new Invoice;

// Set invoice amount.
$invoice->amount(1000);

// Add invoice details: There are 4 syntax available for this.
// 1
$invoice->detail(['detailName' => 'your detail goes here']);
// 2 
$invoice->detail('detailName','your detail goes here');
// 3
$invoice->detail(['name1' => 'detail1','name2' => 'detail2']);
// 4
$invoice->detail('detailName1','your detail1 goes here')
        ->detail('detailName2','your detail2 goes here');

```

available methods:

* `uuid`: set the invoice's unique ID
* `getUuid`: retrieve the invoice's current unique ID
* `detail`: attach some custom details to the invoice
* `getDetails`: retrieve all custom details
* `amount`: set the invoice amount
* `getAmount`: retrieve invoice amount
* `transactionId`: set invoice payment transaction ID
* `getTransactionId`: retrieve payment transaction id
* `via`: set up a driver we use to pay the invoice
* `getDriver`: retrieve the driver

#### Purchase invoice

In order to pay the invoice, we need the payment transaction. We purchased the invoice to retrieve the transaction id:

```php
// At the top of the file.
use TomatoPHP\TomatoWallet\Invoice;
use TomatoPHP\TomatoWallet\Facade\Payment;
...

// Create new invoice.
$invoice = (new Invoice)->amount(1000);

// Purchase the given invoice.
Payment::purchase($invoice,function($driver, $transactionId) {
	// We can store $transactionId in database.
});

// Purchase method accepts a callback function.
Payment::purchase($invoice, function($driver, $transactionId) {
    // We can store $transactionId in database.
});

// You can specify callbackUrl
Payment::callbackUrl('http://yoursite.com/verify')->purchase(
    $invoice, 
    function($driver, $transactionId) {
    	// We can store $transactionId in database.
	}
);
```

#### Pay Invoice

After purchasing the invoice, we can redirect the user to the bank payment page:

```php
// At the top of the file.
use TomatoPHP\TomatoWallet\Invoice;
use TomatoPHP\TomatoWallet\Facade\Payment;
...

// Create new invoice.
$invoice = (new Invoice)->amount(1000);
// Purchase and pay the given invoice.
// You should use return statement to redirect user to the bank page.
return Payment::purchase($invoice, function($driver, $transactionId) {
    // Store transactionId in database as we need it to verify payment in the future.
})->pay()->render();

// Do all things together in a single line.
return Payment::purchase(
    (new Invoice)->amount(1000), 
    function($driver, $transactionId) {
    	// Store transactionId in database.
        // We need the transactionId to verify payment in the future.
	}
)->pay()->render();

// Retrieve json format of Redirection (in this case you can handle redirection to bank gateway)
return Payment::purchase(
    (new Invoice)->amount(1000), 
    function($driver, $transactionId) {
    	// Store transactionId in database.
        // We need the transactionId to verify payment in the future.
	}
)->pay()->toJson();
```

#### Verify payment

When the user has completed the payment, the bank redirects them to your website, then you need to **verify your payment** in order to ensure the `invoice` has been **paid**.

```php
// At the top of the file.
use TomatoPHP\TomatoWallet\Facade\Payment;
use TomatoPHP\TomatoWallet\Exceptions\InvalidPaymentException;
...

// You need to verify the payment to ensure the invoice has been paid successfully.
// We use transaction id to verify payments
// It is a good practice to add invoice amount as well.
try {
	$receipt = Payment::amount(1000)->transactionId($transaction_id)->verify();

    // You can show payment referenceId to the user.
    echo $receipt->getReferenceId();

    ...
} catch (InvalidPaymentException $exception) {
    /**
    	when payment is not verified, it will throw an exception.
    	We can catch the exception to handle invalid payments.
    	getMessage method, returns a suitable message that can be used in user interface.
    **/
    echo $exception->getMessage();
}
```

#### Useful methods

* **`callbackUrl`: can be used to change callbackUrl on the runtime.**

  ```php
  // At the top of the file.
  use TomatoPHP\TomatoWallet\Invoice;
  use TomatoPHP\TomatoWallet\Facade\Payment;
  ...

  // Create new invoice.
  $invoice = (new Invoice)->amount(1000);

  // Purchase the given invoice.
  Payment::callbackUrl($url)->purchase(
      $invoice, 
      function($driver, $transactionId) {
      // We can store $transactionId in database.
  	}
  );
  ```
* **`amount`: you can set the invoice amount directly**

  ```php
  // At the top of the file.
  use TomatoPHP\TomatoWallet\Invoice;
  use TomatoPHP\TomatoWallet\Facade\Payment;
  ...

  // Purchase (we set invoice to null).
  Payment::callbackUrl($url)->amount(1000)->purchase(
      null, 
      function($driver, $transactionId) {
      // We can store $transactionId in database.
  	}
  );
  ```
* **`via`: change driver on the fly**

  ```php
  // At the top of the file.
  use TomatoPHP\TomatoWallet\Invoice;
  use TomatoPHP\TomatoWallet\Facade\Payment;
  ...

  // Create new invoice.
  $invoice = (new Invoice)->amount(1000);

  // Purchase the given invoice.
  Payment::via('driverName')->purchase(
      $invoice, 
      function($driver, $transactionId) {
      // We can store $transactionId in database.
  	}
  );
  ```
* **`config`: set driver configs on the fly**

  ```php
  // At the top of the file.
  use TomatoPHP\TomatoWallet\Invoice;
  use TomatoPHP\TomatoWallet\Facade\Payment;
  ...

  // Create new invoice.
  $invoice = (new Invoice)->amount(1000);

  // Purchase the given invoice with custom driver configs.
  Payment::config('mechandId', 'your mechand id')->purchase(
      $invoice,
      function($driver, $transactionId) {
      // We can store $transactionId in database.
  	}
  );

  // Also we can change multiple configs at the same time.
  Payment::config(['key1' => 'value1', 'key2' => 'value2'])->purchase(
      $invoice,
      function($driver, $transactionId) {
      // We can store $transactionId in database.
  	}
  );
  ```

#### Create custom drivers:

First you have to add the name of your driver, in the drivers array and also you can specify any config parameters you want.

```php
'drivers' => [
    'zarinpal' => [...],
    'my_driver' => [
        ... // Your Config Params here.
    ]
]
```

Now you have to create a Driver Map Class that will be used to pay invoices. In your driver, You just have to extend `TomatoPHP\TomatoWallet\Abstracts\Driver`.

Eg. You created a class: `App\Packages\PaymentDriver\MyDriver`.

```php
namespace App\Packages\PaymentDriver;

use TomatoPHP\TomatoWallet\Abstracts\Driver;
use TomatoPHP\TomatoWallet\Exceptions\InvalidPaymentException;
use TomatoPHP\TomatoWallet\{Contracts\ReceiptInterface, Invoice, Receipt};

class MyDriver extends Driver
{
    protected $invoice; // Invoice.

    protected $settings; // Driver settings.

    public function __construct(Invoice $invoice, $settings)
    {
        $this->invoice($invoice); // Set the invoice.
        $this->settings = (object) $settings; // Set settings.
    }

    // Purchase the invoice, save its transactionId and finaly return it.
    public function purchase() {
        // Request for a payment transaction id.
        ...
            
        $this->invoice->transactionId($transId);
        
        return $transId;
    }
    
    // Redirect into bank using transactionId, to complete the payment.
    public function pay() {
        // It is better to set bankApiUrl in config/payment.php and retrieve it here:
        $bankUrl = $this->settings->bankApiUrl; // bankApiUrl is the config name.

        // Prepare payment url.
        $payUrl = $bankUrl.$this->invoice->getTransactionId();

        // Redirect to the bank.
        return redirect()->to($payUrl);
    }
    
    // Verify the payment (we must verify to ensure that user has paid the invoice).
    public function verify(): ReceiptInterface {
        $verifyPayment = $this->settings->verifyApiUrl;
        
        $verifyUrl = $verifyPayment.$this->invoice->getTransactionId();
        
        ...
        
        /**
			Then we send a request to $verifyUrl and if payment is not valid we throw an InvalidPaymentException with a suitable message.
        **/
        throw new InvalidPaymentException('a suitable message');
        
        /**
        	We create a receipt for this payment if everything goes normally.
        **/
        return new Receipt('driverName', 'payment_receipt_number');
    }
}
```

Once you create that class you have to specify it in the `payment.php` config file `map` section.

```php
'map' => [
    ...
    'my_driver' => App\Packages\PaymentDriver\MyDriver::class,
]
```

**Note:-** You have to make sure that the key of the `map` array is identical to the key of the `drivers` array.

#### Events

You can listen for 2 events

* **InvoicePurchasedEvent**: Occurs when an invoice is purchased (after purchasing invoice is done successfully).
* **InvoiceVerifiedEvent**: This occurs when an invoice is verified successfully.


# Payment Methods

* [asanpardakht](https://asanpardakht.ir/) :heavy\_check\_mark:
* [atipay](https://www.atipay.net/) :heavy\_check\_mark:
* [behpardakht (mellat)](http://www.behpardakht.com/) :heavy\_check\_mark:
* [digipay](https://www.mydigipay.com/) :heavy\_check\_mark:
* [idpay](https://idpay.ir/) :heavy\_check\_mark:
* [irankish](http://irankish.com/) :heavy\_check\_mark:
* [nextpay](https://nextpay.ir/) :heavy\_check\_mark:
* [parsian](https://www.pec.ir/) :heavy\_check\_mark:
* [pasargad](https://bpi.ir/) :heavy\_check\_mark:
* [payir](https://pay.ir/) :heavy\_check\_mark:
* [paypal](http://www.paypal.com/) (will be added soon in next version)
* [payping](https://www.payping.ir/) :heavy\_check\_mark:
* [paystar](http://paystar.ir/) :heavy\_check\_mark:
* [poolam](https://poolam.ir/) :heavy\_check\_mark:
* [sadad (melli)](https://sadadpsp.ir/) :heavy\_check\_mark:
* [saman](https://www.sep.ir) :heavy\_check\_mark:
* [sepehr (saderat)](https://www.sepehrpay.com/) :heavy\_check\_mark:
* [yekpay](https://yekpay.com/) :heavy\_check\_mark:
* [zarinpal](https://www.zarinpal.com/) :heavy\_check\_mark:
* [zibal](https://www.zibal.ir/) :heavy\_check\_mark:
* [sepordeh](https://sepordeh.com/) :heavy\_check\_mark:
* [sizpay](https://www.sizpay.ir/) :heavy\_check\_mark:
* Others are under way.

**Help me to add the gateways below by creating `pull requests`**

* stripe
* authorize
* 2checkout
* braintree
* skrill
* payU
* amazon payments
* wepay
* payoneer
* paysimple


# Config

you can publish config file by use this command

```bash
php artisan vendor:publish --tag="tomato-wallet-config"
```

you can publish views file by use this command

```bash
php artisan vendor:publish --tag="tomato-wallet-views"
```

you can publish languages file by use this command

```bash
php artisan vendor:publish --tag="tomato-wallet-lang"
```

you can publish migrations file by use this command

```bash
php artisan vendor:publish --tag="tomato-wallet-migrations"
```

## Config File

```php
<?php

return [
    /*
|--------------------------------------------------------------------------
| Default Driver
|--------------------------------------------------------------------------
|
| This value determines which of the following gateway to use.
| You can switch to a different driver at runtime.
|
*/
    'default' => 'zarinpal',

    /*
    |--------------------------------------------------------------------------
    | List of Drivers
    |--------------------------------------------------------------------------
    |
    | These are the list of drivers to use for this package.
    | You can change the name. Then you'll have to change
    | it in the map array too.
    |
    */
    'drivers' => [
        'local' => [
            'callbackUrl' => '/callback',
            'title' => 'درگاه پرداخت تست',
            'description' => 'این درگاه *صرفا* برای تست صحت روند پرداخت و لغو پرداخت میباشد',
            'orderLabel' => 'شماره سفارش',
            'amountLabel' => 'مبلغ قابل پرداخت',
            'payButton' => 'پرداخت موفق',
            'cancelButton' => 'پرداخت ناموفق',
        ],
        'fanavacard' => [
            'baseUri' => 'https://fcp.shaparak.ir',
            'apiPaymentUrl' => '_ipgw_//payment/',
            'apiPurchaseUrl' => 'ref-payment/RestServices/mts/generateTokenWithNoSign/',
            'apiVerificationUrl' => 'ref-payment/RestServices/mts/verifyMerchantTrans/',
            'apiReverseAmountUrl' => 'ref-payment/RestServices/mts/reverseMerchantTrans/',
            'username' => 'xxxxxxx',
            'password' => 'xxxxxxx',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'atipay' => [
            'atipayTokenUrl' => 'https://mipg.atipay.net/v1/get-token',
            'atipayRedirectGatewayUrl' => 'https://mipg.atipay.net/v1/redirect-to-gateway',
            'atipayVerifyUrl' => 'https://mipg.atipay.net/v1/verify-payment',
            'apikey' => '',
            'currency' => 'R', //Can be R, T (Rial, Toman)
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using Atipay',
        ],
        'asanpardakht' => [
            'apiPaymentUrl' => 'https://asan.shaparak.ir',
            'apiRestPaymentUrl' => 'https://ipgrest.asanpardakht.ir/v1/',
            'username' => '',
            'password' => '',
            'merchantConfigID' => '',
            'currency' => 'T', //Can be R, T (Rial, Toman)
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using asanpardakht',
        ],
        'behpardakht' => [
            'apiPurchaseUrl' => 'https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl',
            'apiPaymentUrl' => 'https://bpm.shaparak.ir/pgwchannel/startpay.mellat',
            'apiVerificationUrl' => 'https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl',
            'terminalId' => '',
            'username' => '',
            'password' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using behpardakht',
            'currency' => 'T', //Can be R, T (Rial, Toman)
            'cumulativeDynamicPayStatus' => false,
        ],
        'digipay' => [
            'apiOauthUrl' => 'https://api.mydigipay.com/digipay/api/oauth/token',
            'apiPurchaseUrl' => 'https://api.mydigipay.com/digipay/api/businesses/ticket?type=0',
            'apiPaymentUrl' => 'https://api.mydigipay.com/digipay/api/purchases/ipg/pay/',
            'apiVerificationUrl' => 'https://api.mydigipay.com/digipay/api/purchases/verify/',
            'username' => 'username',
            'password' => 'password',
            'client_id' => '',
            'client_secret' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'currency' => 'R', //Can be R, T (Rial, Toman)
        ],
        'etebarino' => [
            'apiPurchaseUrl' => 'https://api.etebarino.com/public/merchant/request-payment',
            'apiPaymentUrl' => 'https://panel.etebarino.com/gateway/public/ipg',
            'apiVerificationUrl' => 'https://api.etebarino.com/public/merchant/verify-payment',
            'merchantId' => '',
            'terminalId' => '',
            'username' => '',
            'password' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using etebarino',
        ],
        'idpay' => [
            'apiPurchaseUrl' => 'https://api.idpay.ir/v1.1/payment',
            'apiPaymentUrl' => 'https://idpay.ir/p/ws/',
            'apiSandboxPaymentUrl' => 'https://idpay.ir/p/ws-sandbox/',
            'apiVerificationUrl' => 'https://api.idpay.ir/v1.1/payment/verify',
            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using idpay',
            'sandbox' => false, // set it to true for test environments
            'currency' => 'R', //Can be R, T (Rial, Toman)
        ],
        'irankish' => [
            'apiPurchaseUrl' => 'https://ikc.shaparak.ir/api/v3/tokenization/make',
            'apiPaymentUrl' => 'https://ikc.shaparak.ir/iuiv3/IPG/Index/',
            'apiVerificationUrl' => 'https://ikc.shaparak.ir/api/v3/confirmation/purchase',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using irankish',
            'terminalId' => '',
            'password' => '',
            'acceptorId' => '',
            'pubKey' => '',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'nextpay' => [
            'apiPurchaseUrl' => 'https://nextpay.org/nx/gateway/token',
            'apiPaymentUrl' => 'https://nextpay.org/nx/gateway/payment/',
            'apiVerificationUrl' => 'https://nextpay.org/nx/gateway/verify',
            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using nextpay',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'omidpay' => [
            'apiGenerateTokenUrl' => 'https://ref.sayancard.ir/ref-payment/RestServices/mts/generateTokenWithNoSign/',
            'apiPaymentUrl' => 'https://say.shaparak.ir/_ipgw_/MainTemplate/payment/',
            'apiVerificationUrl' => 'https://ref.sayancard.ir/ref-payment/RestServices/mts/verifyMerchantTrans/',
            'username' => '',
            'merchantId' => '',
            'password' => '',
            'callbackUrl' => '',
            'description' => 'payment using omidpay',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'parsian' => [
            'apiPurchaseUrl' => 'https://pec.shaparak.ir/NewIPGServices/Sale/SaleService.asmx?wsdl',
            'apiPaymentUrl' => 'https://pec.shaparak.ir/NewIPG/',
            'apiVerificationUrl' => 'https://pec.shaparak.ir/NewIPGServices/Confirm/ConfirmService.asmx?wsdl',
            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using parsian',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'pasargad' => [
            'apiPaymentUrl' => 'https://pep.shaparak.ir/payment.aspx',
            'apiGetToken' => 'https://pep.shaparak.ir/Api/v1/Payment/GetToken',
            'apiCheckTransactionUrl' => 'https://pep.shaparak.ir/Api/v1/Payment/CheckTransactionResult',
            'apiVerificationUrl' => 'https://pep.shaparak.ir/Api/v1/Payment/VerifyPayment',
            'merchantId' => '',
            'terminalCode' => '',
            'certificate' => '', // can be string (and set certificateType to xml_string) or an xml file path (and set cetificateType to xml_file)
            'certificateType' => 'xml_file', // can be: xml_file, xml_string
            'callbackUrl' => 'http://yoursite.com/path/to',
            'currency' => 'R', //Can be R, T (Rial, Toman)
        ],
        'payir' => [
            'apiPurchaseUrl' => 'https://pay.ir/pg/send',
            'apiPaymentUrl' => 'https://pay.ir/pg/',
            'apiVerificationUrl' => 'https://pay.ir/pg/verify',
            'merchantId' => 'test', // set it to `test` for test environments
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using payir',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'paypal' => [
            /* normal api */
            'apiPurchaseUrl' => 'https://www.paypal.com/cgi-bin/webscr',
            'apiPaymentUrl' => 'https://www.zarinpal.com/pg/StartPay/',
            'apiVerificationUrl' => 'https://ir.zarinpal.com/pg/services/WebGate/wsdl',

            /* sandbox api */
            'sandboxApiPurchaseUrl' => 'https://www.sandbox.paypal.com/cgi-bin/webscr',
            'sandboxApiPaymentUrl' => 'https://sandbox.zarinpal.com/pg/StartPay/',
            'sandboxApiVerificationUrl' => 'https://sandbox.zarinpal.com/pg/services/WebGate/wsdl',

            'mode' => 'normal', // can be normal, sandbox
            'currency' => '',
            'id' => '', // Specify the email of the PayPal Business account
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using paypal',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'payping' => [
            'apiPurchaseUrl' => 'https://api.payping.ir/v2/pay/',
            'apiPaymentUrl' => 'https://api.payping.ir/v2/pay/gotoipg/',
            'apiVerificationUrl' => 'https://api.payping.ir/v2/pay/verify/',
            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using payping',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'paystar' => [
            'apiPurchaseUrl' => 'https://core.paystar.ir/api/pardakht/create/',
            'apiPaymentUrl' => 'https://core.paystar.ir/api/pardakht/payment/',
            'apiVerificationUrl' => 'https://core.paystar.ir/api/pardakht/verify/',
            'gatewayId' => '', // your gateway id
            'signKey' => '', // sign key of your gateway
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using paystar',
            'currency' => 'R', //Can be R, T (Rial, Toman)
        ],
        'poolam' => [
            'apiPurchaseUrl' => 'https://poolam.ir/invoice/request/',
            'apiPaymentUrl' => 'https://poolam.ir/invoice/pay/',
            'apiVerificationUrl' => 'https://poolam.ir/invoice/check/',
            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using poolam',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'sadad' => [
            'apiPaymentByMultiIdentityUrl' => 'https://sadad.shaparak.ir/VPG/api/v0/PaymentByMultiIdentityRequest',
            'apiPaymentByIdentityUrl' => 'https://sadad.shaparak.ir/api/v0/PaymentByIdentity/PaymentRequest',
            'apiPaymentUrl' => 'https://sadad.shaparak.ir/api/v0/Request/PaymentRequest',
            'apiPurchaseUrl' => 'https://sadad.shaparak.ir/Purchase',
            'apiVerificationUrl' => 'https://sadad.shaparak.ir/VPG/api/v0/Advice/Verify',
            'key' => '',
            'merchantId' => '',
            'terminalId' => '',
            'callbackUrl' => '',
            'currency' => 'T', //Can be R, T (Rial, Toman)
            'mode' => 'normal', // can be normal, PaymentByIdentity, PaymentByMultiIdentity,
            'PaymentIdentity' => '',
            'MultiIdentityRows' => [
                [
                    "IbanNumber" => '', // Sheba number (with IR)
                    "Amount" => 0,
                    "PaymentIdentity" => '',
                ],
            ],
            'description' => 'payment using sadad',
        ],
        'saman' => [
            'apiPurchaseUrl' => 'https://sep.shaparak.ir/Payments/InitPayment.asmx?WSDL',
            'apiPaymentUrl' => 'https://sep.shaparak.ir/payment.aspx',
            'apiVerificationUrl' => 'https://sep.shaparak.ir/payments/referencepayment.asmx?WSDL',
            'merchantId' => '',
            'callbackUrl' => '',
            'description' => 'payment using saman',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'sep' => [
            'apiGetToken' => 'https://sep.shaparak.ir/onlinepg/onlinepg',
            'apiPaymentUrl' => 'https://sep.shaparak.ir/OnlinePG/OnlinePG',
            'apiVerificationUrl' => 'https://sep.shaparak.ir/verifyTxnRandomSessionkey/ipg/VerifyTransaction',
            'terminalId' => '',
            'callbackUrl' => '',
            'description' => 'Saman Electronic Payment for Saderat & Keshavarzi',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'sepehr' => [
            'apiGetToken' => 'https://mabna.shaparak.ir:8081/V1/PeymentApi/GetToken',
            'apiPaymentUrl' => 'https://mabna.shaparak.ir:8080/pay',
            'apiVerificationUrl' => 'https://mabna.shaparak.ir:8081/V1/PeymentApi/Advice',
            'terminalId' => '',
            'callbackUrl' => '',
            'description' => 'payment using sepehr(saderat)',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'walleta' => [
            'apiPurchaseUrl' => 'https://cpg.walleta.ir/payment/request.json',
            'apiPaymentUrl' => 'https://cpg.walleta.ir/ticket/',
            'apiVerificationUrl' => 'https://cpg.walleta.ir/payment/verify.json',
            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using walleta',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'yekpay' => [
            'apiPurchaseUrl' => 'https://gate.yekpay.com/api/payment/server?wsdl',
            'apiPaymentUrl' => 'https://gate.yekpay.com/api/payment/start/',
            'apiVerificationUrl' => 'https://gate.yekpay.com/api/payment/server?wsdl',
            'fromCurrencyCode' => 978,
            'toCurrencyCode' => 364,
            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using yekpay',
        ],
        'zarinpal' => [
            /* normal api */
            'apiPurchaseUrl' => 'https://api.zarinpal.com/pg/v4/payment/request.json',
            'apiPaymentUrl' => 'https://www.zarinpal.com/pg/StartPay/',
            'apiVerificationUrl' => 'https://api.zarinpal.com/pg/v4/payment/verify.json',

            /* sandbox api */
            'sandboxApiPurchaseUrl' => 'https://sandbox.zarinpal.com/pg/services/WebGate/wsdl',
            'sandboxApiPaymentUrl' => 'https://sandbox.zarinpal.com/pg/StartPay/',
            'sandboxApiVerificationUrl' => 'https://sandbox.zarinpal.com/pg/services/WebGate/wsdl',

            /* zarinGate api */
            'zaringateApiPurchaseUrl' => 'https://ir.zarinpal.com/pg/services/WebGate/wsdl',
            'zaringateApiPaymentUrl' => 'https://www.zarinpal.com/pg/StartPay/:authority/ZarinGate',
            'zaringateApiVerificationUrl' => 'https://ir.zarinpal.com/pg/services/WebGate/wsdl',

            'mode' => 'normal', // can be normal, sandbox, zaringate
            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using zarinpal',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'zibal' => [
            /* normal api */
            'apiPurchaseUrl' => 'https://gateway.zibal.ir/v1/request',
            'apiPaymentUrl' => 'https://gateway.zibal.ir/start/',
            'apiVerificationUrl' => 'https://gateway.zibal.ir/v1/verify',

            'mode' => 'normal', // can be normal, direct

            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using zibal',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'sepordeh' => [
            'apiPurchaseUrl' => 'https://sepordeh.com/merchant/invoices/add',
            'apiPaymentUrl' => 'https://sepordeh.com/merchant/invoices/pay/id:',
            'apiDirectPaymentUrl' => 'https://sepordeh.com/merchant/invoices/pay/automatic:true/id:',
            'apiVerificationUrl' => 'https://sepordeh.com/merchant/invoices/verify',
            'mode' => 'normal', // can be normal, direct
            'merchantId' => '',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'description' => 'payment using sepordeh',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'rayanpay' => [
            'apiPurchaseUrl' => 'https://bpm.shaparak.ir/pgwchannel/startpay.mellat',
            'apiTokenUrl' => 'https://pms.rayanpay.com/api/v1/auth/token/generate',
            'apiPayStart' => 'https://pms.rayanpay.com/api/v1/ipg/payment/start',
            'apiPayVerify' => 'https://pms.rayanpay.com/api/v1/ipg/payment/response/parse',
            'username' => '',
            'client_id' => '',
            'password' => '',
            'callbackUrl' => '',
            'currency' => 'R', //Can be R, T (Rial, Toman)
        ],
        'sizpay' => [
            'apiPurchaseUrl' => 'https://rt.sizpay.ir/KimiaIPGRouteService.asmx?WSDL',
            'apiPaymentUrl' => 'https://rt.sizpay.ir/Route/Payment',
            'apiVerificationUrl' => 'https://rt.sizpay.ir/KimiaIPGRouteService.asmx?WSDL',
            'merchantId' => '',
            'terminal' => '',
            'username' => '',
            'password' => '',
            'SignData' => '',
            'callbackUrl' => '',
            'currency' => 'R', //Can be R, T (Rial, Toman)
        ],
        'vandar' => [
            'apiPurchaseUrl' => 'https://ipg.vandar.io/api/v3/send',
            'apiPaymentUrl' => 'https://ipg.vandar.io/v3/',
            'apiVerificationUrl' => 'https://ipg.vandar.io/api/v3/verify',
            'callbackUrl' => '',
            'merchantId' => '',
            'description' => 'payment using Vandar',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'aqayepardakht' => [
            'apiPurchaseUrl' => 'https://panel.aqayepardakht.ir/api/v2/create',
            'apiPaymentUrl' => 'https://panel.aqayepardakht.ir/startpay/',
            'apiPaymentUrlSandbox' => 'https://panel.aqayepardakht.ir/startpay/sandbox/',
            'apiVerificationUrl' => 'https://panel.aqayepardakht.ir/api/v2/verify',
            'mode' => 'normal', //normal | sandbox
            'callbackUrl' => '',
            'pin' => '',
            'invoice_id' => '',
            'mobile' => '',
            'email' => '',
            'description' => 'payment using Aqayepardakht',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ],
        'azki' => [
            'apiPaymentUrl' => 'https://api.azkivam.com',
            'callbackUrl' => 'http://yoursite.com/path/to',
            'fallbackUrl' => 'http://yoursite.com/path/to',
            'merchantId' => '',
            'key' => '',
            'currency' => 'T', //Can be R, T (Rial, Toman)
            'description' => 'payment using azki',
        ],
        'payfa' => [
            'apiPurchaseUrl' => 'https://payment.payfa.com/v2/api/Transaction/Request',
            'apiPaymentUrl' => 'https://payment.payfa.ir/v2/api/Transaction/Pay/',
            'apiVerificationUrl' => 'https://payment.payfa.com/v2/api/Transaction/Verify/',
            'callbackUrl' => '',
            'apiKey' => '',
            'currency' => 'T', //Can be R, T (Rial, Toman)
        ]
    ],

    /*
    |--------------------------------------------------------------------------
    | Class Maps
    |--------------------------------------------------------------------------
    |
    | This is the array of Classes that maps to Drivers above.
    | You can create your own driver if you like and add the
    | config in the drivers array and the class to use for
    | here with the same name. You will have to extend
    | TomatoPHP\TomatoWallet\Abstracts\Driver in your driver.
    |
    */
    'map' => [
        'local' => \TomatoPHP\TomatoWallet\Drivers\Local\Local::class,
        'fanavacard' => \TomatoPHP\TomatoWallet\Drivers\Fanavacard\Fanavacard::class,
        'asanpardakht' => \TomatoPHP\TomatoWallet\Drivers\Asanpardakht\Asanpardakht::class,
        'atipay' => \TomatoPHP\TomatoWallet\Drivers\Atipay\Atipay::class,
        'behpardakht' => \TomatoPHP\TomatoWallet\Drivers\Behpardakht\Behpardakht::class,
        'digipay' => \TomatoPHP\TomatoWallet\Drivers\Digipay\Digipay::class,
        'etebarino' => \TomatoPHP\TomatoWallet\Drivers\Etebarino\Etebarino::class,
        'idpay' => \TomatoPHP\TomatoWallet\Drivers\Idpay\Idpay::class,
        'irankish' => \TomatoPHP\TomatoWallet\Drivers\Irankish\Irankish::class,
        'nextpay' => \TomatoPHP\TomatoWallet\Drivers\Nextpay\Nextpay::class,
        'omidpay' => \TomatoPHP\TomatoWallet\Drivers\Omidpay\Omidpay::class,
        'parsian' => \TomatoPHP\TomatoWallet\Drivers\Parsian\Parsian::class,
        'pasargad' => \TomatoPHP\TomatoWallet\Drivers\Pasargad\Pasargad::class,
        'payir' => \TomatoPHP\TomatoWallet\Drivers\Payir\Payir::class,
        'paypal' => \TomatoPHP\TomatoWallet\Drivers\Paypal\Paypal::class,
        'payping' => \TomatoPHP\TomatoWallet\Drivers\Payping\Payping::class,
        'paystar' => \TomatoPHP\TomatoWallet\Drivers\Paystar\Paystar::class,
        'poolam' => \TomatoPHP\TomatoWallet\Drivers\Poolam\Poolam::class,
        'sadad' => \TomatoPHP\TomatoWallet\Drivers\Sadad\Sadad::class,
        'saman' => \TomatoPHP\TomatoWallet\Drivers\Saman\Saman::class,
        'sep' => \TomatoPHP\TomatoWallet\Drivers\SEP\SEP::class,
        'sepehr' => \TomatoPHP\TomatoWallet\Drivers\Sepehr\Sepehr::class,
        'walleta' => \TomatoPHP\TomatoWallet\Drivers\Walleta\Walleta::class,
        'yekpay' => \TomatoPHP\TomatoWallet\Drivers\Yekpay\Yekpay::class,
        'zarinpal' => \TomatoPHP\TomatoWallet\Drivers\Zarinpal\Zarinpal::class,
        'zibal' => \TomatoPHP\TomatoWallet\Drivers\Zibal\Zibal::class,
        'sepordeh' => \TomatoPHP\TomatoWallet\Drivers\Sepordeh\Sepordeh::class,
        'rayanpay' => \TomatoPHP\TomatoWallet\Drivers\Rayanpay\Rayanpay::class,
        'sizpay' => \TomatoPHP\TomatoWallet\Drivers\Sizpay\Sizpay::class,
        'vandar' => \TomatoPHP\TomatoWallet\Drivers\Vandar\Vandar::class,
        'aqayepardakht' => \TomatoPHP\TomatoWallet\Drivers\Aqayepardakht\Aqayepardakht::class,
        'azki' => \TomatoPHP\TomatoWallet\Drivers\Azki\Azki::class,
        'payfa' => \TomatoPHP\TomatoWallet\Drivers\Payfa\Payfa::class,
    ],

    'transaction_resource' => null
];
```


# APIs

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/wallet/deposit" method="post" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}

{% openapi src="/files/RJe8iTuLpyvzVbig6e0F" path="/wallet/transactions" method="get" %}
[document (1).json](https://117397612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSlG6RrSDmGrQX2xjM6AT%2Fuploads%2FLYF2ricchUry1N11n6Dp%2Fdocument%20\(1\).json?alt=media\&token=24a4b40b-de8b-479c-a0ee-ea596b6301af)
{% endopenapi %}


# Tomato CMS

full CMS System to manage your content build for Tomato PHP

<figure><img src="/files/DD3JycFu6ZPCN4Wpenq7" alt=""><figcaption></figcaption></figure>

### Installation

```
composer require tomatophp/tomato-cms
```

or as Module

```
composer require tomatophp/tomato-cms-module
```

after installing your package please run this command

```
php artisan tomato-cms:install
```

### Markdown Editor Install

we need a markdown editor to be installed on your front let's start by installing the package

```bash
yarn add md-editor-v3
```

now you need to allow it on your app.js

```javascript
import { MdEditor, MdPreview } from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';

createApp({
    render: renderSpladeApp({ el })
})
    .use(SpladePlugin, {
        max_keep_alive: 10,
        transform_anchors: false,
        progress_bar: true,
    })
    .component("MdEditor", MdEditor)
    .component("MdPreview", MdPreview)
    ...
    .mount(el);
```

### Changelog

Please see [CHANGELOG](https://github.com/tomatophp/tomato-cms/blob/master/CHANGELOG.md) for more information on what has changed recently.

### Security

Please see [SECURITY](https://github.com/tomatophp/tomato-cms/blob/master/SECURITY.md) for more information about the security.

### Credits

* [Fady Mondy](https://www.github.com/3x1io)

### License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/tomato-cms/blob/master/LICENSE.md) for more information.


# Use

this package is very good if you like to build a Company website or blog or personal profile website it supports a lot of CRUDs for any CMS like

* Posts
* Pages
* Comments
* Photos
* Services
* Skills
* Testimonials
* Portfolio

with crawling options to collect data from Behanace, Youtube, and GitHub, which means you can import your content from these platforms to our CMS with 1 click.


# Config

you can publish a config file by using this command

```
php artisan vendor:publish --tag="tomato-cms-config"
```

you can publish view files by using this command

```
php artisan vendor:publish --tag="tomato-cms-views"
```

you can publish language files by using this command

```
php artisan vendor:publish --tag="tomato-cms-lang"
```

you can publish migration files by using this command

```
php artisan vendor:publish --tag="tomato-cms-migrations"
```

### Config File

```php
<?php

return [
    "sections_buttons" => null,
    "behance_username" => null,
    "behance_service_id" => null,
    "youtube_key" => null
];
```

you can add more buttons to the index of the section by just passing a blade path to the `sections_buttons`&#x20;

&#x20;our CMS supports data crawling to collect data from other platforms, using dusk, so you can set your `behanace_username` to the config and we will find your projects&#x20;

as you can see there is a types of posts like open-source it's take a data from GitHub if you passing a repo name

and a videos type that's take the data from youtube, but it's need a key


# Tomato Support

Ticketing and support system with API for tomato admin

## Installation

```bash
composer require tomatophp/tomato-support
```

or as Module

```
composer require tomatophp/tomato-support-module
```

after install your package please run this command

```bash
php artisan tomato-support:install
```

## Support

you can join our discord server to get support [TomatoPHP](https://discord.gg/Xqmt35Uh)

## Docs

you can check docs of this package on [Docs](https://docs.tomatophp.com/plugins/laravel-package-generator)

## Changelog

Please see [CHANGELOG](https://github.com/tomatophp/docs/blob/master/plugins/tomato-support/CHANGELOG.md) for more information on what has changed recently.

## Security

Please see [SECURITY](https://github.com/tomatophp/docs/blob/master/plugins/tomato-support/SECURITY.md) for more information about security.

## Credits

* [Tomatophp](mailto:info@3x1.io)

## License

The MIT License (MIT). Please see [License File](https://github.com/tomatophp/docs/blob/master/plugins/tomato-support/LICENSE.md) for more information.




---

[Next Page](/llms-full.txt/1)

