0

I'm using composer and phing to initialize a boilerplate I made. Basically I'm using this post-create-project hook to call my phing buildfile.

"scripts": {
    "post-create-project-cmd": "bin/phing -f boilerplate.xml"
}

My phing file looks something like this:

<?xml version="1.0"?>
<project name="boilerplate" default="build">
<target name="build">
    <propertyprompt propertyname="APP_NAME" promptcharacter=":" defaultValue="Example">Enter a name for the app</propertyprompt>
    <propertyprompt propertyname="APP_NS" promptcharacter=":" defaultValue="Example">Enter a desired namespace for the app</propertyprompt>
    <php expression="strtolower('${APP_NAME}');" returnProperty="APP_KEY" />
    <php expression="str_replace(' ', '_', '${APP_KEY}');" returnProperty="APP_KEY" />
    <php expression="preg_replace('/[^a-z0-9_-]/i', '', '${APP_KEY}');" returnProperty="APP_KEY" />
    <php expression="preg_replace('/[_-]/', '', '${APP_KEY}');" returnProperty="APP_KEY_PHING" />
    <php expression="str_replace(' ', '', '${APP_NS}');" returnProperty="APP_NS" />

    <echo msg="Your chosen app name is '${APP_NAME}'" />
    <echo msg="Your generated namespace is '${APP_NS}'" />
    <echo msg="Your generated app key is '${APP_KEY}'" />
    <echo msg="Your generated phing key is '${APP_KEY_PHING}'" />

    <copy file="composer.json.tpl" tofile="composer.json"
          overwrite="true">
        <filterchain>
            <replacetokens begintoken="%%" endtoken="%%">
                <token key="APP_NAME" value="${APP_NAME}"/>
                <token key="APP_KEY" value="${APP_KEY}"/>
                <token key="APP_NS" value="${APP_NS}"/>
            </replacetokens>
        </filterchain>
    </copy>
    <delete>
        <fileset dir=".">
            <include name="composer.json.tpl" />
        </fileset>
    </delete>
    <reflexive>
        <fileset dir=".">
            <include pattern="*.*" />
            <include pattern="build/**/*" />
            <include pattern="app/**/*" />
        </fileset>
        <filterchain>
            <replacetokens begintoken="%%" endtoken="%%">
                <token key="APP_NAME" value="${APP_NAME}"/>
                <token key="APP_KEY" value="${APP_KEY}"/>
                <token key="APP_KEY_PHING" value="${APP_KEY_PHING}"/>
                <token key="APP_NS" value="${APP_NS}"/>
            </replacetokens>
        </filterchain>
    </reflexive>
    <echo msg="Project successfully prepared." />
</target>
</project>

When I just execute my phing file everything works fine. When I execute it via composer it skips the propertyprompts and uses the default value.

How can I prohibit this behavior?

Jochen Ullrich
  • 568
  • 3
  • 22

1 Answers1

4

After some reverse engineering I found out why this happens. Composer internally uses a Symfony Process class to spawn a process when you use the command line for a script. This Process component grabs the in & output stream to redirect it to composer somehow. That doesn't allow user inputs, though, and skips them.

What I did to solve it was writing a wrapper around Phing to use that for composer. You can use it if you want, but it's really basic and could be a lot more flexible.

<?php

use Composer\Script\Event;

class BoilerplateInstaller {

    public static function install(Event $event) {
        $phingPath = __DIR__ . "/vendor/phing/phing/classes";
        set_include_path(
            $phingPath .
            PATH_SEPARATOR .
            get_include_path()
        );

        require_once($phingPath.'/phing/Phing.php');
        Phing::startup();
        $args = array(
            '-f',
            'boilerplate.xml',
        );
        Phing::fire($args);
        Phing::shutdown();
    }
}

And this is the changed part of my composer.json

"scripts": {
    "post-create-project-cmd": "BoilerplateInstaller::install"
},
"autoload": {
    "psr-0": {
        "": "./"
    }
}
Jochen Ullrich
  • 568
  • 3
  • 22