├── tests
├── Support
│ ├── Data
│ │ └── .gitkeep
│ ├── _generated
│ │ └── .gitignore
│ ├── WebTester.php
│ ├── UnitTester.php
│ ├── ConsoleTester.php
│ └── FunctionalTester.php
├── .gitignore
├── Functional.suite.yml
├── Console.suite.yml
├── Unit.suite.yml
├── bootstrap.php
├── Web.suite.yml
├── Console
│ ├── YiiCest.php
│ └── HelloCest.php
├── Web
│ ├── HomePageCest.php
│ └── NotFoundHandlerCest.php
├── Unit
│ └── EnvironmentTest.php
└── Functional
│ └── HomePageCest.php
├── config
├── .gitignore
├── web
│ ├── params.php
│ └── di
│ │ ├── psr17.php
│ │ └── application.php
├── environments
│ ├── prod
│ │ └── params.php
│ ├── test
│ │ └── params.php
│ └── dev
│ │ └── params.php
├── console
│ ├── commands.php
│ └── params.php
├── common
│ ├── application.php
│ ├── bootstrap.php
│ ├── routes.php
│ ├── aliases.php
│ ├── di
│ │ ├── application.php
│ │ ├── logger.php
│ │ ├── router.php
│ │ └── error-handler.php
│ └── params.php
└── configuration.php
├── docker
├── dev
│ ├── .gitignore
│ ├── override.env.example
│ ├── .env
│ └── compose.yml
├── prod
│ ├── .gitignore
│ ├── .env
│ └── compose.yml
├── test
│ ├── .gitignore
│ ├── .env
│ └── compose.yml
├── compose.yml
├── .env
└── Dockerfile
├── runtime
└── .gitignore
├── public
├── assets
│ └── .gitignore
├── robots.txt
├── favicon.ico
├── favicon.svg
└── index.php
├── screenshot.png
├── yii.bat
├── .dockerignore
├── src
├── autoload.php
├── Shared
│ └── ApplicationParams.php
├── Web
│ ├── Shared
│ │ └── Layout
│ │ │ └── Main
│ │ │ ├── MainAsset.php
│ │ │ └── layout.php
│ ├── HomePage
│ │ ├── Action.php
│ │ └── template.php
│ └── NotFound
│ │ ├── template.php
│ │ └── NotFoundHandler.php
├── Console
│ └── HelloCommand.php
└── Environment.php
├── .editorconfig
├── .gitignore
├── yii
├── codeception.yml
├── rector.php
├── .php-cs-fixer.php
├── psalm.xml
├── composer-dependency-analyser.php
├── assets
└── main
│ └── site.css
├── composer.json
└── Makefile
/tests/Support/Data/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/.gitignore:
--------------------------------------------------------------------------------
1 | /_output
2 |
--------------------------------------------------------------------------------
/config/.gitignore:
--------------------------------------------------------------------------------
1 | .merge-plan.php
2 |
--------------------------------------------------------------------------------
/docker/dev/.gitignore:
--------------------------------------------------------------------------------
1 | /override.env
2 |
--------------------------------------------------------------------------------
/docker/prod/.gitignore:
--------------------------------------------------------------------------------
1 | /override.env
2 |
--------------------------------------------------------------------------------
/docker/test/.gitignore:
--------------------------------------------------------------------------------
1 | /override.env
2 |
--------------------------------------------------------------------------------
/runtime/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/public/assets/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
--------------------------------------------------------------------------------
/tests/Support/_generated/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/tests/Functional.suite.yml:
--------------------------------------------------------------------------------
1 | actor: FunctionalTester
2 |
--------------------------------------------------------------------------------
/docker/dev/override.env.example:
--------------------------------------------------------------------------------
1 | APP_HOST_PATH=/projects/yiisoft/app
2 |
--------------------------------------------------------------------------------
/docker/prod/.env:
--------------------------------------------------------------------------------
1 | APP_ENV=prod
2 | APP_DEBUG=false
3 | SERVER_NAME=:80
4 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yiisoft/app/HEAD/screenshot.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yiisoft/app/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/config/web/params.php:
--------------------------------------------------------------------------------
1 | 'phpstorm://open?url=file://{file}&line={line}',
7 | ];
8 |
--------------------------------------------------------------------------------
/config/console/commands.php:
--------------------------------------------------------------------------------
1 | Console\HelloCommand::class,
9 | ];
10 |
--------------------------------------------------------------------------------
/docker/compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | app: &appconfig
3 | extra_hosts:
4 | - "host.docker.internal:host-gateway"
5 |
6 | volumes:
7 | caddy_data:
8 | caddy_config:
9 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Ignore everything
2 | *
3 |
4 | # except:
5 |
6 | !/config
7 | !/public
8 | !/src
9 | !autoload.php
10 | !yii
11 | !composer.json
12 | !composer.lock
13 | !.env*
14 |
--------------------------------------------------------------------------------
/config/common/application.php:
--------------------------------------------------------------------------------
1 | 'UTF-8',
7 | 'locale' => 'en',
8 | 'name' => 'My Project',
9 | ];
10 |
--------------------------------------------------------------------------------
/src/autoload.php:
--------------------------------------------------------------------------------
1 | [
7 | 'commands' => require __DIR__ . '/commands.php',
8 | ],
9 | ];
10 |
--------------------------------------------------------------------------------
/config/common/bootstrap.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | return [];
11 |
--------------------------------------------------------------------------------
/docker/.env:
--------------------------------------------------------------------------------
1 | STACK_NAME=app
2 |
3 | #
4 | # Development
5 | #
6 |
7 | DEV_PORT=80
8 |
9 | #
10 | # Production
11 | #
12 |
13 | PROD_HOST=app.example.com
14 | PROD_SSH="ssh://docker-web"
15 |
16 | IMAGE=app
17 | IMAGE_TAG=latest
18 |
--------------------------------------------------------------------------------
/tests/Web.suite.yml:
--------------------------------------------------------------------------------
1 | actor: WebTester
2 | extensions:
3 | enabled:
4 | - Codeception\Extension\RunProcess:
5 | 0: composer serve
6 | sleep: 3
7 | modules:
8 | enabled:
9 | - PhpBrowser:
10 | url: http://127.0.0.1:8080
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | insert_final_newline = true
9 | indent_style = space
10 | indent_size = 4
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
16 | [*.yml]
17 | indent_size = 2
18 |
--------------------------------------------------------------------------------
/src/Shared/ApplicationParams.php:
--------------------------------------------------------------------------------
1 | routes(
12 | Route::get('/')
13 | ->action(Web\HomePage\Action::class)
14 | ->name('home'),
15 | ),
16 | ];
17 |
--------------------------------------------------------------------------------
/tests/Console/YiiCest.php:
--------------------------------------------------------------------------------
1 | runApp();
14 | $I->canSeeResultCodeIs(0);
15 | $I->seeInShellOutput('Yii Console');
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tests/Console/HelloCest.php:
--------------------------------------------------------------------------------
1 | runApp('hello');
14 | $I->canSeeResultCodeIs(0);
15 | $I->seeInShellOutput('Hello!');
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tests/Web/HomePageCest.php:
--------------------------------------------------------------------------------
1 | wantTo('home page works.');
14 | $I->amOnPage('/');
15 | $I->expectTo('see page home.');
16 | $I->see('Hello!');
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/config/common/aliases.php:
--------------------------------------------------------------------------------
1 | dirname(__DIR__, 2),
7 | '@src' => '@root/src',
8 | '@assets' => '@root/public/assets',
9 | '@assetsUrl' => '@baseUrl/assets',
10 | '@assetsSource' => '@root/assets',
11 | '@baseUrl' => '/',
12 | '@public' => '@root/public',
13 | '@runtime' => '@root/runtime',
14 | '@vendor' => '@root/vendor',
15 | ];
16 |
--------------------------------------------------------------------------------
/config/common/di/application.php:
--------------------------------------------------------------------------------
1 | [
11 | '__construct()' => [
12 | 'name' => $params['application']['name'],
13 | 'charset' => $params['application']['charset'],
14 | 'locale' => $params['application']['locale'],
15 | ],
16 | ],
17 | ];
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # phpstorm project files
2 | .idea
3 |
4 | # netbeans project files
5 | nbproject
6 |
7 | # zend studio for eclipse project files
8 | .buildpath
9 | .project
10 | .settings
11 |
12 | # sublime text project / workspace files
13 | *.sublime-project
14 | *.sublime-workspace
15 |
16 | # windows thumbnail cache
17 | Thumbs.db
18 |
19 | # Mac DS_Store Files
20 | .DS_Store
21 |
22 | # composer vendor dir
23 | /vendor
24 |
25 | # Codeception C3
26 | c3.php
27 |
--------------------------------------------------------------------------------
/src/Web/Shared/Layout/Main/MainAsset.php:
--------------------------------------------------------------------------------
1 | run();
19 |
--------------------------------------------------------------------------------
/src/Web/HomePage/Action.php:
--------------------------------------------------------------------------------
1 | viewRenderer->render(__DIR__ . '/template');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/Unit/EnvironmentTest.php:
--------------------------------------------------------------------------------
1 | [
15 | 'class' => Logger::class,
16 | '__construct()' => [
17 | 'targets' => ReferencesArray::from([
18 | FileTarget::class,
19 | StreamTarget::class,
20 | ]),
21 | ],
22 | ],
23 | ];
24 |
--------------------------------------------------------------------------------
/config/common/di/router.php:
--------------------------------------------------------------------------------
1 | [
15 | 'class' => RouteCollection::class,
16 | '__construct()' => [
17 | 'collector' => DynamicReference::to(
18 | static fn() => (new RouteCollector())->addRoute(...$config->get('routes')),
19 | ),
20 | ],
21 | ],
22 | ];
23 |
--------------------------------------------------------------------------------
/src/Web/HomePage/template.php:
--------------------------------------------------------------------------------
1 | setTitle($applicationParams->name);
14 | ?>
15 |
16 |
17 |
Hello!
18 |
19 |
Let's start something great with Yii3 !
20 |
21 |
22 |
23 | Don't forget to check the guide.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/rector.php:
--------------------------------------------------------------------------------
1 | withPaths([
12 | __DIR__ . '/src',
13 | __DIR__ . '/tests',
14 | ])
15 | ->withPhpSets(php82: true)
16 | ->withRules([
17 | InlineConstructorDefaultToPropertyRector::class,
18 | ])
19 | ->withSkip([
20 | ClosureToArrowFunctionRector::class,
21 | ReadOnlyPropertyRector::class,
22 | ]);
23 |
--------------------------------------------------------------------------------
/src/Console/HelloCommand.php:
--------------------------------------------------------------------------------
1 | writeln('Hello!');
22 | return ExitCode::OK;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/Support/WebTester.php:
--------------------------------------------------------------------------------
1 | in([
14 | $root . '/config',
15 | $root . '/src',
16 | $root . '/tests',
17 | ])
18 | ->append([
19 | $root . '/public/index.php',
20 | ]);
21 |
22 | return (new Config())
23 | ->setCacheFile(__DIR__ . '/runtime/cache/.php-cs-fixer.cache')
24 | ->setParallelConfig(ParallelConfigFactory::detect())
25 | ->setRules([
26 | '@PER-CS2.0' => true,
27 | 'no_unused_imports' => true,
28 | ])
29 | ->setFinder($finder);
30 |
--------------------------------------------------------------------------------
/tests/Support/UnitTester.php:
--------------------------------------------------------------------------------
1 | sendRequest(
18 | new ServerRequest(uri: '/'),
19 | );
20 |
21 | assertSame(200, $response->getStatusCode());
22 | assertStringContainsString(
23 | 'Don\'t forget to check the guide',
24 | $response->getBody()->getContents(),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/psalm.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/Web/NotFound/template.php:
--------------------------------------------------------------------------------
1 | setTitle('404');
15 | ?>
16 |
17 |
18 |
19 | 404
20 |
21 |
22 |
23 | The page
24 | = Html::encode($currentRoute->getUri()?->getPath() ?? 'unknown') ?>
25 | not found.
26 |
27 |
28 |
29 | The above error occurred while the Web server was processing your request.
30 | Please contact us if you think this is a server error. Thank you.
31 |
32 |
33 |
34 | Go Back Home
35 |
36 |
37 |
--------------------------------------------------------------------------------
/docker/prod/compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | app:
3 | image: ${IMAGE}:${IMAGE_TAG}
4 | networks:
5 | - caddy_public
6 | volumes:
7 | - runtime:/app/runtime
8 | - caddy_data:/data
9 | - caddy_config:/config
10 | env_file:
11 | - path: ./prod/.env
12 | - path: ./prod/override.env
13 | required: false
14 | deploy:
15 | replicas: 2
16 | update_config:
17 | delay: 10s
18 | parallelism: 1
19 | order: start-first
20 | failure_action: rollback
21 | monitor: 10s
22 | rollback_config:
23 | parallelism: 0
24 | order: stop-first
25 | restart_policy:
26 | condition: on-failure
27 | delay: 5s
28 | max_attempts: 3
29 | window: 120s
30 | labels:
31 | caddy: ${PROD_HOST:-app.example.com}
32 | caddy.reverse_proxy: "{{upstreams 80}}"
33 |
34 | volumes:
35 | runtime:
36 |
37 | networks:
38 | caddy_public:
39 | external: true
40 |
--------------------------------------------------------------------------------
/composer-dependency-analyser.php:
--------------------------------------------------------------------------------
1 | disableComposerAutoloadPathScan()
11 | ->setFileExtensions(['php'])
12 | ->addPathToScan($root . '/src', isDev: false)
13 | ->addPathToScan($root . '/config', isDev: false)
14 | ->addPathToScan($root . '/public/index.php', isDev: false)
15 | ->addPathToScan($root . '/yii', isDev: false)
16 | ->addPathToScan($root . '/tests', isDev: true)
17 | ->ignoreErrorsOnPackage('psr/container', [ErrorType::UNUSED_DEPENDENCY])
18 | ->ignoreErrorsOnPackage('yiisoft/config', [ErrorType::UNUSED_DEPENDENCY])
19 | ->ignoreErrorsOnPackage('yiisoft/di', [ErrorType::UNUSED_DEPENDENCY])
20 | ->ignoreErrorsOnPackage('yiisoft/view', [ErrorType::UNUSED_DEPENDENCY])
21 | ->ignoreErrorsOnPackage('yiisoft/router-fastroute', [ErrorType::UNUSED_DEPENDENCY]);
22 |
--------------------------------------------------------------------------------
/tests/Web/NotFoundHandlerCest.php:
--------------------------------------------------------------------------------
1 | wantTo('see 404 page.');
14 | $I->amOnPage('/non-existent-page');
15 | $I->canSeeResponseCodeIs(404);
16 | $I->see('404');
17 | $I->see('The page /non-existent-page not found.');
18 | $I->see('The above error occurred while the Web server was processing your request.');
19 | $I->see('Please contact us if you think this is a server error. Thank you.');
20 | }
21 |
22 | public function returnHome(WebTester $I): void
23 | {
24 | $I->wantTo('check "Go Back Home" link.');
25 | $I->amOnPage('/non-existent-page');
26 | $I->canSeeResponseCodeIs(404);
27 | $I->click('Go Back Home');
28 | $I->expectTo('see page home.');
29 | $I->see('Hello!');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Web/NotFound/NotFoundHandler.php:
--------------------------------------------------------------------------------
1 | viewRenderer
26 | ->render(__DIR__ . '/template', ['urlGenerator' => $this->urlGenerator, 'currentRoute' => $this->currentRoute])
27 | ->withStatus(Status::NOT_FOUND);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/Support/ConsoleTester.php:
--------------------------------------------------------------------------------
1 | runShellCommand(
35 | dirname(__DIR__, 2) . '/yii' . ($parameters === null ? '' : (' ' . $parameters)),
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/config/web/di/psr17.php:
--------------------------------------------------------------------------------
1 | RequestFactory::class,
20 | ServerRequestFactoryInterface::class => ServerRequestFactory::class,
21 | ResponseFactoryInterface::class => ResponseFactory::class,
22 | StreamFactoryInterface::class => StreamFactory::class,
23 | UriFactoryInterface::class => UriFactory::class,
24 | UploadedFileFactoryInterface::class => UploadedFileFactory::class,
25 | ];
26 |
--------------------------------------------------------------------------------
/config/common/di/error-handler.php:
--------------------------------------------------------------------------------
1 | [
14 | '__construct()' => [
15 | 'traceLink' => static function (string $file, int|null $line) use ($params): string|null {
16 | if (!isset($params['traceLink'])) {
17 | return null;
18 | }
19 |
20 | try {
21 | $hostPath = Environment::appHostPath();
22 | if ($hostPath !== null) {
23 | /** @var string $file */
24 | $file = preg_replace('~^(/app/)~', rtrim($hostPath, '\\/') . '/', $file);
25 | }
26 | return str_replace(
27 | ['{file}', '{line}'],
28 | [$file, (string) $line],
29 | $params['traceLink'],
30 | );
31 | } catch (Throwable) {
32 | return null;
33 | }
34 | },
35 | ],
36 | ],
37 | ];
38 |
--------------------------------------------------------------------------------
/config/common/params.php:
--------------------------------------------------------------------------------
1 | require __DIR__ . '/application.php',
15 |
16 | 'yiisoft/aliases' => [
17 | 'aliases' => require __DIR__ . '/aliases.php',
18 | ],
19 |
20 | 'yiisoft/view' => [
21 | 'basePath' => null,
22 | 'parameters' => [
23 | 'assetManager' => Reference::to(AssetManager::class),
24 | 'applicationParams' => Reference::to(ApplicationParams::class),
25 | 'aliases' => Reference::to(Aliases::class),
26 | 'urlGenerator' => Reference::to(UrlGeneratorInterface::class),
27 | 'currentRoute' => Reference::to(CurrentRoute::class),
28 | ],
29 | ],
30 |
31 | 'yiisoft/yii-view-renderer' => [
32 | 'viewPath' => null,
33 | 'layout' => '@src/Web/Shared/Layout/Main/layout.php',
34 | 'injections' => [
35 | Reference::to(CsrfViewInjection::class),
36 | ],
37 | ],
38 | ];
39 |
--------------------------------------------------------------------------------
/tests/Support/FunctionalTester.php:
--------------------------------------------------------------------------------
1 | runAndGetResponse($request);
46 |
47 | $body = $response->getBody();
48 | if ($body->isSeekable()) {
49 | $body->rewind();
50 | }
51 |
52 | return $response;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/main/site.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | html {
6 | height: 100%;
7 | }
8 | body {
9 | display: flex;
10 | flex-direction: column;
11 | height: 100%;
12 | font: 16px/24px "Trebuchet MS", Helvetica, sans-serif;
13 | background: #f8f8f8;
14 | color: #4b4b4b;
15 | }
16 |
17 | .header {
18 | margin: 24px;
19 | padding: 12px;
20 | border-radius: 12px;
21 | background: #fff;
22 | color: #888;
23 | box-shadow: 0 0 24px #f4f4f4;
24 | text-align: center;
25 | }
26 | .header svg {
27 | height: 48px;
28 | }
29 |
30 | .content {
31 | flex-grow: 1;
32 | display: flex;
33 | align-items: center;
34 | }
35 | .content_i {
36 | flex-grow: 1;
37 | padding: 24px 5%;
38 | }
39 | .content a {
40 | color: #00617b;
41 | }
42 | .content a:hover {
43 | color: #1191b3;
44 | }
45 |
46 | .footer {
47 | border-top: 1px solid #e6e8ec;
48 | margin: 24px 24px 0;
49 | padding: 24px;
50 | text-align: center;
51 | }
52 |
53 | .footer_copyright a {
54 | color: #838b99;
55 | text-decoration: none;
56 | }
57 |
58 | .footer_copyright a:hover {
59 | color: #0b7794;
60 | text-decoration: underline;
61 | }
62 |
63 | .footer_icons {
64 | padding-top: 16px;
65 | display: flex;
66 | justify-content: center;
67 | }
68 |
69 | .footer_icons a {
70 | margin: 0 12px;
71 | text-decoration: none;
72 | }
73 |
74 | .footer_icons svg {
75 | height: 32px;
76 | fill: #838b99;
77 | }
78 |
79 | .footer_icons a:hover svg {
80 | fill: #0b7794;
81 | }
82 |
83 | .text-center {
84 | text-align: center;
85 | }
86 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM composer/composer:2-bin AS composer
2 |
3 | FROM dunglas/frankenphp:1-php8.2-bookworm AS base
4 |
5 | RUN apt update && apt -y install \
6 | unzip
7 |
8 | RUN install-php-extensions \
9 | opcache \
10 | mbstring \
11 | intl \
12 | dom \
13 | ctype \
14 | curl \
15 | phar \
16 | openssl \
17 | xml \
18 | xmlwriter \
19 | simplexml \
20 | pdo
21 |
22 | #
23 | # Development
24 | #
25 |
26 | FROM base AS dev
27 | ARG USER_ID=10001
28 | ARG GROUP_ID=10001
29 | ARG USER_NAME=appuser
30 | ARG GROUP_NAME=appuser
31 |
32 | RUN install-php-extensions \
33 | xdebug
34 |
35 | COPY --from=composer /composer /usr/bin/composer
36 |
37 | # Based on https://frankenphp.dev/docs/docker/#running-as-a-non-root-user
38 | RUN \
39 | groupadd --gid ${GROUP_ID} ${GROUP_NAME}; \
40 | useradd --gid ${GROUP_ID} --uid ${USER_ID} ${GROUP_NAME}; \
41 | # Add additional capability to bind to port 80 and 443 \
42 | setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \
43 | # Give write access to /data/caddy and /config/caddy \
44 | chown -R ${USER_NAME}:${GROUP_NAME} /data/caddy && chown -R ${USER_NAME}:${GROUP_NAME} /config/caddy
45 | USER ${USER_NAME}
46 |
47 | #
48 | # Production
49 | #
50 |
51 | FROM base AS prod-builder
52 | COPY --from=composer /composer /usr/bin/composer
53 | COPY .. /app
54 | RUN --mount=type=cache,target=/tmp/cache \
55 | composer install --no-dev --no-progress --no-interaction --classmap-authoritative && \
56 | rm composer.lock composer.json
57 |
58 | FROM base AS prod
59 | ENV APP_ENV=prod
60 | COPY --from=prod-builder --chown=www-data:www-data /app /app
61 | USER www-data
62 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | setLevels([
50 | LogLevel::EMERGENCY,
51 | LogLevel::ERROR,
52 | LogLevel::WARNING,
53 | ]),
54 | ],
55 | ),
56 | new HtmlRenderer(),
57 | ),
58 | );
59 | $runner->run();
60 |
--------------------------------------------------------------------------------
/config/configuration.php:
--------------------------------------------------------------------------------
1 | [
10 | 'params' => 'common/params.php',
11 | 'params-web' => [
12 | '$params',
13 | 'web/params.php',
14 | ],
15 | 'params-console' => [
16 | '$params',
17 | 'console/params.php',
18 | ],
19 | 'di' => 'common/di/*.php',
20 | 'di-web' => [
21 | '$di',
22 | 'web/di/*.php',
23 | ],
24 | 'di-console' => '$di',
25 | 'di-delegates' => [],
26 | 'di-delegates-console' => '$di-delegates',
27 | 'di-delegates-web' => '$di-delegates',
28 | 'di-providers' => [],
29 | 'di-providers-web' => [
30 | '$di-providers',
31 | ],
32 | 'di-providers-console' => [
33 | '$di-providers',
34 | ],
35 | 'events' => [],
36 | 'events-web' => ['$events'],
37 | 'events-console' => ['$events'],
38 | 'routes' => 'common/routes.php',
39 | 'bootstrap' => 'common/bootstrap.php',
40 | 'bootstrap-web' => '$bootstrap',
41 | 'bootstrap-console' => '$bootstrap',
42 | ],
43 | 'config-plugin-environments' => [
44 | Environment::DEV => [
45 | 'params' => [
46 | 'environments/dev/params.php',
47 | ],
48 | ],
49 | Environment::TEST => [
50 | 'params' => [
51 | 'environments/test/params.php',
52 | ],
53 | ],
54 | Environment::PROD => [
55 | 'params' => [
56 | 'environments/prod/params.php',
57 | ],
58 | ],
59 | ],
60 | 'config-plugin-options' => [
61 | 'source-directory' => 'config',
62 | ],
63 | ];
64 |
--------------------------------------------------------------------------------
/config/web/di/application.php:
--------------------------------------------------------------------------------
1 | [
25 | '__construct()' => [
26 | 'dispatcher' => DynamicReference::to([
27 | 'class' => MiddlewareDispatcher::class,
28 | 'withMiddlewares()' => [
29 | [
30 | ErrorCatcher::class,
31 | SessionMiddleware::class,
32 | CsrfTokenMiddleware::class,
33 | FormatDataResponse::class,
34 | RequestCatcherMiddleware::class,
35 | Router::class,
36 | ],
37 | ],
38 | ]),
39 | 'fallbackHandler' => Reference::to(NotFoundHandler::class),
40 | ],
41 | ],
42 |
43 | ParametersResolverInterface::class => [
44 | 'class' => CompositeParametersResolver::class,
45 | '__construct()' => [
46 | Reference::to(HydratorAttributeParametersResolver::class),
47 | Reference::to(RequestInputParametersResolver::class),
48 | ],
49 | ],
50 | ];
51 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yiisoft/app",
3 | "type": "project",
4 | "description": "Yii3 web application template",
5 | "keywords": [
6 | "yii3",
7 | "app"
8 | ],
9 | "license": "BSD-3-Clause",
10 | "support": {
11 | "issues": "https://github.com/yiisoft/app/issues?state=open",
12 | "source": "https://github.com/yiisoft/app",
13 | "forum": "https://www.yiiframework.com/forum/",
14 | "wiki": "https://www.yiiframework.com/wiki/",
15 | "irc": "ircs://irc.libera.chat:6697/yii",
16 | "chat": "https://t.me/yii3en"
17 | },
18 | "funding": [
19 | {
20 | "type": "opencollective",
21 | "url": "https://opencollective.com/yiisoft"
22 | },
23 | {
24 | "type": "github",
25 | "url": "https://github.com/sponsors/yiisoft"
26 | }
27 | ],
28 | "scripts": {
29 | "serve": [
30 | "Composer\\Config::disableProcessTimeout",
31 | "@php ./yii serve"
32 | ],
33 | "test": "codecept run"
34 | },
35 | "require": {
36 | "php": "8.2 - 8.5",
37 | "ext-filter": "*",
38 | "httpsoft/http-message": "^1.1.6",
39 | "psr/container": "^2.0.2",
40 | "psr/http-factory": "^1.1",
41 | "psr/http-message": "^2.0",
42 | "psr/http-server-handler": "^1.0.2",
43 | "psr/log": "^3.0.2",
44 | "symfony/console": "^7.4.1",
45 | "yiisoft/aliases": "^3.1.1",
46 | "yiisoft/assets": "^5.1.2",
47 | "yiisoft/config": "^1.6.2",
48 | "yiisoft/csrf": "^2.2.3",
49 | "yiisoft/data-response": "^2.1.2",
50 | "yiisoft/definitions": "^3.4.1",
51 | "yiisoft/di": "^1.4.1",
52 | "yiisoft/error-handler": "^4.3.1",
53 | "yiisoft/html": "^3.12",
54 | "yiisoft/http": "^1.3",
55 | "yiisoft/input-http": "^1.0.1",
56 | "yiisoft/log": "^2.2.0",
57 | "yiisoft/log-target-file": "^3.1",
58 | "yiisoft/middleware-dispatcher": "^5.4",
59 | "yiisoft/request-provider": "^1.2",
60 | "yiisoft/router": "^4.0.2",
61 | "yiisoft/router-fastroute": "^4.0.3",
62 | "yiisoft/session": "^3.0.1",
63 | "yiisoft/view": "^12.2.2",
64 | "yiisoft/yii-console": "^2.4.2",
65 | "yiisoft/yii-http": "^1.1.1",
66 | "yiisoft/yii-runner-console": "^2.2.1",
67 | "yiisoft/yii-runner-http": "^3.2.1",
68 | "yiisoft/yii-view-renderer": "^7.3.1"
69 | },
70 | "require-dev": {
71 | "codeception/c3": "^2.9",
72 | "codeception/codeception": "^5.3.3",
73 | "codeception/module-asserts": "^3.2.1",
74 | "codeception/module-cli": "^2.0.1",
75 | "codeception/module-phpbrowser": "^3.0.2",
76 | "friendsofphp/php-cs-fixer": "^3.92.3",
77 | "phpunit/phpunit": "^11.5.46",
78 | "rector/rector": "^2.2.14",
79 | "roave/infection-static-analysis-plugin": "^1.40",
80 | "roave/security-advisories": "dev-latest",
81 | "shipmonk/composer-dependency-analyser": "^1.8.4",
82 | "vimeo/psalm": "^6.14.2"
83 | },
84 | "autoload": {
85 | "psr-4": {
86 | "App\\": "src"
87 | }
88 | },
89 | "autoload-dev": {
90 | "psr-4": {
91 | "App\\Tests\\": "tests"
92 | }
93 | },
94 | "extra": {
95 | "config-plugin-file": "config/configuration.php"
96 | },
97 | "config": {
98 | "sort-packages": true,
99 | "bump-after-update": true,
100 | "allow-plugins": {
101 | "yiisoft/config": true,
102 | "infection/extension-installer": true,
103 | "codeception/c3": true,
104 | "composer/installers": true
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/Environment.php:
--------------------------------------------------------------------------------
1 | register(MainAsset::class);
20 |
21 | $this->addCssFiles($assetManager->getCssFiles());
22 | $this->addCssStrings($assetManager->getCssStrings());
23 | $this->addJsFiles($assetManager->getJsFiles());
24 | $this->addJsStrings($assetManager->getJsStrings());
25 | $this->addJsVars($assetManager->getJsVars());
26 |
27 | $this->beginPage()
28 | ?>
29 |
30 |
31 |
32 |
33 |
34 |
35 | = Html::encode($this->getTitle()) ?>
36 | head() ?>
37 |
38 |
39 | beginBody() ?>
40 |
41 |
69 |
70 |
71 |
72 | = $content ?>
73 |
74 |
75 |
76 |
124 |
125 | endBody() ?>
126 |
127 |
128 | endPage() ?>
129 |
--------------------------------------------------------------------------------