Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Commit

Permalink
Initial checkin
Browse files Browse the repository at this point in the history
- Create the PHAR file by:
  - Installing box-project globally: `composer global require 'kherge/box=~2.4' --prefer-source`
  - Copying box.json.dist to box.json, and providing a path to the private key
    to use when signing.
  - Executing `box build -vv` and providing the key passphrase when prompted.
  • Loading branch information
weierophinney committed Dec 11, 2015
0 parents commit 6369b7f
Show file tree
Hide file tree
Showing 13 changed files with 364 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
@@ -0,0 +1,6 @@
vendor/
box.json
component-installer.phar
component-installer.phar.pubkey
composer.lock
phpunit.xml
12 changes: 12 additions & 0 deletions LICENSE.md
@@ -0,0 +1,12 @@
Copyright (c) 2015, Zend Technologies USA, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

- Neither the name of Zend Technologies USA, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 changes: 22 additions & 0 deletions README.md
@@ -0,0 +1,22 @@
# Component Installer for Zend Framework 3 Applications

This repository contains the class `Zend\ComponentInstaller\ComponentInstaller`,
which provides Composer event hooks for the events:

- post-package-install
- post-package-uninstall

In order to utilize these, you will need to add the `ComponentInstaller`
classfile to your project, make it autoloadable, and then add its relevant
static methods as scripts for the above events.

To do that, this repository also provides a PHAR file that provides an
installer. It is available at:

- https://weierophinney.github.io/zend-component-installer/component-installer.phar

The public key for verifying the package is at:

- https://weierophinney.github.io/zend-component-installer/component-installer.phar.pubkey

The PHAR file is self-updateable.
3 changes: 3 additions & 0 deletions bin/console
@@ -0,0 +1,3 @@
#!/usr/bin/env php
<?php
include 'console.php';
9 changes: 9 additions & 0 deletions bin/console.bat
@@ -0,0 +1,9 @@
@echo off

if "%PHPBIN%" == "" set PHPBIN=@php_bin@
if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
GOTO RUN
:USE_PEAR_PATH
set PHPBIN=%PHP_PEAR_PHP_BIN%
:RUN
"%PHPBIN%" "@bin_dir@\console.php" %*
19 changes: 19 additions & 0 deletions bin/console.php
@@ -0,0 +1,19 @@
<?php
require __DIR__ . '/../vendor/autoload.php';

use Zend\Console\Console;
use ZF\Console\Application;
use ZF\Console\Dispatcher;

$version = '0.0.1';

$application = new Application(
'Component Installer',
$version,
include __DIR__ . '/../config/routes.php',
Console::getInstance(),
new Dispatcher()
);

$exit = $application->run();
exit($exit);
28 changes: 28 additions & 0 deletions box.json.dist
@@ -0,0 +1,28 @@
{
"algorithm": "OPENSSL",
"blacklist": [
],
"chmod": "0755",
"compression": "GZ",
"directories": [
"config",
"src"
],
"files": [
"LICENSE.md"
],
"finder": [
{
"name": "*.php",
"exclude": ["tests", "test"],
"in": "vendor"
}
],
"git-version": "package_version",
"intercept": true,
"key": "<path to openssl private key>",
"key-pass": true,
"main": "bin/console.php",
"output": "component-installer.phar",
"stub": true
}
35 changes: 35 additions & 0 deletions composer.json
@@ -0,0 +1,35 @@
{
"name": "zendframework/component-installer",
"description": "Composer scripts for automating component registration in zend-mvc applications",
"license": "BSD-3-Clause",
"require": {
"php": "^5.5 || ^7.0",
"zendframework/zend-console": "^2.5",
"zfcampus/zf-console": "^1.0"
},
"require-dev": {
"composer/composer": ">=1.0.0-alpha10",
"phpunit/phpunit": "^4.7",
"roave/security-advisories": "dev-master",
"squizlabs/php_codesniffer": "^2.5"
},
"autoload": {
"psr-4": {
"Zend\\ComponentInstaller\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"ZendTest\\ComponentInstaller\\": "test/"
}
},
"scripts": {
"check": [
"@cs",
"@test"
],
"cs": "phpcs",
"cs-fix": "phpcbf",
"test": "phpunit"
}
}
14 changes: 14 additions & 0 deletions config/routes.php
@@ -0,0 +1,14 @@
<?php

return [
[
'name' => 'install',
'route' => '[<path>]',
'description' => 'Install the zend-mvc component installer scripts and related code into your project tree.',
'short_description' => 'Install the component installer scripts',
'options_descriptions' => [
'[<path>]' => 'Path to the project, if not the current working directory'
],
'handler' => Zend\ComponentInstaller\Command\Installer::class,
]
];
21 changes: 21 additions & 0 deletions phpcs.xml
@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<ruleset name="Zend Framework coding standard">
<description>Zend Framework coding standard</description>

<!-- display progress -->
<arg value="p"/>
<arg name="colors"/>

<!-- inherit rules from: -->
<rule ref="PSR2"/>
<rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace">
<properties>
<property name="ignoreBlankLines" value="false"/>
</properties>
</rule>

<!-- Paths to check -->
<file>src</file>
<file>test</file>
</ruleset>
17 changes: 17 additions & 0 deletions phpunit.xml.dist
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true">
<testsuites>
<testsuite name="Zend\\Expressive Tests">
<directory>./test</directory>
</testsuite>
</testsuites>

<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
</phpunit>
116 changes: 116 additions & 0 deletions src/Command/Installer.php
@@ -0,0 +1,116 @@
<?php
namespace Zend\ComponentInstaller\Command;

use Zend\Console\Adapter\AdapterInterface as Console;
use Zend\Console\ColorInterface as Color;
use ZF\Console\Route;

class Installer
{
const SCRIPT_POST_PACKAGE_INSTALL = 'Zend\ComponentInstaller\ComponentInstaller::postPackageInstall';
const SCRIPT_POST_PACKAGE_UNINSTALL = 'Zend\ComponentInstaller\ComponentInstaller::postPackageUninstall';

public function __invoke($route, $console)
{
$path = $route->getMatchedParam('path', realpath(getcwd()));

$installPath = $this->createComponentInstallerDirectory($path);
if (false === $installPath) {
$console->writeLine(sprintf(
'Unable to create component-installer directory in selected path (%s); aborting',
$path
), Color::RED);
return 1;
}

if (false === copy(__DIR__ . '/../ComponentInstaller.php', sprintf('%s/ComponentInstaller.php', $installPath))) {
$console->writeLine(sprintf(
'Unable to copy ComponentInstaller.php to %s/component-installer/; aborting',
$path
), Color::RED);
return 1;
}
$composer = $this->getComposer($path);
if (false === $composer
|| empty($composer)
) {
$console->writeLine(sprintf(
'Unable to read/parse %s/composer.json; aborting',
$path
), Color::RED);
return 1;
}

$composer = $this->injectAutoloadEntry($composer);
$composer = $this->injectScripts($composer);
if (false === $this->writeComposer($composer, $path)) {
$console->writeLine(sprintf(
'Unable to write updated %s/composer.json; aborting',
$path
), Color::RED);
return 1;
}

$console->writeLine('ComponentInstaller installed!', Color::GREEN);
return 0;
}

private function createComponentInstallerDirectory($path)
{
$newPath = sprintf('%s/component-installer', $path);
if (is_dir($newPath)) {
return $newPath;
}
if (false === mkdir($newPath, 0755, true)) {
return false;
}
return $newPath;
}

private function getComposer($path)
{
$composerFile = sprintf('%s/composer.json', $path);
if (! is_file($composerFile)) {
return false;
}
$composerJson = file_get_contents($composerFile);
return json_decode($composerJson, true);
}

private function injectAutoloadEntry(array $composer)
{
if (isset($composer['autoload']['psr-4']['Zend\\ComponentInstaller\\'])) {
return $composer;
}
$composer['autoload']['psr-4']['Zend\\ComponentInstaller\\'] = 'component-installer/';
return $composer;
}

private function injectScripts(array $composer)
{
if (! isset($composer['scripts']['post-package-install'])) {
$composer['scripts']['post-package-install'] = [];
}
if (! isset($composer['scripts']['post-package-uninstall'])) {
$composer['scripts']['post-package-uninstall'] = [];
}
if (! in_array(self::SCRIPT_POST_PACKAGE_INSTALL, $composer['scripts']['post-package-install'])) {
$composer['scripts']['post-package-install'][] = self::SCRIPT_POST_PACKAGE_INSTALL;
}
if (! in_array(self::SCRIPT_POST_PACKAGE_UNINSTALL, $composer['scripts']['post-package-uninstall'])) {
$composer['scripts']['post-package-uninstall'][] = self::SCRIPT_POST_PACKAGE_UNINSTALL;
}
return $composer;
}

private function writeComposer(array $composer, $path)
{
return file_put_contents(
sprintf('%s/composer.json', $path),
json_encode(
$composer,
JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
)
);
}
}
62 changes: 62 additions & 0 deletions src/ComponentInstaller.php
@@ -0,0 +1,62 @@
<?php
namespace Zend\ComponentInstaller;

/*
use Composer\IO\IOInterface;
use Composer\Script\Event;
use Composer\Script\PackageEvent;
*/

class ComponentInstaller
{
public static function postPackageInstall(/* PackageEvent */ $event)
{
if (! $event->isDevMode()) {
// Do nothing in production mode.
return;
}

if (! is_file('config/application.config.php')) {
// Do nothing if config/application.config.php does not exist
return;
}

$io = $event->getIo();

$package = $event->getOperation()->getPackage();
$name = $package->getName();
$extra = $package->getExtra();

if (! isset($extra['module'])) {
// Do nothing if the package is not a module
return;
}
$module = $extra['module'];

$io->write(sprintf('<info>Installing module %s from package %s</info>', $module, $name));
self::updateApplicationConfig($module, $io);
}

private static function updateApplicationConfig($module, /* IOInterface */ $io)
{
$config = file_get_contents('config/application.config.php');

if (self::moduleIsRegistered($module, $config)) {
$io->write(sprintf('<info> Module is already registered; skipping</info>'));
return;
}

$pattern = '/^(\s+)(\'modules\'\s*\=\>\s*(array\(|\[))\s*$/m';
$replacement = '$1$2' . "\n" . '$1 \'' . $module . '\',';
$config = preg_replace($pattern, $replacement, $config);
file_put_contents('config/application.config.php', $config);
}

private static function moduleIsRegistered($module, $config)
{
return preg_match(
'/\'modules\'\s*\=\>\s*(array\(|\[)[^)\]]*\'' . $module . '\'/s',
$config
);
}
}

0 comments on commit 6369b7f

Please sign in to comment.