Skip to content

Commit 69b97e8

Browse files
committed
Widgets Namespaces
1 parent b3e533b commit 69b97e8

File tree

10 files changed

+153
-4
lines changed

10 files changed

+153
-4
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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,17 @@ 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+
* @return mixed
100+
* @throws \Illuminate\Container\EntryNotFoundException
101+
*/
102+
public function get($id)
103+
{
104+
return $this->app->get($id);
105+
}
93106
}
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: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
return $this;
28+
}
29+
30+
/**
31+
* Get namespace by his alias.
32+
*
33+
* @param string $label
34+
*
35+
* @return string
36+
* @throws \Exception
37+
*/
38+
public function getNamespace($alias)
39+
{
40+
if (!isset($this->namespaces[$alias])) {
41+
throw new NamespaceNotFoundException('Namespace not found with the alias "'.$alias.'"');
42+
}
43+
44+
return $this->namespaces[$alias];
45+
}
46+
}

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: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Arrilot\Widgets\Contracts\ApplicationWrapperContract;
77
use Arrilot\Widgets\Factories\AsyncWidgetFactory;
88
use Arrilot\Widgets\Factories\WidgetFactory;
9+
use Arrilot\Widgets\NamespacesRepository;
910
use Illuminate\Container\Container;
1011
use Closure;
1112
use Doctrine\Instantiator\Exception\InvalidArgumentException;
@@ -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: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Arrilot\Widgets\Test;
44

55
use Arrilot\Widgets\Factories\WidgetFactory;
6+
use Arrilot\Widgets\NamespacesRepository;
67
use Arrilot\Widgets\Test\Dummies\TestCachedWidget;
78
use Arrilot\Widgets\Test\Support\TestApplicationWrapper;
89
use Arrilot\Widgets\Test\Support\TestCase;
@@ -68,6 +69,20 @@ public function testItCanRunWidgetsUsingFQCN()
6869
$this->assertEquals('Default test slider was executed with $slides = 6', $output);
6970
}
7071

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

0 commit comments

Comments
 (0)