mnsami/composer-custom-directory-installer
Composer 安装命令:
composer require mnsami/composer-custom-directory-installer
包简介
A composer plugin, to help install packages of different types in custom paths.
关键字:
README 文档
README
A Composer plugin to install packages in custom directories outside the default vendor folder.
This is not another composer-installer library for supporting non-composer package types such as application. By default it handles library-type packages, but you can extend it to any Composer package type via extra.installer-types in your root composer.json.
Table of Contents
- Why this plugin?
- Requirements
- Installation
- How to use
- Path Variables
- Matching Strategies
- Custom
installer-name - Supporting Custom Package Types
- Complete example
- Real-world use cases
- Migrating from oomphinc/composer-installers-extender
- Security
- Upgrading from v1.x
- Note
https://getcomposer.org/doc/04-schema.md#type
The type of the package. It defaults to library.
Package types are used for custom installation logic. If you have a package that needs some special logic, you can define a custom type. This could be a symfony-bundle, a wordpress-plugin or a typo3-module. These types will all be specific to certain projects, and they will need to provide an installer capable of installing packages of that type.
Why this plugin?
Composer has a built-in installer-paths key, but it only works if the package itself declares a dependency on composer/installers — something most packages on Packagist don't do. If you add an installer-paths rule for a package that doesn't opt in, Composer silently ignores it and installs the package to vendor/ anyway.
This plugin removes that constraint. It intercepts installation at the root-project level, so any package can be redirected to a custom path without requiring any changes to the package itself.
In short: if you've ever added installer-paths and nothing happened, this plugin is the fix.
Requirements
- PHP >= 8.1
- Composer 2.x
Installation
Add the plugin to the require section of your composer.json:
"require": { "mnsami/composer-custom-directory-installer": "^2.1" }
Important — Composer 2.2+ plugin trust:
Composer 2.2 and later require you to explicitly allow third-party plugins. Add the following to your composer.json:
"config": { "allow-plugins": { "mnsami/composer-custom-directory-installer": true } }
Without this, Composer will either prompt interactively or block the plugin entirely in non-interactive (CI) environments.
How to use
In the extra section of your root composer.json, define the custom directory for each package:
"extra": { "installer-paths": { "./monolog/": ["monolog/monolog"] } }
This tells Composer to install monolog/monolog into the ./monolog/ directory instead of vendor/monolog/monolog.
Path Variables
You can use the following variables in your installer-paths to build dynamic paths:
| Variable | Description | Example value |
|---|---|---|
{$vendor} |
The vendor portion of the package name | monolog |
{$name} |
The package name (or installer-name override) |
monolog |
{$type} |
The Composer package type | library |
"extra": { "installer-paths": { "./customlibs/{$vendor}/db/{$name}": ["doctrine/orm"], "./custom/{$type}/{$vendor}/{$name}": ["acme/*"] } }
Path Variable Flags
You can append transformation flags after a pipe (|) to modify how a variable is substituted:
{$token|flags}
Flags are applied left-to-right in the order given:
| Flag | Transformation | Example input | Example output |
|---|---|---|---|
F |
Capitalize first letter (ucfirst) |
my-package |
My-package |
P |
Strip hyphens/underscores and capitalize each following word | my-package |
myPackage |
U |
Uppercase all characters | my-package |
MY-PACKAGE |
Flags can be combined. FP together produces PascalCase (capitalize first + strip separators):
| Expression | Input | Output |
|---|---|---|
{$name|F} |
my-package |
My-package |
{$name|P} |
my-package |
myPackage |
{$name|FP} |
my-package |
MyPackage |
{$name|U} |
my-package |
MY-PACKAGE |
{$vendor|U} |
acme |
ACME |
Example:
"installer-paths": { "src/{$vendor|U}/{$name|FP}/": ["acme/my-package"], "modules/{$name|FP}/": ["type:drupal-module"] }
For a package acme/my-package (type library), this resolves to src/ACME/MyPackage/.
Matching Strategies
installer-paths supports three matching strategies. Precedence is evaluated globally across all entries: all entries are first scanned for an exact name match, then for a type match, then for a wildcard match. An exact match in a later-listed entry always wins over a wildcard match in an earlier-listed entry.
1. Exact package name (highest precedence)
Matches one specific package:
"installer-paths": { "./libs/monolog/": ["monolog/monolog"] }
2. Package type prefix
Matches all packages of a given Composer type using the type: prefix:
"installer-paths": { "./wp-content/plugins/{$name}/": ["type:wordpress-plugin"] }
3. Wildcard vendor glob (lowest precedence)
Matches all packages from a given vendor using *:
"installer-paths": { "./acme-libs/{$name}/": ["acme/*"] }
Custom installer-name
A package can override the {$name} variable by setting installer-name in its own extra section (inside the package's composer.json, not the root project):
"extra": { "installer-name": "my-custom-name" }
When set, {$name} in the path template will resolve to my-custom-name instead of the package's actual name.
Supporting Custom Package Types
By default the plugin only handles the library package type. To install packages of other types (e.g. drupal-module, wordpress-plugin) into custom directories, declare those types in extra.installer-types:
"extra": { "installer-types": ["drupal-module", "wordpress-plugin"], "installer-paths": { "web/modules/{$name}/": ["type:drupal-module"], "wp-content/plugins/{$name}/": ["type:wordpress-plugin"] } }
The plugin will claim any package whose type appears in installer-types and apply the matching installer-paths rule. Without this list, packages of non-library types are left to Composer's default installer.
Complete example
{
"require": {
"mnsami/composer-custom-directory-installer": "^2.1",
"monolog/monolog": "*",
"acme/foo": "*",
"acme/bar": "*"
},
"config": {
"allow-plugins": {
"mnsami/composer-custom-directory-installer": true
}
},
"extra": {
"installer-types": ["wordpress-plugin"],
"installer-paths": {
"./logger/": ["monolog/monolog"],
"./acme/{$name}/": ["acme/*"],
"./plugins/{$name}/": ["type:wordpress-plugin"]
}
}
}
Real-world use cases
WordPress with WPackagist
Most WordPress plugins available via WPackagist don't require composer/installers, so native installer-paths silently fails for them. This plugin makes it work:
{
"require": {
"mnsami/composer-custom-directory-installer": "^2.1",
"wpackagist-plugin/contact-form-7": "*",
"wpackagist-theme/twentytwentyfour": "*"
},
"config": {
"allow-plugins": {
"mnsami/composer-custom-directory-installer": true
}
},
"extra": {
"installer-types": ["wordpress-plugin", "wordpress-theme"],
"installer-paths": {
"wp-content/plugins/{$name}/": ["type:wordpress-plugin"],
"wp-content/themes/{$name}/": ["type:wordpress-theme"]
}
}
}
Docker / keeping vendor outside the web root
Put one package (e.g. a CLI tool) in a path that's bind-mounted into a container, while everything else stays in vendor/:
"extra": { "installer-paths": { "/tools/{$name}/": ["vendor/some-cli-tool"] } }
Monorepos with sibling library directories
Route internal packages to their canonical location in the repo tree:
"extra": { "installer-types": ["company-module"], "installer-paths": { "../modules/{$name}/": ["type:company-module"] } }
PascalCase or namespaced paths
Use path variable flags to match the naming convention your framework expects:
"extra": { "installer-paths": { "src/Modules/{$name|FP}/": ["acme/*"] } }
acme/my-module installs to src/Modules/MyModule/.
Migrating from oomphinc/composer-installers-extender
oomphinc/composer-installers-extender has not had a functional release since December 2021. This plugin is a maintained, drop-in alternative with a superset of its features (path variable flags, three-pass precedence, traversal guards).
Before:
"require": { "composer/installers": "^2.0", "oomphinc/composer-installers-extender": "^2.0" }, "config": { "allow-plugins": { "composer/installers": true, "oomphinc/composer-installers-extender": true } }, "extra": { "installer-types": ["drupal-module"], "installer-paths": { "web/modules/contrib/{$name}/": ["type:drupal-module"] } }
After:
"require": { "mnsami/composer-custom-directory-installer": "^2.1" }, "config": { "allow-plugins": { "mnsami/composer-custom-directory-installer": true } }, "extra": { "installer-types": ["drupal-module"], "installer-paths": { "web/modules/contrib/{$name}/": ["type:drupal-module"] } }
The extra.installer-types and extra.installer-paths keys are identical — only the require and allow-plugins entries change. If you required composer/installers solely for path routing (not for any package's own declared dependency), you can remove it too.
Security
Resolved install paths are validated against two attack vectors:
- Directory traversal — a resolved path containing
..throws anInvalidArgumentException. - Absolute path injection — a resolved path that is absolute (starting with
/or a Windows drive letter) throws anInvalidArgumentException. This can occur when a package'sinstaller-nameis set to an absolute path value.
Both checks apply after all {$variable} substitutions are complete.
Upgrading from v1.x
| v1.x | v2.x | |
|---|---|---|
| PHP | >= 5.3 | >= 8.1 |
| Composer | 1.x / 2.x | 2.x only |
| Require string | "1.*" |
"^2.1" |
type: matching |
No | Yes |
Wildcard vendor/* |
No | Yes |
{$type} variable |
No | Yes |
allow-plugins needed |
No | Yes (Composer 2.2+) |
installer-types support |
No | Yes |
Path variable flags (|F, |P, |U) |
No | Yes |
Existing installer-paths configurations (exact package names) are fully backwards-compatible and require no changes.
Note
Composer type: project is not supported by this installer, as packages with type project only make sense to be used with application shells like symfony/framework-standard-edition.
mnsami/composer-custom-directory-installer 适用场景与选型建议
mnsami/composer-custom-directory-installer 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 5.4M 次下载、GitHub Stars 达 143, 最近一次更新时间为 2014 年 08 月 08 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「composer」 「wordpress」 「drupal」 「composer-installer」 「composer-plugin」 「monorepo」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 mnsami/composer-custom-directory-installer 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 mnsami/composer-custom-directory-installer 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 mnsami/composer-custom-directory-installer 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Provides an add-on purchasable entity.
Drupal integration module for the Kalastatic prototyping and styleguide tool
Provides a base set of configuration and module dependencies for starting new Drupal projects.
This module extends Drupal Migrate framework.
This composer plugin enables installation of GravityForms WordPress plugin and its addons.
统计信息
- 总下载量: 5.4M
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 148
- 点击次数: 29
- 依赖项目数: 71
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2014-08-08