spiral / app

Spiral Framework Skeleton HTTP Application: Queue, Console, Cycle ORM
https://spiral.dev/
MIT License
190 stars 20 forks source link

Changing folder structure. #83

Closed nbish11 closed 1 year ago

nbish11 commented 1 year ago

I would like to use this package and when I follow the documentation and install it, everything works in its default state. However, I need to change the directory structure of the app, instead of having everything under the app folder, I would like everything under the root folder instead. No matter how I try to configure the application, it doesn't work. The documentation states I can change directories in the mapDirectories method, and after a dump, everything points to the right place.

This is the error I keep getting:

2022-11-12T16:27:41.731+1000    DEBUG   rpc             plugin was started      {"address": "tcp://127.0.0.1:6001", "list of the plugins with RPC methods:": ["metrics", "jobs", "kv", "informer", "resetter"]}
[INFO] RoadRunner server started; version: 2.11.4, buildtime: 2022-10-06T14:43:01+0000
2022-11-12T16:28:41.731+1000    ERROR   container/poller.go:16  vertex got an error     {"id": "http.Plugin", "error": "static_pool_allocate_workers: WorkerAllocate: failed to spawn a worker, possible reasons: https://roadrunner.dev/docs/known-issues-allocate-timeout/2.x/en"}
github.com/roadrunner-server/endure/pkg/container.(*Endure).poll.func1
        github.com/roadrunner-server/endure@v1.4.5/pkg/container/poller.go:16
2022-11-12T16:29:11.751+1000    ERROR   container/stop.go:147   vertices which are not stopped  {"id": ["logger.Plugin", "server.Plugin", "static.Plugin", "gzip.Plugin", "prometheus.Plugin", "send.Plugin", "memory.Plugin", "boltdb.Plugin", "redis.Plugin", "kv.Plugin", "memcached.Plugin", "config.Plugin"]}
github.com/roadrunner-server/endure/pkg/container.(*Endure).shutdown
        github.com/roadrunner-server/endure@v1.4.5/pkg/container/stop.go:147
github.com/roadrunner-server/endure/pkg/container.(*Endure).Shutdown
        github.com/roadrunner-server/endure@v1.4.5/pkg/container/endure.go:468
reflect.Value.call
        reflect/value.go:584
reflect.Value.Call
        reflect/value.go:368
github.com/roadrunner-server/endure/pkg/fsm.(*FSMImpl).Transition
        github.com/roadrunner-server/endure@v1.4.5/pkg/fsm/fsm.go:216
github.com/roadrunner-server/endure/pkg/container.(*Endure).Stop
        github.com/roadrunner-server/endure@v1.4.5/pkg/container/endure.go:340
github.com/roadrunner-server/endure/pkg/container.(*Endure).startMainThread.func1
        github.com/roadrunner-server/endure@v1.4.5/pkg/container/poller.go:52
2022-11-12T16:29:11.751+1000    ERROR   container/poller.go:54  error during stopping vertex    {"id": "http.Plugin", "error": "endure_shutdown: Timeout: timeout exceed, some vertices may not be stopped and can cause memory leak"}
github.com/roadrunner-server/endure/pkg/container.(*Endure).startMainThread.func1
        github.com/roadrunner-server/endure@v1.4.5/pkg/container/poller.go:54
error: static_pool_allocate_workers: WorkerAllocate: failed to spawn a worker, possible reasons: https://roadrunner.dev/docs/known-issues-allocate-timeout/2.x/en
plugin: http.Plugin

This is my mapDirectories() method:

protected function mapDirectories(array $directories): array
    {
        if (!isset($directories['root'])) {
            throw new BootException('Missing required directory `root`');
        }

        if (!isset($directories['app'])) {
            $directories['app'] = $directories['root'] . '/';
        }

        $directories = \array_merge(
            [       // public root
                'app' => $directories['root'] . '/',
                // public root
                'public' => $directories['root'] . '/public/',
                // vendor libraries
                'vendor' => $directories['root'] . '/vendor/',
                // data directories
                'runtime' => $directories['root'] . '/runtime/',
                'cache' => $directories['root'] . '/runtime/cache/',
                // application directories
                'config' => $directories['root'] . '/config/',
                'resources' => $directories['root'] . '/resources/',
            ],
            $directories
        );

        return $directories;
    }

My folder structure:

root
|- /config
|- /locale
|- /migrations
|- /public
|- /runtime
|- /src
|- /tests
|- /vendor
|- /views
|- ...
|- .rr.yaml
|- app.php
|- composer.json
|- rr
|- ...

If I reset everything back to defaults, there are no problems. I have change no other files other than directory paths in.

butschster commented 1 year ago

Hi! You just need to open app.php file and use something like below

$app = App::create(
    directories: [
        'root' => __DIR__,
        'app' => __DIR__ . '/',
    ]
)->run();

But I don't recommend to use root directory for Application, it's not secure.

butschster commented 1 year ago

You need also change autoloader namespaces in composer.json


    "autoload": {
        "psr-4": {
            "App\\": "app/src" <============
        }
    },
nbish11 commented 1 year ago

I re-installed Spiral from scratch, made only the changes you gave, and ran composer dump-autoload. I have also tried to run php app.php configure -vvv, which just hangs, and I have to force quit. Unfortunately, is still does not work.

May I ask why it is insecure to run from root directory?

butschster commented 1 year ago

Oh, I missed that you have src folder for all your source code.

butschster commented 1 year ago

I'll try to check it by myself

nbish11 commented 1 year ago

Thanks

butschster commented 1 year ago

@nbish11 I investigated the problem and found the solution.

The reason of the problem is tokenizer component. By default, when you start an application it starts to iterate classes in application directory. But if you set as application directory root - Tokenizer start to scan vendor directory also, but there are some classes can not be parsed by tokenizer and it throws an exception.

There are two ways to solve the problem:

  1. Fix mapDirectories method. Somethig like code below
protected function mapDirectories(array $directories): array
{
    $directories['app'] = $directories['root'] . '/src/';
    $directories['config'] = $directories['root'] . '/config/';
    $directories['resources'] = $directories['root'] . '/resources/';

    return parent::mapDirectories($directories);
}
  1. Create tokenizer.php config file on your config directory and fix application path
<?php

declare(strict_types=1);

return [
    'debug' => false,
    'directories' => [
        directory('app') . '/src', <---------- Scan only inside src directory
    ],
    'exclude' => [
        directory('resources'),
        directory('config'),
        'tests',
        'migrations',
    ],
];

P.S. Don't forget fix paths in composer.json

"autoload": {
        "psr-4": {
            "App\\": "src"  <=========
        },
        "files": [
            "src/Application/helpers.php"  <=========
        ]
    },

I hope it will help you!

nbish11 commented 1 year ago

I went with the second option, everything works perfectly now! Thank you for your help.