Skip to content

Commit

Permalink
Merge pull request #124 from sebastienheyd/master
Browse files Browse the repository at this point in the history
Widgets Namespaces
  • Loading branch information
arrilot committed Mar 25, 2019
2 parents b3e533b + a886814 commit 24297e9
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 5 deletions.
28 changes: 28 additions & 0 deletions README.md
Expand Up @@ -383,3 +383,31 @@ Widget::group('sidebar')->removeAll(); // Widget group is empty now
`Widget::group('sidebar')->any(); // bool`

`Widget::group('sidebar')->count(); // int`

## Namespaces for third party packages (extra)

In some cases, it may be useful to deliver widgets with your own packages. For example, if your package allows
you to manage news, it would be convenient to have immediately configurable widgets, ready for display, directly
delivered with your package.

To avoid having to use the fqcn each time, you can set a widget namespace into your package provider. This way the
widgets from your package can be more easily identified, and especially the syntax will be shorter.

To do that, all you have to do is to register the namespace in your package service provider :

```php
public function boot()
{
app('arrilot.widget-namespaces')->registerNamespace('my-package-name', '\VendorName\PackageName\Path\To\Widgets');
}
```

After that you can use the namespace in your views :

```php
@widget('my-package-name::foo.bar')

// is equivalent to
@widget('\VendorName\PackageName\Path\To\Widgets\Foo\Bar')
```

2 changes: 1 addition & 1 deletion src/Console/WidgetMakeCommand.php
Expand Up @@ -224,7 +224,7 @@ protected function makeViewName()
// convert to snake_case part by part to avoid unexpected underscores.
$nameArray = explode('/', $name);
array_walk($nameArray, function (&$part) {
$part = snake_case($part);
$part = Str::snake($part);
});

return implode('/', $nameArray);
Expand Down
9 changes: 9 additions & 0 deletions src/Contracts/ApplicationWrapperContract.php
Expand Up @@ -54,4 +54,13 @@ public function getNamespace();
* @return mixed
*/
public function make($abstract, array $parameters = []);

/**
* Wrapper around app()->get().
*
* @param string $id
*
* @return mixed
*/
public function get($id);
}
16 changes: 13 additions & 3 deletions src/Factories/AbstractWidgetFactory.php
Expand Up @@ -8,6 +8,7 @@
use Arrilot\Widgets\Misc\InvalidWidgetClassException;
use Arrilot\Widgets\Misc\ViewExpressionTrait;
use Arrilot\Widgets\WidgetId;
use Illuminate\Support\Str;

abstract class AbstractWidgetFactory
{
Expand Down Expand Up @@ -115,12 +116,21 @@ protected function instantiateWidget(array $params = [])
{
WidgetId::increment();

$this->widgetName = $this->parseFullWidgetNameFromString(array_shift($params));
$str = array_shift($params);

if (preg_match('#^(.*?)::(.*?)$#', $str, $m)) {
$rootNamespace = $this->app->get('arrilot.widget-namespaces')->getNamespace($m[1]);
$str = $m[2];
}

$this->widgetName = $this->parseFullWidgetNameFromString($str);
$this->widgetFullParams = $params;
$this->widgetConfig = (array) array_shift($params);
$this->widgetParams = $params;

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

$fqcn = $rootNamespace.'\\'.$this->widgetName;
$widgetClass = class_exists($fqcn) ? $fqcn : $this->widgetName;
Expand Down Expand Up @@ -149,7 +159,7 @@ protected function instantiateWidget(array $params = [])
*/
protected function parseFullWidgetNameFromString($widgetName)
{
return studly_case(str_replace('.', '\\_', $widgetName));
return Str::studly(str_replace('.', '\\_', $widgetName));
}

/**
Expand Down
14 changes: 14 additions & 0 deletions src/Misc/LaravelApplicationWrapper.php
Expand Up @@ -90,4 +90,18 @@ public function make($abstract, array $parameters = [])
{
return $this->app->make($abstract, $parameters);
}

/**
* Wrapper around app()->get().
*
* @param string $id
*
* @throws \Illuminate\Container\EntryNotFoundException
*
* @return mixed
*/
public function get($id)
{
return $this->app->get($id);
}
}
9 changes: 9 additions & 0 deletions src/Misc/NamespaceNotFoundException.php
@@ -0,0 +1,9 @@
<?php

namespace Arrilot\Widgets\Misc;

use Exception;

class NamespaceNotFoundException extends Exception
{
}
48 changes: 48 additions & 0 deletions src/NamespacesRepository.php
@@ -0,0 +1,48 @@
<?php

namespace Arrilot\Widgets;

use Arrilot\Widgets\Misc\NamespaceNotFoundException;

class NamespacesRepository
{
/**
* The array of namespaces.
*
* @var array
*/
protected $namespaces;

/**
* Register a namespace.
*
* @param string $alias
* @param string $namespace
*
* @return WidgetNamespaces
*/
public function registerNamespace($alias, $namespace)
{
$this->namespaces[$alias] = rtrim($namespace, '\\');

return $this;
}

/**
* Get namespace by his alias.
*
* @param string $label
*
* @throws \Exception
*
* @return string
*/
public function getNamespace($alias)
{
if (!isset($this->namespaces[$alias])) {
throw new NamespaceNotFoundException('Namespace not found with the alias "'.$alias.'"');
}

return $this->namespaces[$alias];
}
}
4 changes: 4 additions & 0 deletions src/ServiceProvider.php
Expand Up @@ -33,6 +33,10 @@ public function register()
return new WidgetGroupCollection(new LaravelApplicationWrapper());
});

$this->app->singleton('arrilot.widget-namespaces', function () {
return new NamespacesRepository();
});

$this->app->singleton('command.widget.make', function ($app) {
return new WidgetMakeCommand($app['files']);
});
Expand Down
17 changes: 16 additions & 1 deletion tests/Support/TestApplicationWrapper.php
Expand Up @@ -6,9 +6,10 @@
use Arrilot\Widgets\Contracts\ApplicationWrapperContract;
use Arrilot\Widgets\Factories\AsyncWidgetFactory;
use Arrilot\Widgets\Factories\WidgetFactory;
use Illuminate\Container\Container;
use Arrilot\Widgets\NamespacesRepository;
use Closure;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
use Illuminate\Container\Container;

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

throw new InvalidArgumentException("Binding {$abstract} cannot be resolved while testing");
}

/**
* Wrapper around app()->get().
*
* @param string $id
*
* @return mixed
*/
public function get($id)
{
if ($id == 'arrilot.widget-namespaces') {
return (new NamespacesRepository())->registerNamespace('dummy', '\Arrilot\Widgets\Test\Dummies');
}
}
}
14 changes: 14 additions & 0 deletions tests/WidgetFactoryTest.php
Expand Up @@ -68,6 +68,20 @@ public function testItCanRunWidgetsUsingFQCN()
$this->assertEquals('Default test slider was executed with $slides = 6', $output);
}

public function testItThrowsExceptionForNamespaceNotFound()
{
$this->expectException('Arrilot\Widgets\Misc\NamespaceNotFoundException');

$output = $this->factory->run('notfound::TestDefaultSlider');
}

public function testItCanRunWidgetsUsingNamespace()
{
$output = $this->factory->run('dummy::TestDefaultSlider');

$this->assertEquals('Default test slider was executed with $slides = 6', $output);
}

public function testItLoadsWidgetsFromRootNamespaceFirst()
{
$output = $this->factory->run('Exception');
Expand Down

0 comments on commit 24297e9

Please sign in to comment.