Search code examples
arraysmultidimensional-arrayphing

How to handle multidimensional data in build properties to process them with foreach?


having a list of users which should be different for stage and production:

user1:
    name: username1
    password: password1
    email: email1
    roles: role1, role2
user2:
    name: username2
    password: password2
    email: email2
    roles: role1, role2
user3:
    name: username3
    password: password3
    email: email3
    roles: role1, role2
user4:
    name: username4
    password: password4
    email: email4
    roles: role1, role2
user5:
    name: username5
    password: password5
    email: email5
    roles: role1, role2

i tried to put them in the build.properties file (i skipped the roles part)

[user]
admins=username1|password1|email1,username2|password2|email2,username3|password3|email3,username4|password4|email4,username5|password5|email5

which work quite ok with the following code snippet in the build.xml

<target name="createUsers">
    <foreach list="${admins}" param="_userset" target="createUser" />
</target>

<target name="createUser">
    <php expression="strpos('${_userset}', '|')" returnProperty="_pos1"/>
    <php expression="strrpos('${_userset}', '|')" returnProperty="_pos2"/>
    <php expression="${_pos2}-${_pos1}" returnProperty="_len"/>

    <php expression="substr('${_userset}', 0, ${_pos1})" returnProperty="_username"/>
    <php expression="substr('${_userset}', ${_pos1}+1, ${_len}-1)" returnProperty="_password"/>
    <php expression="substr('${_userset}', ${_pos2}+1)" returnProperty="_email"/>

    <SymfonyConsole console="${bin.symfony}" command="fos:user:create">
        <arg value="${_username}" />
        <arg value="${_email}" />
        <arg value="${_password}" />
    </SymfonyConsole>
</target>

but the part in the build.properties file is quite unreadable and unhandy, also adding new values like roles, which is also a list, is rather unhandy.

breaking up the lines does not work, like for java https://stackoverflow.com/a/8978515/590247:

[user]
admins=username1|password1|email1,\
    username2|password2|email2,\
    username3|password3|email3,\
    username4|password4|email4,\
    username5|password5|email5

is there a better way to store the multidimensional data?


Solution

  • One solution for this, would be to write an adhoctask, partially similar to http://raphaelstolt.blogspot.ie/2009/04/creating-and-using-phing-ad-hoc-tasks.html ( a very simple example is in the phing documentation at https://www.phing.info/docs/guide/stable/app.coretasks.html#AdhocTaskdefTask ).

    You would iterate through your arrays in that adhoctask (perhaps passed in as a property or read in directly from the properties file... - better yet as a serialized array written to a file).

    It's not strictly possible to call a phing task from an adhoc task, but you can get around this with exec...

    $r = exec(escapeshellcommand("phing -f build.xml symfonycreateusertask");
    

    But as you're simply using SymfonyConsole to essentially exec control out to symfony, I would do that directly instead.

    As a very rough example, code for this might look like:

    <adhoc-task name="createusers"><![CDATA[
            class CreateusersTask extends Task {
                private $filename;
    
                function setFile($filename) {
                    $this->filename = $filename;
                }
    
                function main() {
                    $this->log("Createusers: " . $this->filename);
                    $serialised = file_get_contents($this->filename);
                    $users = unserialize($serialised);
                    foreach($users as $userRow) {
                        $output = [];
                        $return = 0;
                        $user = $userRow['user'];
                        //....
                        $r = exec(
                         "symfony fos:user:create $user $email $password", 
                         $output, 
                         $return
                        );
                        $this->log(implode($output));
                    }
                }
            }
    ]]></adhoc-task>
    

    And in the target...

    <target name="...">
    <createusers file="users.data"/>
    </target>