Skip to content

Commit 3b08793

Browse files
authored
Addons can get their directory without needing it in the manifest (#2761)
1 parent 99e812e commit 3b08793

File tree

5 files changed

+77
-27
lines changed

5 files changed

+77
-27
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"autoload-dev": {
6565
"psr-4": {
6666
"Tests\\": "tests",
67-
"Foo\\Bar\\": "tests/fixtures/Addon"
67+
"Foo\\Bar\\": "tests/Fixtures/Addon"
6868
}
6969
}
7070
}

src/Extend/Addon.php

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Statamic\Extend;
44

55
use Facades\Statamic\Licensing\LicenseManager;
6+
use ReflectionClass;
67
use Statamic\Facades\File;
78
use Statamic\Facades\Path;
89
use Statamic\Facades\URL;
@@ -63,6 +64,13 @@ final class Addon
6364
*/
6465
protected $autoload;
6566

67+
/**
68+
* The service provider class.
69+
*
70+
* @var string
71+
*/
72+
protected $provider;
73+
6674
/**
6775
* The name of the addon. eg. "Bloodhound Search".
6876
*
@@ -162,8 +170,8 @@ public static function makeFromPackage(array $package)
162170
$instance = self::make($package['id']);
163171

164172
$keys = [
165-
'id', 'slug', 'editions', 'marketplaceId', 'marketplaceSlug', 'marketplaceSellerSlug', 'name', 'namespace', 'directory',
166-
'autoload', 'description', 'package', 'version', 'latestVersion', 'url', 'developer', 'developerUrl', 'isCommercial',
173+
'id', 'slug', 'editions', 'marketplaceId', 'marketplaceSlug', 'marketplaceSellerSlug', 'name', 'namespace',
174+
'autoload', 'provider', 'description', 'package', 'version', 'latestVersion', 'url', 'developer', 'developerUrl', 'isCommercial',
167175
];
168176

169177
foreach (Arr::only($package, $keys) as $key => $value) {
@@ -297,7 +305,7 @@ public function name($name = null)
297305
public function hasFile($path)
298306
{
299307
if (! $this->directory()) {
300-
throw new \Exception('Cannot check files without a directory specified.');
308+
throw new \Exception('Cannot check files without a provider specified.');
301309
}
302310

303311
return File::exists(Path::assemble($this->directory(), $path));
@@ -312,7 +320,7 @@ public function hasFile($path)
312320
public function getFile($path)
313321
{
314322
if (! $this->directory()) {
315-
throw new \Exception('Cannot get files without a directory specified.');
323+
throw new \Exception('Cannot get files without a provider specified.');
316324
}
317325

318326
return File::get(Path::assemble($this->directory(), $path));
@@ -327,7 +335,7 @@ public function getFile($path)
327335
public function putFile($path, $contents)
328336
{
329337
if (! $this->directory()) {
330-
throw new \Exception('Cannot write files without a directory specified.');
338+
throw new \Exception('Cannot write files without a provider specified.');
331339
}
332340

333341
File::put(
@@ -393,6 +401,28 @@ public function __call($method, $args)
393401
return $this;
394402
}
395403

404+
/**
405+
* The directory the package is located within. eg. "/path/to/vendor/statamic/bloodhound".
406+
*
407+
* @return string
408+
*/
409+
public function directory()
410+
{
411+
if (! $this->provider) {
412+
return null;
413+
}
414+
415+
if ($this->directory) {
416+
return $this->directory;
417+
}
418+
419+
$reflector = new ReflectionClass($this->provider);
420+
421+
$dir = Str::removeRight(dirname($reflector->getFileName()), rtrim($this->autoload, '/'));
422+
423+
return $this->directory = Str::removeRight($dir, '/');
424+
}
425+
396426
public function existsOnMarketplace()
397427
{
398428
return $this->marketplaceSlug() !== null;

src/Extend/Manifest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ protected function formatPackage($package)
6060
'latestVersion' => data_get($marketplaceData, 'latest_version', null),
6161
'version' => Str::removeLeft($package['version'], 'v'),
6262
'namespace' => $namespace,
63-
'directory' => $directory,
6463
'autoload' => $autoload,
64+
'provider' => $provider,
6565

6666
// Local data for marketplace GUI?
6767
'name' => $statamic['name'] ?? Arr::last($providerParts),

tests/Extend/AddonTest.php

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,22 @@
33
namespace Statamic\Testing\Extend;
44

55
use Facades\Statamic\Licensing\LicenseManager;
6+
use Foo\Bar\TestAddonServiceProvider;
67
use Illuminate\Support\Collection;
78
use Statamic\Extend\Addon;
89
use Statamic\Facades\File;
910
use Tests\TestCase;
1011

1112
class AddonTest extends TestCase
1213
{
14+
protected $addonFixtureDir;
15+
16+
public function setUp(): void
17+
{
18+
parent::setUp();
19+
$this->addonFixtureDir = realpath(__DIR__.'/../Fixtures/Addon');
20+
}
21+
1322
/** @test */
1423
public function it_creates_an_instance_with_a_name()
1524
{
@@ -100,7 +109,8 @@ public function it_creates_an_instance_from_a_package()
100109
$this->assertEquals('Test Addon', $addon->name());
101110
$this->assertEquals('Test description', $addon->description());
102111
$this->assertEquals('Vendor\\TestAddon', $addon->namespace());
103-
$this->assertEquals('/path/to/addon', $addon->directory());
112+
$this->assertEquals($this->addonFixtureDir, $addon->directory());
113+
$this->assertEquals('', $addon->autoload());
104114
$this->assertEquals('http://test-url.com', $addon->url());
105115
$this->assertEquals('Test Developer LLC', $addon->developer());
106116
$this->assertEquals('http://test-developer.com', $addon->developerUrl());
@@ -111,10 +121,10 @@ public function it_creates_an_instance_from_a_package()
111121
/** @test */
112122
public function it_checks_if_a_file_exists()
113123
{
114-
$addon = Addon::make('Test Addon')->directory('/path/to/addon');
124+
$addon = $this->makeFromPackage();
115125

116-
File::shouldReceive('exists')->with('/path/to/addon/test.txt')->andReturnTrue();
117-
File::shouldReceive('exists')->with('/path/to/addon/notfound.txt')->andReturnFalse();
126+
File::shouldReceive('exists')->with($this->addonFixtureDir.'/test.txt')->andReturnTrue();
127+
File::shouldReceive('exists')->with($this->addonFixtureDir.'/notfound.txt')->andReturnFalse();
118128

119129
$this->assertTrue($addon->hasFile('test.txt'));
120130
$this->assertFalse($addon->hasFile('notfound.txt'));
@@ -123,33 +133,33 @@ public function it_checks_if_a_file_exists()
123133
/** @test */
124134
public function it_gets_file_contents()
125135
{
126-
$addon = Addon::make('Test Addon')->directory('/path/to/addon');
136+
$addon = $this->makeFromPackage();
127137

128-
File::shouldReceive('get')->with('/path/to/addon/test.txt')->andReturn('the file contents');
138+
File::shouldReceive('get')->with($this->addonFixtureDir.'/test.txt')->andReturn('the file contents');
129139

130140
$this->assertEquals('the file contents', $addon->getFile('test.txt'));
131141
}
132142

133143
/** @test */
134144
public function it_writes_file_contents()
135145
{
136-
$addon = Addon::make('Test Addon')->directory('/path/to/addon');
146+
$addon = $this->makeFromPackage();
137147

138-
File::shouldReceive('put')->with('/path/to/addon/test.txt', 'the file contents');
148+
File::shouldReceive('put')->with($this->addonFixtureDir.'/test.txt', 'the file contents');
139149

140150
$addon->putFile('test.txt', 'the file contents');
141151
}
142152

143153
/** @test */
144-
public function it_doesnt_allow_getting_files_if_no_directory_is_set()
154+
public function it_doesnt_allow_getting_files_if_no_provider_is_set()
145155
{
146156
File::spy();
147-
$addon = $this->makeFromPackage(['directory' => null]);
157+
$addon = $this->makeFromPackage(['provider' => null]);
148158

149159
try {
150160
$addon->getFile('foo.txt', 'foo');
151161
} catch (\Exception $e) {
152-
$this->assertEquals('Cannot get files without a directory specified.', $e->getMessage());
162+
$this->assertEquals('Cannot get files without a provider specified.', $e->getMessage());
153163
File::shouldNotHaveReceived('get');
154164

155165
return;
@@ -159,15 +169,15 @@ public function it_doesnt_allow_getting_files_if_no_directory_is_set()
159169
}
160170

161171
/** @test */
162-
public function it_doesnt_allow_checking_for_files_if_no_directory_is_set()
172+
public function it_doesnt_allow_checking_for_files_if_no_provider_is_set()
163173
{
164174
File::spy();
165-
$addon = $this->makeFromPackage(['directory' => null]);
175+
$addon = $this->makeFromPackage(['provider' => null]);
166176

167177
try {
168178
$addon->hasFile('foo.txt', 'foo');
169179
} catch (\Exception $e) {
170-
$this->assertEquals('Cannot check files without a directory specified.', $e->getMessage());
180+
$this->assertEquals('Cannot check files without a provider specified.', $e->getMessage());
171181
File::shouldNotHaveReceived('get');
172182

173183
return;
@@ -177,15 +187,15 @@ public function it_doesnt_allow_checking_for_files_if_no_directory_is_set()
177187
}
178188

179189
/** @test */
180-
public function it_doesnt_allow_writing_files_if_no_directory_is_set()
190+
public function it_doesnt_allow_writing_files_if_no_provider_is_set()
181191
{
182192
File::spy();
183-
$addon = $this->makeFromPackage(['directory' => null]);
193+
$addon = $this->makeFromPackage(['provider' => null]);
184194

185195
try {
186196
$addon->putFile('foo.txt', 'foo');
187197
} catch (\Exception $e) {
188-
$this->assertEquals('Cannot write files without a directory specified.', $e->getMessage());
198+
$this->assertEquals('Cannot write files without a provider specified.', $e->getMessage());
189199
File::shouldNotHaveReceived('put');
190200

191201
return;
@@ -230,15 +240,15 @@ public function it_gets_the_license()
230240
$this->assertEquals('the license', Addon::make('foo/bar')->license());
231241
}
232242

233-
private function makeFromPackage($attributes)
243+
private function makeFromPackage($attributes = [])
234244
{
235245
return Addon::makeFromPackage(array_merge([
236246
'id' => 'vendor/test-addon',
237247
'name' => 'Test Addon',
238248
'description' => 'Test description',
239249
'namespace' => 'Vendor\\TestAddon',
240-
'directory' => '/path/to/addon',
241-
'autoload' => 'src',
250+
'provider' => TestAddonServiceProvider::class,
251+
'autoload' => '',
242252
'url' => 'http://test-url.com',
243253
'developer' => 'Test Developer LLC',
244254
'developerUrl' => 'http://test-developer.com',
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Foo\Bar;
4+
5+
use Statamic\Providers\AddonServiceProvider;
6+
7+
class TestAddonServiceProvider extends AddonServiceProvider
8+
{
9+
//
10+
}

0 commit comments

Comments
 (0)