Skip to content

Commit 3acda36

Browse files
authored
Merge pull request #36 from tattersoftware/vendor
Vendor Classes
2 parents 6709f9a + 37ebe94 commit 3acda36

File tree

9 files changed

+271
-67
lines changed

9 files changed

+271
-67
lines changed

README.md

Lines changed: 127 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,18 @@ use Tatter\Assets\Bundle;
103103

104104
class FrontendBundle extends Bundle
105105
{
106-
protected $bundles = [
107-
StylesBundle::class,
108-
];
109-
110-
protected $paths = [
111-
'bootstrap/dist/css/bootstrap.min.css',
112-
'bootstrap/dist/js/bootstrap.bundle.min.js',
113-
];
114-
115-
protected $uris = [
116-
'https://pagecdn.io/lib/cleave/1.6.0/cleave.min.js',
117-
];
106+
protected $bundles = [
107+
StylesBundle::class,
108+
];
109+
110+
protected $paths = [
111+
'bootstrap/dist/css/bootstrap.min.css',
112+
'bootstrap/dist/js/bootstrap.bundle.min.js',
113+
];
114+
115+
protected $uris = [
116+
'https://pagecdn.io/lib/cleave/1.6.0/cleave.min.js',
117+
];
118118
}
119119
```
120120

@@ -132,17 +132,17 @@ use Tatter\Assets\Bundle;
132132

133133
class ColorBundle extends Bundle
134134
{
135-
protected function define()
136-
{
137-
$this
138-
->add(Asset::createFromPath('styles.css')) // Add individual Assets
139-
->merge($someOtherBundle); // Or combine multiple Bundles
140-
141-
// Create more complex Assets
142-
$source = '<script src="https://pagecdn.io/lib/cleave/1.6.0/cleave.min.js" type="text/javascript"></script>';
143-
$inHead = true; // Force a JavaScript Asset to the <head> tag
144-
$asset = new Asset($source, $inHead);
145-
}
135+
protected function define()
136+
{
137+
$this
138+
->add(Asset::createFromPath('styles.css')) // Add individual Assets
139+
->merge($someOtherBundle); // Or combine multiple Bundles
140+
141+
// Create more complex Assets
142+
$source = '<script src="https://pagecdn.io/lib/cleave/1.6.0/cleave.min.js" type="text/javascript"></script>';
143+
$inHead = true; // Force a JavaScript Asset to the <head> tag
144+
$asset = new Asset($source, $inHead);
145+
}
146146
}
147147
```
148148

@@ -159,18 +159,18 @@ use Tatter\Assets\Config\Assets as AssetsConfig;
159159

160160
class Assets extends AssetsConfig
161161
{
162-
public $routes = [
163-
'*' => [
164-
'bootstrap/bootstrap.min.css',
165-
'bootstrap/bootstrap.bundle.min.js',
166-
'font-awesome/css/all.min.css',
167-
'styles/main.css',
168-
],
169-
'files' => [
170-
'dropzone/dropzone.min.css',
171-
'dropzone/dropzone.min.js',
172-
],
173-
];
162+
public $routes = [
163+
'*' => [
164+
'bootstrap/bootstrap.min.css',
165+
'bootstrap/bootstrap.bundle.min.js',
166+
'font-awesome/css/all.min.css',
167+
'styles/main.css',
168+
],
169+
'files' => [
170+
'dropzone/dropzone.min.css',
171+
'dropzone/dropzone.min.js',
172+
],
173+
];
174174
}
175175
```
176176

@@ -192,21 +192,21 @@ Add this module as well:
192192
Edit your **Filters.php** config file to enable the `AssetsFilter` on all routes:
193193

194194
```php
195-
/**
196-
* List of filter aliases that are always
197-
* applied before and after every request.
198-
*
199-
* @var array
200-
*/
201-
public $globals = [
202-
'before' => [
203-
// 'honeypot',
204-
// 'csrf',
205-
],
206-
'after' => [
207-
'assets' => ['except' => 'api/*'],
208-
],
209-
];
195+
/**
196+
* List of filter aliases that are always
197+
* applied before and after every request.
198+
*
199+
* @var array
200+
*/
201+
public $globals = [
202+
'before' => [
203+
// 'honeypot',
204+
// 'csrf',
205+
],
206+
'after' => [
207+
'assets' => ['except' => 'api/*'],
208+
],
209+
];
210210
```
211211

212212
Create a new `Bundle` to define your Bootstrap files in **app/Bundles/DropzoneJS.php**:
@@ -218,10 +218,10 @@ use Tatter\Assets\Bundle;
218218

219219
class DropzoneJS extends Bundle
220220
{
221-
protected $paths = [
222-
'dropzone/dropzone.min.css',
223-
'dropzone/dropzone.min.js',
224-
];
221+
protected $paths = [
222+
'dropzone/dropzone.min.css',
223+
'dropzone/dropzone.min.js',
224+
];
225225
}
226226
```
227227

@@ -230,20 +230,20 @@ will load on every route and DropzoneJS will load on specific routes:
230230

231231
```php
232232
public $routes = [
233-
'*' => [
234-
'bootstrap/dist/css/bootstrap.min.css',
235-
'bootstrap/dist/js/bootstrap.bundle.min.js',
236-
],
237-
'files/*' => [
238-
\App\Bundles\DropzoneJS::class,
239-
],
240-
'upload' => [
241-
\App\Bundles\DropzoneJS::class,
242-
],
233+
'*' => [
234+
'bootstrap/dist/css/bootstrap.min.css',
235+
'bootstrap/dist/js/bootstrap.bundle.min.js',
236+
],
237+
'files/*' => [
238+
\App\Bundles\DropzoneJS::class,
239+
],
240+
'upload' => [
241+
\App\Bundles\DropzoneJS::class,
242+
],
243243
];
244244
```
245245

246-
> Note: We could have made a `Bundle` for Bootstrap as well but since they are only needed for on route this is just as easy.
246+
> Note: We could have made a `Bundle` for Bootstrap as well but since they are only needed for one route this is just as easy.
247247
248248
If you finished all that then your assets should be injected into your `<head>` and `<body>` tags accordingly.
249249

@@ -278,3 +278,65 @@ Your view file:
278278
</body>
279279
</html>
280280
```
281+
282+
## Vendor Classes
283+
284+
This library includes two abstract class stubs to ease working with third-party assets.
285+
`VendorPublisher` is a wrapper for the framework's [Publisher Library](https://codeigniter.com/user_guide/libraries/publisher.html)
286+
primed for use with `Assets`, and `VendorBundle` is a specialized version of this library's
287+
`Bundle` primed to handle assets published via `VendorPublisher`. Together these two classes
288+
can take a lot of the work out of managing assets you include from external sources.
289+
290+
Let's revisit the example above... Instead of copies the files into **public/assets/** ourselves
291+
(and re-copying every time there is an update) let's create a `VendorPublisher` to do that
292+
for us. In **app/Publishers/BootstrapPublisher.php**:
293+
```php
294+
<?php
295+
296+
namespace App\Publishers;
297+
298+
use Tatter\Assets\VendorPublisher;
299+
300+
class BootstrapPublisher extends VendorPublisher
301+
{
302+
protected $source = 'vendor/twbs/bootstrap/dist';
303+
protected $path = 'bootstrap';
304+
}
305+
306+
```
307+
308+
That's all! `VendorPublisher` knows that `$path` is relative the to directory in your Assets
309+
config file, so when you run `php spark publish` next all the latest Bootstrap assets will
310+
be copied into that directory (default: **public/assets/vendor/**).
311+
312+
> Note: Since these are external dependencies be sure to exclude them from your repo with your **.gitignore** file.
313+
314+
Now lets use these assets. We can create a new `VendorBundle` and use the new `addPath()`
315+
method to access the same files we just published from Composer's vendor directory.
316+
In **app/Bundles/BootstrapBundle.php**:
317+
```php
318+
<?php
319+
320+
namespace App\Bundles;
321+
322+
use Tatter\Assets\VendorBundle;
323+
324+
class BootstrapBundle extends VendorBundle
325+
{
326+
protected function define(): void
327+
{
328+
$this
329+
->addPath('bootstrap/bootstrap.min.css')
330+
->addPath('bootstrap/bootstrap.bundle.min.js');
331+
}
332+
}
333+
```
334+
335+
Now add the new bundle to our **app/Config/Assets.php** routes:
336+
```php
337+
public $routes = [
338+
'*' => [\App\Bundles\BootstrapBundle::class],
339+
];
340+
```
341+
342+
And we have hands-free Bootstrap updates from now on!

src/Asset.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ final class Asset
5252
//--------------------------------------------------------------------
5353

5454
/**
55-
* Loads and returns the configuration.
55+
* Loads, standardizes, and returns the configuration.
5656
*/
5757
public static function config(): AssetsConfig
5858
{
@@ -62,6 +62,7 @@ public static function config(): AssetsConfig
6262
// Standardize formats
6363
self::$config->uri = rtrim(self::$config->uri, '/') . '/';
6464
self::$config->directory = rtrim(self::$config->directory, '/') . '/';
65+
self::$config->vendor = rtrim(self::$config->vendor, '/') . '/';
6566
}
6667

6768
return self::$config;

src/Config/Assets.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ class Assets extends BaseConfig
2727
*/
2828
public $directory = FCPATH . 'assets/';
2929

30+
/**
31+
* Path for third-party published Assets. The path is relative to
32+
* both $directory and $uri. Recommended to add the resulting file
33+
* path to .gitignore so published vendor assets will not be tracked.
34+
*
35+
* @var string
36+
*/
37+
public $vendor = 'vendor/';
38+
3039
/**
3140
* Whether to append file modification timestamps on asset tags.
3241
* Makes it less likely for modified assets to remain cached.

src/Filters/AssetsFilter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function before(RequestInterface $request, $arguments = null)
2626
}
2727

2828
/**
29-
* Renders the menus and injects their content.
29+
* Gathers the route-specific assets and adds their tags to the response.
3030
*
3131
* @param array|null $arguments
3232
*/

src/VendorBundle.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace Tatter\Assets;
4+
5+
/**
6+
* Vendor Bundle Abstract Class
7+
*
8+
* A bundle of Assets specifically sourced from
9+
* third-party files published to the configured
10+
* "vendor" path (see Assets Config) and used in
11+
* conjunction with VendorPublisher.
12+
*/
13+
abstract class VendorBundle extends Bundle
14+
{
15+
/**
16+
* The base directory, i.e. Assets directory + vendor path
17+
*
18+
* @var string|null
19+
*/
20+
private static $base;
21+
22+
/**
23+
* Returns the base path according to the configurations.
24+
*/
25+
public static function base(): string
26+
{
27+
if (self::$base === null) {
28+
$config = Asset::config();
29+
self::$base = $config->directory . '/' . $config->vendor;
30+
}
31+
32+
return self::$base;
33+
}
34+
35+
/**
36+
* Adds an Asset by its vendor path, i.e. relative to base().
37+
*
38+
* @return $this
39+
*/
40+
final public function addPath(string $path)
41+
{
42+
$this->add(Asset::createFromPath(Asset::config()->vendor . trim($path, '/ ')));
43+
44+
return $this;
45+
}
46+
}

src/VendorPublisher.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace Tatter\Assets;
4+
5+
use CodeIgniter\Publisher\Publisher;
6+
use DomainException;
7+
8+
/**
9+
* Vendor Publisher Abstract Class
10+
*
11+
* A Publisher wrapper for Assets sourced from
12+
* third-party files to be published to the configured
13+
* "vendor" path (see Assets Config) and used in
14+
* conjunction with VendorBundle.
15+
*/
16+
abstract class VendorPublisher extends Publisher
17+
{
18+
/**
19+
* Destination path relative to AssetsConfig::directory.
20+
* Must be set by child classes.
21+
*
22+
* @var string
23+
*/
24+
protected $path;
25+
26+
/**
27+
* Set the real destination.
28+
*/
29+
public function __construct(?string $source = null, ?string $destination = null)
30+
{
31+
if (! is_string($this->path)) {
32+
throw new DomainException('Invalid relative destination $path.');
33+
}
34+
35+
$this->destination = VendorBundle::base();
36+
37+
if (! is_dir($this->destination)) {
38+
mkdir($this->destination, 0775, true);
39+
}
40+
41+
parent::__construct($source, $destination);
42+
}
43+
}

0 commit comments

Comments
 (0)