Skip to content

KejawenLab/SemartApiSkeleton

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SemartApiSkeleton

SemartApiSkeleton adalah solusi untuk membangun aplikasi secara super cepat, sangat fleksibel dan luar biasa mudah untuk aplikasi berbasis Admin maupun Api

SemartApiSkeleton menggunakan swoole sebagai PHP Runtime untuk menjalankan PHP dengan model long pooling sebagaimana NodeJs, Golang atau sejenisnya.

Requirement

Install

Pre Step

Clone dan Generate PKI (Public Key Infrastucture)

git clone https://github.com/KejawenLab/SemartApiSkeleton
cd SemartApiSkeleton
mkdir -p config/jwt
openssl genpkey -out config/jwt/private.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096
#Jangan lupa untuk mengingat passphrase yang diinput
openssl pkey -in config/jwt/private.pem -out config/jwt/public.pem -pubout

Docker Install

Install menggunakan metode Docker adalah cara tercepat untuk memulai tanpa perlu install dependencies terlebih dahulu

  • Ubah file .env.template menjadi file .env

  • Ubah isi file .env sesuai dengan kebutuhan terutama pada JWT_PASSPHRASE, berikut contoh konfigurasinya

# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
#  * .env                contains default values for the environment variables needed by the app
#  * .env.local          uncommitted file with local overrides
#  * .env.$APP_ENV       committed environment-specific defaults
#  * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration

APP_RUNTIME=Runtime\Swoole\Runtime

###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=ykWmyQ9xVGbn+vQB2gzCWg==
#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
#TRUSTED_HOSTS='^(localhost|example\.com)$'
###< symfony/framework-bundle ###

###> lexik/jwt-authentication-bundle ###
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=CHANGEME-TO-VALUE-THAT-YOU-PROVIDE-WHEN-GENERATING-PRIVATE-KEY
###< lexik/jwt-authentication-bundle ###

###> snc/redis-bundle ###
# passwords that contain special characters (@, %, :, +) must be urlencoded
REDIS_URL=redis://session
###< snc/redis-bundle ###

###> CUSTOM ###
NGINX_WEBROOT=/semart/public
SWOOLE_HOST="0.0.0.0"
SWOOLE_PORT=9501
APP_SUPER_ADMIN=SPRADM
APP_TITLE="Semart Api Skeleton"
APP_DESCRIPTION="Semart Api Skeleton Application"
APP_VERSION=1@dev
APP_UPLOAD_DIR=%kernel.project_dir%/storage
APP_MEDIA_PREFIX=/medias
###< CUSTOM ###

###> doctrine/doctrine-bundle ###
DATABASE_DRIVER=pdo_pgsql
DATABASE_CHARSET=utf8
DATABASE_USER=semart
DATABASE_PASSWORD=CHANGEME-TO-VALUE-PROVIDED-BY-SEMART-ENCRYPT-COMMAND
DATABASE_NAME=semart_skeleton
DATABASE_HOST=db
DATABASE_PORT=5432
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8"
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
# DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7
###< doctrine/doctrine-bundle ###

###> nelmio/cors-bundle ###
CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
###< nelmio/cors-bundle ###

###> symfony/messenger ###
# Choose one of the transports below
MESSENGER_TRANSPORT_DSN=amqp://guest:guest@messenger:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=doctrine://default
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
###< symfony/messenger ###
  • Karena Semart Api Skeleton menggunakan encryption password untuk koneksi ke database, maka kita perlu mengenkripsi password database terlebih dahulu. Pada file docker-compose.yml, password database adalah semart, maka kita perlu menjalankan perintah berikut:
docker compose -f docker-compose.yml build && docker compose -f docker-compose.yml up
docker compose -f docker-compose.yml exec app bash -c "php bin/console semart:encrypt semart"

Jika Anda menggunakan Taskfile, Anda cukup menjalankan perintah:

task encrypt -- semart
  • Abaikan warning atau error yang terjadi

  • Ubah nilai DATABASE_PASSWORD pada file .env sesuai dengan hasil perintah di atas

  • Restart container

  • Jalankan perintah berikut:

docker compose -f docker-compose.yml exec app bash -c "php bin/console cache:clear"
docker compose -f docker-compose.yml exec app bash -c "chmod 777 -R var"
docker compose -f docker-compose.yml exec app bash -c "php bin/console doctrine:database:create --no-interaction"
docker compose -f docker-compose.yml exec app bash -c "php bin/console doctrine:schema:update --force --no-interaction"
docker compose -f docker-compose.yml exec app bash -c "php bin/console doctrine:fixtures:load --no-interaction"
docker compose -f docker-compose.yml exec app bash -c "php bin/console assets:install"

Jika Anda menggunakan Taskfile, Anda cukup menjalankan perintah:

task install
  • Swagger berjalan pada alamat http://localhost:9876/api/doc dengan username admin dan password admin

  • Admin berjalan pada alamat http://localhost:9876/admin dengan username admin dan password admin sama seperti pada Swagger

  • Adminer berjalan pada alamat http://localhost:6789 dengan host db, username root dan password semart

Cara Penggunaan

Buat Folder Todo/Model pada app

cd <your_installation_dir> && mkdir -p app/Todo/Model

Buat Interface TodoInterface pada folder Todo/Model

Model harus extends KejawenLab\ApiSkeleton\Entity\EntityInterface interface

<?php

declare(strict_types=1);

namespace KejawenLab\Application\Todo\Model;

use KejawenLab\ApiSkeleton\Entity\EntityInterface;

/**
 * @author Muhamad Surya Iksanudin<surya.iksanudin@gmail.com>
 */
interface TodoInterface extends EntityInterface
{
    public function getId(): ?string;

    public function getTask(): ?string;

    public function isDone(): bool;
}

Buat Entity pada folder app/Entity

Entity harus implement KejawenLab\Application\Todo\Model\TodoInterface.

Kamu dapat merujuk pada dokumentasi resmi tentang Mapping Entity, namun sangat tidak disarankan menggunakan Symfony Maker untuk membuat entity pada SemartApiSkeleton

<?php

declare(strict_types=1);

namespace KejawenLab\Application\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Blameable\Traits\BlameableEntity;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use KejawenLab\Application\Repository\TodoRepository;
use KejawenLab\Application\Todo\Model\TodoInterface;
use KejawenLab\ApiSkeleton\Util\StringUtil;
use OpenApi\Attributes as OA;
use Ramsey\Uuid\Doctrine\UuidGenerator;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

#[Gedmo\SoftDeleteable(fieldName: 'deletedAt')]
#[ORM\Entity(repositoryClass: TodoRepository::class)]
#[ORM\Table(name: 'todos')]
class Todo implements TodoInterface
{
    use BlameableEntity;
    use SoftDeleteableEntity;
    use TimestampableEntity;

    #[Groups(groups: ['read'])]
    #[OA\Property(type: 'string')]
    #[ORM\Id]
    #[ORM\Column(type: 'uuid', unique: true)]
    #[ORM\CustomIdGenerator(class: UuidGenerator::class)]
    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
    private UuidInterface $id;

    #[Assert\Length(max: 255)]
    #[Assert\NotBlank]
    #[Groups(groups: ['read'])]
    #[ORM\Column(type: 'string', length: 255)]
    private ?string $task;

    #[Groups(groups: ['read'])]
    #[ORM\Column(type: 'boolean')]
    private bool $done;
    
    public function __construct()
    {
        $this->task = null;
        $this->done = false;
    }

    public function getId(): ?string
    {
        return (string) $this->id;
    }

    public function getTask(): ?string
    {
        return $this->task;
    }

    public function setTask(string $task): void
    {
        $this->task = StringUtil::title($task);
    }

    public function isDone(): bool
    {
        return $this->done;
    }

    public function setDone(bool $done): void
    {
        $this->done = $done;
    }

    public function getNullOrString(): ?string
    {
        return $this->getTask();
    }
}

Class KejawenLab\Application\Repository\TodoRepository untuk sekarang belum ada, namun jangan khawatir, SemartApiSkeleton akan mengenerate class tersebut nanti.

Daftarkan sebagai auditable

Buka file config/packages/dh_auditor.yaml dan daftarkan entity sebagai berikut:

dh_auditor:
    providers:
        doctrine:
            entities:
                ...
                KejawenLab\Application\Entity\Todo: ~

Generate Controller, Form, Repository, Serivce, Register Menu, Template, dan Api Documentation

docker compose -f docker-compose.yml exec app bash -c "php bin/console semart:generate Todo"
docker compose -f docker-compose.yml exec app bash -c "php bin/console doctrine:schema:update --force --no-interaction"

Jika Anda menggunakan Taskfile, Anda cukup menjalankan perintah:

task generate -- Todo

Generate Command

Setelah menjalankan perintah di atas maka susunan folder Todo/Model akan menjadi seperti berikut:

After Generate

Dan jika kamu login ke Semart Api Skeleton maka akan muncul menu Todo pada sidebar sebagai berikut:

After Generate

Dan ketika membuka menu Menu maka record Todo pun akan muncul sebagai berikut:

Menu

Dan pastinya kamu juga bisa set permission untuk Todo pada menu Hak Akses (Group -> Lihat -> Hak Akses) sebagai berikut:

Todo Permission

Dan jika kamu mengakses halaman Api Documentation maka akan muncul section Todo sebagai berikut:

Api Doc

Sangat mudah sekali bukan? Selanjutnya kamu harus restart dulu docker-nya agar class-class yang tadi digenerate dan didaftarkan sebagai service. Hal ini perlu dilakukan karena kita menggunakan swoole.

Update translation

Ketika kamu mengetik menu Todo pada sidebar, maka akan muncul tampilan sebagai berikut:

Todo List

Terdapat beberapa text yang aneh? Santai, kamu cukup buka file translations/pages.id.yaml dan tambahkan baris berikut:

        todo:
            saved: 'Todo berhasil disimpan'
            deleted: 'Todo berhasil dihapus'
            not_found: 'Todo tidak ditemukan'
            list: 'Daftar Todo'
            add: 'Tambah Todo'
            edit: 'Ubah Todo'
            view: 'Detil Todo'

Selanjut, kamu juga perlu mengubah translasi pada file translations/tables.id.yaml sebagai berikut:

            todo:
                task: 'Tugas'
                done: 'Selesai?'

Selanjutnya, kamu juga perlu mengubah translasi pada file translations/forms.id.yaml dan tambahkan baris berikut:

            todo:
                task: 'Tugas'
                done: 'Selesai?'

Ketika kamu berusaha menambahkan task, maka akan kamu harus mengeklik check box done, untuk memodifikasi itu, kamu harus mengubah definisi form (akan dibahas selanjutnya).

Jangan lupa untuk merestart docker untuk mendapatkan perubahan.

Untuk lebih jelas tentang translasi pada Symfony, kamu dapat membaca dokumentasi resmi tentang Symfony Translation

Update form type

Secara default, semua field yang ada pada form adalah required sehingga kita wajib mengisinya. Untuk mengubahnya, ubah config file Form/TodoType pada fungsi buildForm sebagai berikut:

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('task', null, [
            'required' => true,
            'label' => 'sas.form.field.todo.task',
        ]);
        $builder->add('done', null, [
            'required' => false,
            'label' => 'sas.form.field.todo.done',
        ]);
    }

Untuk lebih jelas tentang Symfony Form, kamu dapat membaca dokumentasi resmi tentang Symfony Form

Jangan lupa untuk merestart docker untuk mendapatkan perubahan.

Perubahan ini akan berlaku pada halaman Admin maupun Rest Api.

Mengaktifkan fungsi pencarian

Secara default, SemartApiSkeleton telah menyiapkan class untuk menghandle kustomasi query, namun SemartApiSkeleton tidak memberikan logic apapun pada class tersebut. Kamu sendiri yang perlu memberikut logic pada class tersebut.

Sebagai contoh, kita akan coba mengaktifkan fungsi pencarian Todo berdasarkan field task, maka kita mengubah file Todo/Query/SearchQueryExtension pada fungsi apply sebagai berikut:

    public function apply(QueryBuilder $queryBuilder, Request $request): void
    {
        $query = $request->query->get('q');
        if (!$query) {
            return;
        }

        $queryBuilder->andWhere(
            $queryBuilder->expr()->like(
                sprintf('UPPER(%s.task)', $this->aliasHelper->findAlias('root')),
                $queryBuilder->expr()->literal(sprintf('%%%s%%', StringUtil::uppercase($query)))
            )
        );
    }

SemartApiSkeleton menggunakan Doctrine Query Builder untuk melakukan kustomasi query pada query extension.

Jangan lupa untuk merestart docker untuk mendapatkan perubahan.

Update Template

Secara default, SemartApiSkeleton akan mengubah bool menjadi string (direpresentasikan dengan 0 dan 1) seperti pada daftar todo berikut:

Todo List

Kita dapat mengubahnya melalui file templates/todo/all.html.twig sebagai berikut:

{% for property in properties %}
    {% if 'id' != property.name %}
        <tr>
            <td style="width: 149px;">{{ ('sas.table.column.' ~ context ~ '.' ~ property.name) | trans({}, 'tables') }}</td>
            <td style="width: 7px;">:</td>
            {% if 'done' == property.name %}
                <td>{% if todo.done %}Selesai{% else %}Belum Selesai{% endif %}</td>
            {% else %}
                <td>{{ semart_print(attribute(data, property.name)) }}</td>
            {% endif %}
        </tr>
    {% endif %}
{% endfor %}

Selain itu, kita juga perlu mengubah file templates/todo/view.html.twig sebagai berikut:

{% for property in properties %}
    {% if 'id' != property.name %}
        <tr>
            <td style="width: 149px;">{{ ('sas.table.column.' ~ context ~ '.' ~ property.name) | trans({}, 'tables') }}</td>
            <td style="width: 7px;">:</td>
            {% if 'done' == property.name %}
                <td>{% if data.done %}Selesai{% else %}Belum Selesai{% endif %}</td>
            {% else %}
                <td>{{ semart_print(attribute(data, property.name)) }}</td>
            {% endif %}
        </tr>
    {% endif %}
{% endfor %}

Untuk lebih jelas tentang Twig Template, kamu dapat membaca dokumentasi resmi Twig Template

Jangan lupa untuk merestart docker untuk mendapatkan perubahan.

Fitur

  • RESTful Api Generator

  • Admin Generator

  • Api Documentation

  • Sandbox

  • JWT Authentication

  • Rate Limiter

  • Single Sign In

  • Query Extension

  • Soft Deletable

  • Audit Trail

  • User Management

  • Profile Management

  • Group Management

  • Menu Management

  • Permission Management

  • Setting Management

  • Cronjob Management

  • Cache Management

  • Media Management

  • Public & Private Media Support

  • Public & Private Api Support

  • Housekeeping

  • Password History

  • Api Client/Consumer Management

  • Health Check

  • Export to CSV

Dokumentasi

Dasar

Lanjutan

Digunakan Oleh

Kementerian Pariwisata
(checked: 8-7-2021)

Pemprov DKI Jakarta
(checked: 8-7-2021)

Kementerian Kesehatan
(checked: 17-11-2021)

Direktorat Jenderal Imigrasi
(checked: 04-01-2022)

Copyright

Semart Api Skeleton dikembangkan dan dimaintain oleh KejawenLab

Lisensi

Lisensi dari Semart Api Skeleton adalah MIT License namun proyek yang dibangun menyeseuaikan dengan kebijakan masing-masing

Screenshot

Halaman Admin

Admin

Api Doc

Api Doc

Sandbox

Sandbox

Cronjob Management

Cronjob

Setting Management

Setting

Media Management

Media

Group Management

Group

Menu Management

Menu

User Management

User

Profile Management

Profile

Client/Api Consumer Management

Consumer