tobento/apps

支持多个应用程序。每个应用程序将在其自己的应用程序中运行。

1.0.0 2024-09-08 13:47 UTC

This package is auto-updated.

Last update: 2024-09-08 13:57:55 UTC


README

支持多个应用程序。每个应用程序将在其自己的应用程序中运行。

目录

入门

使用此命令添加运行此应用程序项目的最新版本。

composer require tobento/apps

要求

  • PHP 8.0 或更高版本

文档

应用程序

如果您使用的是骨架,请查看 应用程序骨架

您还可以查看 应用程序 以了解有关应用程序的一般信息。

创建新应用程序

要创建新应用程序,只需扩展 AppBoot::class 并按需定义常量。

use Tobento\Apps\AppBoot;

class Backend extends AppBoot
{
    /**
     * Specify your app boots:
     */
    protected const APP_BOOT = [
        //\Tobento\App\Console\Boot\Console::class,
        //\Tobento\App\User\Web\Boot\UserWeb::class,
    ];
    
    /**
     * Set a unique app id. Must be lowercase and
     * only contain [a-z0-9-] characters.
     * Furthermore, do not set ids with two dashes such as 'foo--bar'
     * as supapps id will be separated by two dashes.
     */
    protected const APP_ID = 'backend';

    /**
     * You may set a slug for the routing e.g. example.com/slug/
     * Or you may set the slug to an empty string e.g. example.com/
     */
    protected const SLUG = 'admin';
    
    /**
     * You may set a domains for the routing e.g. ['api.example.com']
     * In addition, you may set the slug to an empty string,
     * otherwise it gets appended e.g. api.example.com/slug
     */
    protected const DOMAINS = [];
    
    /**
     * You may set a migration to be installed on booting e.g Migration::class
     */
    protected const MIGRATION = '';
}

允许子应用程序

如果您的应用程序支持子应用程序,请将 supportsSubapps 属性设置为 true

use Tobento\Apps\AppBoot;

class DomainFoo extends AppBoot
{
    /**
     * Specify your app boots:
     */
    protected const APP_BOOT = [
        Backend::class,
        Frontend::class,
    ];
    
    /**
     * Set a unique app id. Must be lowercase and
     * only contain [a-z0-9-] characters.
     * Furthermore, do not set ids with two dashes such as 'foo--bar'
     * as supapps id will be separated by two dashes.
     */
    protected const APP_ID = 'domain-foo';

    /**
     * You may set a slug for the routing e.g. example.com/slug/
     * Or you may set the slug to an empty string e.g. example.com/
     */
    protected const SLUG = '';
    
    /**
     * You may set a domains for the routing e.g. ['api.example.com']
     * In addition, you may set the slug to an empty string,
     * otherwise it gets appended e.g. api.example.com/slug
     */
    protected const DOMAINS = ['example.com'];    
    
    /**
     * @var bool
     */
    protected bool $supportsSubapps = true;
}

启动应用程序

创建应用程序后,您需要启动您的应用程序

use Tobento\App\AppFactory;

// Create the app:
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(DomainFoo::class);
$app->boot(DomainBar::class);
$app->boot(Backend::class);

// Adding app specific boots:
$app->booting();
$app->get(Backend::class)->addBoot(BackendSpecificBoot::class);

// Run the app:
$app->run();

在启动中使用应用程序的示例

use Tobento\App\Boot;

class Blog extends Boot
{
    public const BOOT = [
        Backend::class,
        Frontend::class,
    ];
    
    public function boot(Backend $backend, Frontend $frontend): void
    {
        $backend->addBoot(BlogBackend::class);
        $frontend->addBoot(BlogFrontend::class);
    }
}

接下来,启动您的 Blog 启动

use Tobento\App\AppFactory;

// Create the app:
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(Blog::class);

// Run the app:
$app->run();

应用程序配置

应用程序配置位于默认应用程序骨架配置位置的 app/config/apps.php 文件中。

目录结构

目录结构将如下所示

your-project/
  app/ #root app
    config/
    src/
    ...
  apps/
    backend/
      config/
      views/
      ...
  public/
    apps/
      backend/
        assets/
    assets/
    index.php
  vendor/

共享配置

您可以使用 app:rootapp:parent 目录来共享配置,以指向相同的目录

在应用程序中的每个 config/database.php

'defaults' => [
    'pdo' => 'mysql',
    'storage' => 'file',
    'shared:storage' => 'shared:file',
],
    
'databases' => [
    'shared:file' => [
        'factory' => \Tobento\Service\Database\Storage\StorageDatabaseFactory::class,
        'config' => [
            'storage' => \Tobento\Service\Storage\JsonFileStorage::class,
            'dir' => directory('app:parent').'storage/database/file/',
        ],
    ],
],

并在您的应用程序中

use Tobento\Service\Database\DatabasesInterface;

$storageDatabase = $app->get(DatabasesInterface::class)->default('shared:storage');

// or
$fileDatabase = $app->get(DatabasesInterface::class)->get('shared:file');

访问应用程序

您可以通过使用 AppsInterface::class 并检索所需的应用程序来从另一个应用程序访问应用程序。

use Tobento\Apps\AppBoot;
use Tobento\Apps\AppsInterface;
use Tobento\Service\Routing\RouterInterface;

// Boot the app if it has not booted yet:
$app->booting();

// Get the apps:
$apps = $app->get(AppsInterface::class);

// Get any desired app:
var_dump($apps->get('frontend') instanceof AppBoot);
// bool(true)

$frontendApp = $apps->get('frontend')->app();
$frontendApp->booting();

// For instance, get all frontend app routes:
$routes = $frontendApp->get(RouterInterface::class)->getRoutes();

子应用程序

访问父应用程序时,您必须首先启动父应用程序,否则子应用程序将找不到!

use Tobento\Apps\AppsInterface;
use Tobento\Service\Routing\RouterInterface;

// Boot the app if it has not booted yet:
$app->booting();

// Get the apps:
$apps = $app->get(AppsInterface::class);

// Boot parent app:
$apps->get('domain-foo')->app()->booting();

// Get sub app:
$frontendApp = $apps->get('domain-foo--frontend')->app();
$frontendApp->booting();

// For instance, get all frontend app routes:
$routes = $frontendApp->get(RouterInterface::class)->getRoutes();

控制台

以下命令应在根应用程序控制台运行。

应用程序列表命令

apps:list 命令提供了所有应用程序的概述

php ap apps:list

应用程序命令

使用 apps 命令,您可以在每个应用程序中运行任何命令。

在所有应用程序上运行 route:list 命令

php ap apps route:list

仅在前端和后端应用程序上运行 route:list 命令

php ap apps route:list --aid=frontend --aid=backend

应用程序创建控制台命令

您可以使用 apps:create-console 命令为每个应用程序创建控制台。

php ap apps:create-console

一旦创建,控制台就在每个应用程序目录中可用

your-project/
  apps/
    backend/
      config/
      views/
      ap #console

测试

当使用 应用程序测试 包时,您需要在 createApp 方法上返回您想要测试的特定应用程序。

use Tobento\App\Testing\TestCase;
use Tobento\App\AppInterface;
use Tobento\Apps\AppsInterface;

final class BackendAppTest extends TestCase
{
    public function createApp(): AppInterface
    {
        $app = require __DIR__.'/../app/app.php';
        $app->booting();
        
        // Return the app you want to test:
        return $app->get(AppsInterface::class)->get('backend')->app();
    }
}

使用临时应用程序

use Tobento\App\Testing\TestCase;
use Tobento\App\AppInterface;
use Tobento\Apps\AppsInterface;

final class BackendAppTest extends TestCase
{
    public function createApp(): AppInterface
    {
        $app = $this->createTmpApp(rootDir: __DIR__.'/..');
        
        // Boot your apps:
        $app->boot(Backend::class);
        $app->booting();
        
        // Get the app you want to test:
        $app = $app->get(AppsInterface::class)->get('backend')->app();
        
        // You may boot additional boots for testing:
        $app->boot(\Tobento\App\Seeding\Boot\Seeding::class);
        
        return $app;
    }
}

使用子应用程序的示例

use Tobento\App\Testing\TestCase;
use Tobento\App\AppInterface;
use Tobento\Apps\AppsInterface;

final class BackendAppTest extends TestCase
{
    public function createApp(): AppInterface
    {
        $app = $this->createTmpApp(rootDir: __DIR__.'/..');
        
        // Boot your apps:
        $app->boot(DomainFoo::class);
        $app->booting();
        
        // Get and boot parent app:
        $app = $app->get(AppsInterface::class)->get('domain-foo')->app();
        $app->booting();
        
        // Get sub app:
        $app = $app->get(AppsInterface::class)->get('domain-foo--backend')->app();
        
        // You may boot additional boots for testing:
        $app->boot(\Tobento\App\Seeding\Boot\Seeding::class);
        
        return $app;
    }
}

致谢