• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

orchestral / testbench-core / 17420988551

03 Sep 2025 02:10AM UTC coverage: 91.914% (-0.2%) from 92.083%
17420988551

push

github

web-flow
Add `Orchestra\Testbench\uses_default_skeleton()` function and fix loading framework configuration from `laravel/framework` repository (#358)

* Add `Orchestra\Testbench\uses_default_skeleton` function

Also fix loading framework configuration

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

---------

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

4 of 4 new or added lines in 3 files covered. (100.0%)

3 existing lines in 1 file now uncovered.

1546 of 1682 relevant lines covered (91.91%)

76.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.89
/src/Bootstrap/LoadConfiguration.php
1
<?php
2

3
namespace Orchestra\Testbench\Bootstrap;
4

5
use Generator;
6
use Illuminate\Config\Repository;
7
use Illuminate\Contracts\Config\Repository as RepositoryContract;
8
use Illuminate\Contracts\Foundation\Application;
9
use Illuminate\Support\Collection;
10
use Illuminate\Support\LazyCollection;
11
use Orchestra\Sidekick\Env;
12
use RuntimeException;
13
use SplFileInfo;
14
use Symfony\Component\Finder\Finder;
15

16
use function Orchestra\Testbench\default_skeleton_path;
17
use function Orchestra\Testbench\package_path;
18
use function Orchestra\Testbench\uses_default_skeleton;
19

20
/**
21
 * @internal
22
 *
23
 * @phpstan-type TLaravel \Illuminate\Contracts\Foundation\Application
24
 */
25
class LoadConfiguration
26
{
27
    /**
28
     * Cached Laravel Framework default configuration.
29
     *
30
     * @var \Illuminate\Contracts\Config\Repository|null
31
     */
32
    protected static ?RepositoryContract $cachedFrameworkConfigurations = null;
33

34
    /**
35
     * Bootstrap the given application.
36
     *
37
     * @param  TLaravel  $app
38
     * @return void
39
     */
40
    public function bootstrap(Application $app): void
41
    {
42
        $app->instance('config', $config = new Repository([]));
190✔
43

44
        $this->loadConfigurationFiles($app, $config);
190✔
45

46
        if (\is_null($config->get('database.connections.testing'))) {
190✔
47
            $config->set('database.connections.testing', [
190✔
48
                'driver' => 'sqlite',
190✔
49
                'database' => ':memory:',
190✔
50
                'foreign_key_constraints' => Env::get('DB_FOREIGN_KEYS', false),
190✔
51
            ]);
190✔
52
        }
53

54
        $this->configureDefaultDatabaseConnection($config);
190✔
55

56
        mb_internal_encoding('UTF-8');
190✔
57
    }
58

59
    /**
60
     * Load the configuration items from all of the files.
61
     *
62
     * @param  TLaravel  $app
63
     * @param  \Illuminate\Contracts\Config\Repository  $config
64
     * @return void
65
     */
66
    private function loadConfigurationFiles(Application $app, RepositoryContract $config): void
67
    {
68
        $shouldMerge = method_exists($app, 'shouldMergeFrameworkConfiguration')
190✔
69
            ? $app->shouldMergeFrameworkConfiguration()
190✔
70
            : true;
×
71

72
        static::$cachedFrameworkConfigurations ??= new Repository(
190✔
73
            (new Collection(uses_default_skeleton($app->basePath()) ? [] : $this->getFrameworkDefaultConfigurations()))
190✔
74
                ->transform(fn ($path, $key) => require $path)
190✔
75
                ->all()
190✔
76
        );
190✔
77

78
        $this->extendsLoadedConfiguration(
190✔
79
            (new LazyCollection(function () use ($app) {
190✔
80
                $path = $this->getConfigurationPath($app);
190✔
81

82
                if (\is_string($path)) {
190✔
83
                    yield from $this->getConfigurationsFromPath($path);
190✔
84
                }
85
            }))
190✔
86
                ->collect()
190✔
87
                ->transform(fn ($path, $key) => $this->resolveConfigurationFile($path, $key))
190✔
88
        )->each(static function ($path, $key) use ($config) {
190✔
89
            $config->set($key, require $path);
190✔
90
        })->when($shouldMerge === true, static function ($configurations) use ($config) {
190✔
91
            /** @var \Illuminate\Contracts\Config\Repository $baseConfigurations */
92
            $baseConfigurations = static::$cachedFrameworkConfigurations;
190✔
93

94
            /** @var array<int, string> $excludes */
95
            $excludes = $configurations->keys()->all();
190✔
96

97
            (new Collection($baseConfigurations->all()))->reject(
190✔
98
                fn ($data, $key) => \in_array($key, $excludes)
190✔
99
            )->each(function ($data, $key) use ($config) {
190✔
100
                $config->set($key, $data);
×
101
            });
190✔
102

103
            return $configurations->each(static function ($data, $key) use ($config, $baseConfigurations) {
190✔
104
                foreach (static::mergeableOptions($key) as $option) {
190✔
105
                    $name = "{$key}.{$option}";
190✔
106

107
                    $config->set($name, array_merge(($baseConfigurations->get($name) ?? []), ($config->get($name) ?? [])));
190✔
108
                }
109
            });
190✔
110
        });
190✔
111
    }
112

113
    /**
114
     * Get the configuration file nesting path.
115
     *
116
     * @param  \SplFileInfo  $file
117
     * @param  string  $configPath
118
     * @return string
119
     */
120
    protected function getNestedDirectory(SplFileInfo $file, string $configPath): string
121
    {
122
        $directory = $file->getPath();
190✔
123

124
        if ($nested = trim(str_replace($configPath, '', $directory), DIRECTORY_SEPARATOR)) {
190✔
125
            $nested = str_replace(DIRECTORY_SEPARATOR, '.', $nested).'.';
61✔
126
        }
127

128
        return $nested;
190✔
129
    }
130

131
    /**
132
     * Resolve the configuration file.
133
     *
134
     * @param  string  $path
135
     * @param  string  $key
136
     * @return string
137
     */
138
    protected function resolveConfigurationFile(string $path, string $key): string
139
    {
140
        return $path;
140✔
141
    }
142

143
    /**
144
     * Extend the loaded configuration.
145
     *
146
     * @param  \Illuminate\Support\Collection  $configurations
147
     * @return \Illuminate\Support\Collection
148
     */
149
    protected function extendsLoadedConfiguration(Collection $configurations): Collection
150
    {
151
        return $configurations;
140✔
152
    }
153

154
    /**
155
     * Configure the default database connection.
156
     *
157
     * @param  \Illuminate\Contracts\Config\Repository  $config
158
     * @return void
159
     */
160
    protected function configureDefaultDatabaseConnection(RepositoryContract $config): void
161
    {
162
        if ($config->get('database.default') === 'sqlite' && ! is_file($config->get('database.connections.sqlite.database'))) {
190✔
163
            $config->set('database.default', 'testing');
90✔
164
        }
165
    }
166

167
    /**
168
     * Get the application configuration path.
169
     *
170
     * @param  TLaravel  $app
171
     * @return string
172
     *
173
     * @throws \RuntimeException
174
     */
175
    protected function getConfigurationPath(Application $app): string
176
    {
177
        $configurationPath = is_dir($app->basePath('config'))
190✔
178
            ? $app->basePath('config')
190✔
179
            : default_skeleton_path('config');
×
180

181
        if ($configurationPath === false) {
190✔
182
            throw new RuntimeException('Unable to locate configuration path');
×
183
        }
184

185
        return $configurationPath;
190✔
186
    }
187

188
    /**
189
     * Get the framework default configurations.
190
     *
191
     * @return array<string, string>
192
     */
193
    protected function getFrameworkDefaultConfigurations(): array
194
    {
UNCOV
195
        return (new LazyCollection(function () {
×
UNCOV
196
            yield from $this->getConfigurationsFromPath(package_path(['vendor', 'laravel', 'framework', 'config']));
×
UNCOV
197
        }))->all();
×
198
    }
199

200
    /**
201
     * Get the configurations from path.
202
     *
203
     * @param  string  $path
204
     * @return \Generator
205
     */
206
    protected function getConfigurationsFromPath(string $path): Generator
207
    {
208
        foreach (Finder::create()->files()->name('*.php')->in($path) as $file) {
190✔
209
            $directory = $this->getNestedDirectory($file, $path);
190✔
210

211
            yield $directory.basename($file->getRealPath(), '.php') => $file->getRealPath();
190✔
212
        }
213
    }
214

215
    /**
216
     * Get the options within the configuration file that should be merged again.
217
     *
218
     * @param  string  $name
219
     * @return array<int, string>
220
     */
221
    public static function mergeableOptions(string $name): array
222
    {
223
        return [
224
            'auth' => ['guards', 'providers', 'passwords'],
225
            'broadcasting' => ['connections'],
226
            'cache' => ['stores'],
227
            'database' => ['connections'],
228
            'filesystems' => ['disks'],
229
            'logging' => ['channels'],
230
            'mail' => ['mailers'],
231
            'queue' => ['connections'],
232
        ][$name] ?? [];
190✔
233
    }
234
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc