Skip to content

Commit 24297e9

Browse files
authored
Merge pull request #124 from sebastienheyd/master
Widgets Namespaces
2 parents b3e533b + a886814 commit 24297e9

File tree

10 files changed

+156
-5
lines changed

10 files changed

+156
-5
lines changed

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,31 @@ Widget::group('sidebar')->removeAll(); // Widget group is empty now
383383
`Widget::group('sidebar')->any(); // bool`
384384

385385
`Widget::group('sidebar')->count(); // int`
386+
387+
## Namespaces for third party packages (extra)
388+
389+
In some cases, it may be useful to deliver widgets with your own packages. For example, if your package allows
390+
you to manage news, it would be convenient to have immediately configurable widgets, ready for display, directly
391+
delivered with your package.
392+
393+
To avoid having to use the fqcn each time, you can set a widget namespace into your package provider. This way the
394+
widgets from your package can be more easily identified, and especially the syntax will be shorter.
395+
396+
To do that, all you have to do is to register the namespace in your package service provider :
397+
398+
```php
399+
public function boot()
400+
{
401+
app('arrilot.widget-namespaces')->registerNamespace('my-package-name', '\VendorName\PackageName\Path\To\Widgets');
402+
}
403+
```
404+
405+
After that you can use the namespace in your views :
406+
407+
```php
408+
@widget('my-package-name::foo.bar')
409+
410+
// is equivalent to
411+
@widget('\VendorName\PackageName\Path\To\Widgets\Foo\Bar')
412+
```
413+

src/Console/WidgetMakeCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ protected function makeViewName()
224224
// convert to snake_case part by part to avoid unexpected underscores.
225225
$nameArray = explode('/', $name);
226226
array_walk($nameArray, function (&$part) {
227-
$part = snake_case($part);
227+
$part = Str::snake($part);
228228
});
229229

230230
return implode('/', $nameArray);

src/Contracts/ApplicationWrapperContract.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,13 @@ public function getNamespace();
5454
* @return mixed
5555
*/
5656
public function make($abstract, array $parameters = []);
57+
58+
/**
59+
* Wrapper around app()->get().
60+
*
61+
* @param string $id
62+
*
63+
* @return mixed
64+
*/
65+
public function get($id);
5766
}

src/Factories/AbstractWidgetFactory.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Arrilot\Widgets\Misc\InvalidWidgetClassException;
99
use Arrilot\Widgets\Misc\ViewExpressionTrait;
1010
use Arrilot\Widgets\WidgetId;
11+
use Illuminate\Support\Str;
1112

1213
abstract class AbstractWidgetFactory
1314
{
@@ -115,12 +116,21 @@ protected function instantiateWidget(array $params = [])
115116
{
116117
WidgetId::increment();
117118

118-
$this->widgetName = $this->parseFullWidgetNameFromString(array_shift($params));
119+
$str = array_shift($params);
120+
121+
if (preg_match('#^(.*?)::(.*?)$#', $str, $m)) {
122+
$rootNamespace = $this->app->get('arrilot.widget-namespaces')->getNamespace($m[1]);
123+
$str = $m[2];
124+
}
125+
126+
$this->widgetName = $this->parseFullWidgetNameFromString($str);
119127
$this->widgetFullParams = $params;
120128
$this->widgetConfig = (array) array_shift($params);
121129
$this->widgetParams = $params;
122130

123-
$rootNamespace = $this->app->config('laravel-widgets.default_namespace', $this->app->getNamespace().'Widgets');
131+
if (!isset($rootNamespace)) {
132+
$rootNamespace = $this->app->config('laravel-widgets.default_namespace', $this->app->getNamespace().'Widgets');
133+
}
124134

125135
$fqcn = $rootNamespace.'\\'.$this->widgetName;
126136
$widgetClass = class_exists($fqcn) ? $fqcn : $this->widgetName;
@@ -149,7 +159,7 @@ protected function instantiateWidget(array $params = [])
149159
*/
150160
protected function parseFullWidgetNameFromString($widgetName)
151161
{
152-
return studly_case(str_replace('.', '\\_', $widgetName));
162+
return Str::studly(str_replace('.', '\\_', $widgetName));
153163
}
154164

155165
/**

src/Misc/LaravelApplicationWrapper.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,18 @@ public function make($abstract, array $parameters = [])
9090
{
9191
return $this->app->make($abstract, $parameters);
9292
}
93+
94+
/**
95+
* Wrapper around app()->get().
96+
*
97+
* @param string $id
98+
*
99+
* @throws \Illuminate\Container\EntryNotFoundException
100+
*
101+
* @return mixed
102+
*/
103+
public function get($id)
104+
{
105+
return $this->app->get($id);
106+
}
93107
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Arrilot\Widgets\Misc;
4+
5+
use Exception;
6+
7+
class NamespaceNotFoundException extends Exception
8+
{
9+
}

src/NamespacesRepository.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace Arrilot\Widgets;
4+
5+
use Arrilot\Widgets\Misc\NamespaceNotFoundException;
6+
7+
class NamespacesRepository
8+
{
9+
/**
10+
* The array of namespaces.
11+
*
12+
* @var array
13+
*/
14+
protected $namespaces;
15+
16+
/**
17+
* Register a namespace.
18+
*
19+
* @param string $alias
20+
* @param string $namespace
21+
*
22+
* @return WidgetNamespaces
23+
*/
24+
public function registerNamespace($alias, $namespace)
25+
{
26+
$this->namespaces[$alias] = rtrim($namespace, '\\');
27+
28+
return $this;
29+
}
30+
31+
/**
32+
* Get namespace by his alias.
33+
*
34+
* @param string $label
35+
*
36+
* @throws \Exception
37+
*
38+
* @return string
39+
*/
40+
public function getNamespace($alias)
41+
{
42+
if (!isset($this->namespaces[$alias])) {
43+
throw new NamespaceNotFoundException('Namespace not found with the alias "'.$alias.'"');
44+
}
45+
46+
return $this->namespaces[$alias];
47+
}
48+
}

src/ServiceProvider.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ public function register()
3333
return new WidgetGroupCollection(new LaravelApplicationWrapper());
3434
});
3535

36+
$this->app->singleton('arrilot.widget-namespaces', function () {
37+
return new NamespacesRepository();
38+
});
39+
3640
$this->app->singleton('command.widget.make', function ($app) {
3741
return new WidgetMakeCommand($app['files']);
3842
});

tests/Support/TestApplicationWrapper.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
use Arrilot\Widgets\Contracts\ApplicationWrapperContract;
77
use Arrilot\Widgets\Factories\AsyncWidgetFactory;
88
use Arrilot\Widgets\Factories\WidgetFactory;
9-
use Illuminate\Container\Container;
9+
use Arrilot\Widgets\NamespacesRepository;
1010
use Closure;
1111
use Doctrine\Instantiator\Exception\InvalidArgumentException;
12+
use Illuminate\Container\Container;
1213

1314
class TestApplicationWrapper implements ApplicationWrapperContract
1415
{
@@ -107,4 +108,18 @@ public function make($abstract, array $parameters = [])
107108

108109
throw new InvalidArgumentException("Binding {$abstract} cannot be resolved while testing");
109110
}
111+
112+
/**
113+
* Wrapper around app()->get().
114+
*
115+
* @param string $id
116+
*
117+
* @return mixed
118+
*/
119+
public function get($id)
120+
{
121+
if ($id == 'arrilot.widget-namespaces') {
122+
return (new NamespacesRepository())->registerNamespace('dummy', '\Arrilot\Widgets\Test\Dummies');
123+
}
124+
}
110125
}

tests/WidgetFactoryTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ public function testItCanRunWidgetsUsingFQCN()
6868
$this->assertEquals('Default test slider was executed with $slides = 6', $output);
6969
}
7070

71+
public function testItThrowsExceptionForNamespaceNotFound()
72+
{
73+
$this->expectException('Arrilot\Widgets\Misc\NamespaceNotFoundException');
74+
75+
$output = $this->factory->run('notfound::TestDefaultSlider');
76+
}
77+
78+
public function testItCanRunWidgetsUsingNamespace()
79+
{
80+
$output = $this->factory->run('dummy::TestDefaultSlider');
81+
82+
$this->assertEquals('Default test slider was executed with $slides = 6', $output);
83+
}
84+
7185
public function testItLoadsWidgetsFromRootNamespaceFirst()
7286
{
7387
$output = $this->factory->run('Exception');

0 commit comments

Comments
 (0)