Skip to content
Permalink
Browse files

ENHANCEMENT Allow vendor modules with url rewriting

API Introduce ModuleResource feature
  • Loading branch information...
Damian Mooyman
Damian Mooyman committed Sep 21, 2017
1 parent 91943c0 commit fa57deeba4099d74a8746909e3ba1767353c465b
Showing with 877 additions and 266 deletions.
  1. +1 −1 .gitignore
  2. +0 −5 _config/config.yml
  3. +8 −0 _config/resources.yml
  4. +27 −0 docs/en/02_Developer_Guides/01_Templates/06_Themes.md
  5. +76 −28 docs/en/02_Developer_Guides/05_Extending/How_Tos/01_Publish_a_Module.md
  6. +2 −0 docs/en/04_Changelogs/4.0.0.md
  7. +34 −4 src/Control/SimpleResourceURLGenerator.php
  8. +1 −1 src/Core/Manifest/ClassManifest.php
  9. +200 −33 src/Core/Manifest/ManifestFileFinder.php
  10. +78 −43 src/Core/Manifest/Module.php
  11. +9 −37 src/Core/Manifest/ModuleManifest.php
  12. +121 −0 src/Core/Manifest/ModuleResource.php
  13. +1 −1 src/Core/Manifest/ResourceURLGenerator.php
  14. +44 −39 src/View/ThemeResourceLoader.php
  15. +1 −1 tests/behat/src/ConfigContext.php
  16. +67 −0 tests/php/Control/SimpleResourceURLGeneratorTest.php
  17. +1 −0 tests/php/Control/SimpleResourceURLGeneratorTest/_fakewebroot/basemodule/client/file.js
  18. +2 −0 tests/php/Control/SimpleResourceURLGeneratorTest/_fakewebroot/basemodule/client/style.css
  19. +1 −0 ...p/Control/SimpleResourceURLGeneratorTest/_fakewebroot/vendor/silverstripe/mymodule/client/file.js
  20. +2 −0 ...Control/SimpleResourceURLGeneratorTest/_fakewebroot/vendor/silverstripe/mymodule/client/style.css
  21. +39 −25 tests/php/Core/Manifest/ClassManifestTest.php
  22. +33 −23 tests/php/Core/Manifest/ManifestFileFinderTest.php
  23. +21 −15 tests/php/Core/Manifest/ModuleManifestTest.php
  24. +74 −7 tests/php/Core/Manifest/ThemeResourceLoaderTest.php
  25. +4 −0 tests/php/Core/Manifest/fixtures/classmanifest/vendor/silverstripe/modulec/_config/config.yml
  26. +6 −0 tests/php/Core/Manifest/fixtures/classmanifest/vendor/silverstripe/modulec/code/VendorClassA.php
  27. +6 −0 tests/php/Core/Manifest/fixtures/classmanifest/vendor/silverstripe/modulec/code/VendorTraitA.php
  28. +5 −0 tests/php/Core/Manifest/fixtures/classmanifest/vendor/silverstripe/modulec/composer.json
  29. 0 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/anothervendor/library/notamodule.txt
  30. +1 −0 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/thismodule/_config.php
  31. 0 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/thismodule/code/tests/tests2.txt
  32. 0 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/thismodule/lang/lang.txt
  33. 0 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/thismodule/module.txt
  34. 0 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/thismodule/tests/tests.txt
  35. +4 −0 tests/php/Core/Manifest/fixtures/templatemanifest/module/composer.json
  36. +1 −0 tests/php/Core/Manifest/fixtures/templatemanifest/vendor/silverstripe/vendormodule/_config.php
  37. +4 −0 tests/php/Core/Manifest/fixtures/templatemanifest/vendor/silverstripe/vendormodule/composer.json
  38. 0 ...fixtures/templatemanifest/vendor/silverstripe/vendormodule/themes/vendortheme/css/vendorstyle.css
  39. 0 ...s/templatemanifest/vendor/silverstripe/vendormodule/themes/vendortheme/javascript/vendorscript.js
  40. +3 −3 tests/php/i18n/i18nTextCollectorTest.php
@@ -8,6 +8,6 @@ node_modules/
coverage/
/**/*.js.map
/**/*.css.map
vendor/
/vendor/
composer.lock
silverstripe-cache/
@@ -1,11 +1,6 @@
---
Name: coreconfig
---
SilverStripe\Core\Injector\Injector:
SilverStripe\Core\Manifest\ResourceURLGenerator:
class: SilverStripe\Control\SimpleResourceURLGenerator
properties:
NonceStyle: mtime
SilverStripe\Control\HTTP:
cache_control:
max-age: 0
@@ -0,0 +1,8 @@
---
Name: coreresources
---
SilverStripe\Core\Injector\Injector:
SilverStripe\Core\Manifest\ResourceURLGenerator:
class: SilverStripe\Control\SimpleResourceURLGenerator
properties:
NonceStyle: mtime
@@ -29,6 +29,8 @@ As you've added new files to your SilverStripe installation, make sure you clear
`?flush=1` to your website URL (e.g http://yoursite.com/?flush=1).
</div>

### Configuring themes

After installing the files through either method, update the current theme in SilverStripe. This can be done by
either altering the `SSViewer.themes` setting in a [config.yml](../configuration) or by changing the current theme in
the Site Configuration panel (http://yoursite.com/admin/settings)
@@ -42,6 +44,31 @@ SilverStripe\View\SSViewer:
- '$default'
```

There are a variety of ways in which you can specify a theme. The below describe the three
main styles of syntax:

1. You can use the following to point to a theme or path within your root project:

- `themename` -> A simple name with no slash represents a theme in the `/themes` directory
- `/some/path/to/theme` - Any `/` prefixed string will be treated as a direct filesystem path to a theme root.
- `$themeset` - Any `$` prefixed name will refer to a set of themes. By default only `$default` set is configured,
which represents all module roots with a `templates` directory.

2. Using the `:` syntax you can also specify themes relative to the given module:

- `myvendor/mymodule:sometheme` - This will specify a standard theme within the given module.
This will lookup the theme in the `themes` subfolder within this module. E.g.
`/vendor/myvendor/mymodule/themes/sometheme`.
Note: This syntax also works without the vendor prefix (`mymodule:sometheme`)
- `myvendor/mymodule:/some/path` - Rather than looking in the themes subdir, look in the
exact path within the root of the given module.

3. You can also specify a module root folder directly.

- `myvendor/mymodule` - Points to the base folder of the given module.
- `mymodule:` - Also points to the base folder of the given module, but without a vendor.
The `:` is necessary to distinguish this from a non-module theme.

### Manually

Unpack the contents of the zip file you download into the `themes` directory in your SilverStripe installation. The
@@ -17,39 +17,87 @@ this:

**mycustommodule/composer.json**

```js
{
"name": "your-vendor-name/module-name",
"description": "One-liner describing your module",
"type": "silverstripe-module",
"homepage": "http://github.com/your-vendor-name/module-name",
"keywords": ["silverstripe", "some-tag", "some-other-tag"],
"license": "BSD-3-Clause",
"authors": [
{"name": "Your Name","email": "your@email.com"}
],
"support": {
"issues": "http://github.com/your-vendor-name/module-name/issues"
},
"require": {
"silverstripe/cms": "~3.1",
"silverstripe/framework": "~3.1"
},
"extra": {
"installer-name": "module-name",
"screenshots": [
"relative/path/screenshot1.png",
"http://myhost.com/screenshot2.png"
]
}
}
```json
{
"name": "your-vendor-name/module-name",
"description": "One-liner describing your module",
"type": "silverstripe-module",
"homepage": "http://github.com/your-vendor-name/module-name",
"keywords": ["silverstripe", "some-tag", "some-other-tag"],
"license": "BSD-3-Clause",
"authors": [
{"name": "Your Name","email": "your@email.com"}
],
"support": {
"issues": "http://github.com/your-vendor-name/module-name/issues"
},
"require": {
"silverstripe/cms": "^4",
"silverstripe/framework": "^4"
},
"extra": {
"installer-name": "module-name",
"screenshots": [
"relative/path/screenshot1.png",
"http://myhost.com/screenshot2.png"
]
}
}
```

Once your module is published online with a service like Github.com or Bitbucket.com, submit the repository to
[Packagist](https://packagist.org/) to have the module accessible to developers. It'll automatically get picked
up by [addons.silverstripe.org](http://addons.silverstripe.org/) website.

## Vendor modules

By default `silverstripe-module` type libraries are installed to the root web folder, however a new type
`silverstripe-vendormodule` allows you to publish your module to the vendor directory.

The below is an example of a vendor module composer.json:

```json
{
"name": "tractorcow/test-vendor-module",
"description": "Test module for silverstripe/vendor-plugin",
"type": "silverstripe-vendormodule",
"require": {
"silverstripe/vendor-plugin": "^1.0",
"silverstripe/cms": "^4.0"
},
"license": "BSD-3-Clause",
"autoload": {
"psr-4": {
"TractorCow\\TestVendorModule\\": "src/"
}
},
"extra": {
"expose": [
"client"
]
},
"minimum-stability": "dev"
}
```

Note that these modules have the following distinct characteristics:

- Library type is `silverstripe-vendormodule`
- Any folder which should be exposed to the public webroot must be declared in the `extra.expose` config.
These paths will be automatically rewritten to public urls which don't directly serve files from the `vendor`
folder. For instance, `vendor/tractorcow/test-vendor-module/client` will be rewritten to
`resources/tractorcow/test-vendor-module/client`.
- Any module which uses the folder expose feature must require `silverstripe/vendor-plugin` in order to
support automatic rewriting and linking. For more information on this plugin you can see the
[silverstripe/vendor-plugin github page](https://github.com/silverstripe/vendor-plugin).

Linking to resources in vendor modules uses exactly the same syntax as non-vendor modules. For example,
this is how you would require a script in this module:

```php
Requirements::javascript('tractorcow/test-vendor-module:client/js/script.js');
```

## Releasing versions

Over time you may have to release new versions of your module to continue to work with newer versions of SilverStripe.
@@ -76,4 +124,4 @@ Here's some common values for your `require` section
* `3.0.*`: Version `3.0`, including `3.0.1`, `3.0.2` etc, excluding `3.1`
* `~3.0`: Version `3.0` or higher, including `3.0.1` and `3.1` etc, excluding `4.0`
* `~3.0,<3.2`: Version `3.0` or higher, up until `3.2`, which is excluded
* `~3.0,>3.0.4`: Version `3.0` or higher, starting with `3.0.4`
* `~3.0,>3.0.4`: Version `3.0` or higher, starting with `3.0.4`
@@ -64,6 +64,8 @@ guide developers in preparing existing 3.x code for compatibility with 4.0
[intervention/image](https://github.com/intervention/image) library to power manipualations.
* Dependencies can managed via [recipe-plugin](https://github.com/silverstripe/recipe-plugin). See [recipe-core](https://github.com/silverstripe/recipe-core) and [recipe-cms](https://github.com/silverstripe/recipe-cms) as examples.
* Authentication has been upgraded to a modular approach using re-usable interfaces and easier to hook in to LoginHandlers.
* Support for modules installed in vendor folder. See [/developer_guides/extending/how_tos/publish_a_module](the
module publishing guide) for more information.
## <a name="upgrading"></a>Upgrading
@@ -3,6 +3,8 @@
namespace SilverStripe\Control;
use InvalidArgumentException;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Manifest\ModuleResource;
use SilverStripe\Core\Manifest\ResourceURLGenerator;
/**
@@ -11,6 +13,18 @@
*/
class SimpleResourceURLGenerator implements ResourceURLGenerator
{
/**
* Rewrites applied after generating url.
* Note: requires either silverstripe/vendor-plugin-helper or silverstripe/vendor-plugin
* to ensure the file is available.
*
* @config
* @var array
*/
private static $url_rewrites = [
'#^vendor/#i' => 'resources/',
];
/*
* @var string
*/
@@ -45,18 +59,34 @@ public function setNonceStyle($nonceStyle)
/**
* Return the URL for a resource, prefixing with Director::baseURL() and suffixing with a nonce
*
* @param string $relativePath File or directory path relative to BASE_PATH
* @param string|ModuleResource $relativePath File or directory path relative to BASE_PATH
* @return string Doman-relative URL
* @throws InvalidArgumentException If the resource doesn't exist
*/
public function urlForResource($relativePath)
{
$absolutePath = preg_replace('/\?.*/', '', Director::baseFolder() . '/' . $relativePath);
if (!file_exists($absolutePath)) {
if ($relativePath instanceof ModuleResource) {
// Load from module resource
$resource = $relativePath;
$relativePath = $resource->getRelativePath();
$exists = $resource->exists();
$absolutePath = $resource->getPath();
} else {
// Use normal string
$absolutePath = preg_replace('/\?.*/', '', Director::baseFolder() . '/' . $relativePath);
$exists = file_exists($absolutePath);
}
if (!$exists) {
throw new InvalidArgumentException("File {$relativePath} does not exist");
}
// Apply url rewrites
$rules = Config::inst()->get(static::class, 'url_rewrites') ?: [];
foreach ($rules as $from => $to) {
$relativePath = preg_replace($from, $to, $relativePath);
}
// Apply nonce
$nonce = '';
// Don't add nonce to directories
if ($this->nonceStyle && is_file($absolutePath)) {
@@ -444,7 +444,7 @@ public function regenerate($includeTests)
'name_regex' => '/^[^_].*\\.php$/',
'ignore_files' => array('index.php', 'main.php', 'cli-script.php'),
'ignore_tests' => !$includeTests,
'file_callback' => function ($basename, $pathname) use ($includeTests) {
'file_callback' => function ($basename, $pathname, $depth) use ($includeTests, $finder) {
$this->handleFile($basename, $pathname, $includeTests);
},
));

0 comments on commit fa57dee

Please sign in to comment.
You can’t perform that action at this time.