Completed
Pull Request — master (#23)
by
unknown
05:28
created

ScriptHandler::ensureConfigAndRouting()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
rs 9.4285
cc 3
eloc 8
nc 2
nop 1
1
<?php
2
3
/**
4
 * @license MIT, http://opensource.org/licenses/MIT
5
 * @copyright Aimeos (aimeos.org), 2014-2016
6
 * @package symfony
7
 */
8
9
10
namespace Aimeos\ShopBundle\Composer;
11
12
use Symfony\Component\Filesystem\Filesystem;
13
use Symfony\Component\Process\Process;
14
use Symfony\Component\Process\PhpExecutableFinder;
15
use Composer\Script\CommandEvent;
16
17
18
/**
19
 * Performs bundle setup during composer installs
20
 *
21
 * @package symfony
22
 */
23
class ScriptHandler
24
{
25
	/**
26
	 * Sets up the shop database.
27
	 *
28
	 * @param CommandEvent $event CommandEvent instance
29
	 * @throws \RuntimeException If an error occured
30
	 */
31
	public static function setupDatabase( CommandEvent $event )
32
	{
33
		$options = $env = array();
34
35
		if( $event->isDevMode() ) {
36
			$options[] = '--option=setup/default/demo:1';
37
		} else {
38
			$env[] = '--env=prod';
39
		}
40
41
		self::executeCommand( $event, 'aimeos:setup', $options + $env );
42
		self::executeCommand( $event, 'aimeos:cache', $env );
43
	}
44
45
46
	/**
47
	 * Ensure existing config and routing for the shop bundle.
48
	 *
49
	 * @param CommandEvent $event CommandEvent instance
50
	 * @throws \RuntimeException If an error occured
51
	 */
52
	public static function ensureConfigAndRouting( CommandEvent $event )
53
	{
54
		$event->getIO()->write( 'Installing the Aimeos shop bundle' );
55
56
		$options = self::getOptions( $event );
57
58
		if( !isset( $options['symfony-app-dir'] ) || !is_dir( $options['symfony-app-dir'] ) )
59
		{
60
			$msg = 'An error occurred because the "%1$s" option or the "%2$s" directory isn\'t available';
61
			throw new \RuntimeException( sprintf( $msg, 'symfony-app-dir', $options['symfony-app-dir'] ) );
62
		}
63
64
		self::updateConfigFile( $options['symfony-app-dir'] . '/config/config.yml' );
65
		self::updateRoutingFile( $options['symfony-app-dir'] . '/config/routing.yml' );
66
	}
67
68
69
	/**
70
	 * Installs the shop bundle.
71
	 *
72
	 * @param CommandEvent $event CommandEvent instance
73
	 * @throws \RuntimeException If an error occured
74
	 */
75
	public static function installBundle( CommandEvent $event )
76
	{
77
		$event->getIO()->write( 'Installing the Aimeos shop bundle' );
78
79
		$options = self::getOptions( $event );
80
81
		if( !isset( $options['symfony-app-dir'] ) || !is_dir( $options['symfony-app-dir'] ) )
82
		{
83
			$msg = 'An error occurred because the "%1$s" option or the "%2$s" directory isn\'t available';
84
			throw new \RuntimeException( sprintf( $msg, 'symfony-app-dir', $options['symfony-app-dir'] ) );
85
		}
86
87
		if( !isset( $options['symfony-web-dir'] ) || !is_dir( $options['symfony-web-dir'] ) )
88
		{
89
			$msg = 'An error occurred because the "%1$s" option or the "%2$s" directory isn\'t available';
90
			throw new \RuntimeException( sprintf( $msg, 'symfony-web-dir', $options['symfony-web-dir'] ) );
91
		}
92
93
		self::createDirectory( $options['symfony-app-dir'] . '/secure' );
94
		self::createDirectory( $options['symfony-web-dir'] . '/uploads' );
95
		self::createDirectory( $options['symfony-web-dir'] . '/preview' );
96
		self::createDirectory( $options['symfony-web-dir'] . '/files' );
97
	}
98
99
100
	/**
101
	 * Creates a new directory if it doesn't exist yet
102
	 *
103
	 * @param string $dir Absolute path of the new directory
104
	 * @throws \RuntimeException If directory couldn't be created
105
	 */
106
	protected static function createDirectory( $dir )
107
	{
108
		$perm = 0755;
109
110
		if( !is_dir( $dir ) && !mkdir( $dir, $perm, true ) )
111
		{
112
			$msg = 'Unable to create directory "%1$s" with permission "%2$s"';
113
			throw new \RuntimeException( sprintf( $msg, $dir, $perm ) );
114
		}
115
	}
116
117
118
	/**
119
	 * Executes a Symphony command.
120
	 *
121
	 * @param CommandEvent $event Command event object
122
	 * @param string $cmd Command name to execute, e.g. "aimeos:update"
123
	 * @param array List of configuration options for the given command
124
	 * @throws \RuntimeException If the command couldn't be executed
125
	 */
126
	protected static function executeCommand( CommandEvent $event, $cmd, array $options = array() )
127
	{
128
		$php = escapeshellarg( self::getPhp() );
129
		$console = escapeshellarg( self::getConsoleDir( $event ) . '/console' );
130
		$cmd = escapeshellarg( $cmd );
131
132
		foreach( $options as $key => $option ) {
133
			$options[$key] = escapeshellarg( $option );
134
		}
135
136
		if( $event->getIO()->isDecorated() ) {
137
			$console .= ' --ansi';
138
		}
139
140
		$process = new Process( $php . ' ' . $console . ' ' . $cmd . ' ' . implode( ' ', $options ), null, null, null, 3600 );
141
142
		$process->run( function( $type, $buffer ) use ( $event ) {
143
			$event->getIO()->write( $buffer, false );
144
		} );
145
146
		if( !$process->isSuccessful() ) {
147
			throw new \RuntimeException( sprintf( 'An error occurred when executing the "%s" command', escapeshellarg( $cmd ) ) );
148
		}
149
	}
150
151
152
153
	/**
154
	 * Returns a relative path to the directory that contains the `console` command.
155
	 *
156
	 * @param CommandEvent $event Command event object
157
	 * @return string The path to the console directory
158
	 * @throws \RuntimeException If console directory couldn't be found
159
	 */
160
	protected static function getConsoleDir( CommandEvent $event )
161
	{
162
		$options = self::getOptions( $event );
163
164
		if( isset( $options['symfony-bin-dir'] ) && is_dir( $options['symfony-bin-dir'] ) ) {
165
			return $options['symfony-bin-dir'];
166
		}
167
168
		if( isset( $options['symfony-app-dir'] ) && is_dir( $options['symfony-app-dir'] ) ) {
169
			return $options['symfony-app-dir'];
170
		}
171
172
		throw new \RuntimeException( sprintf( 'Console directory not found. Neither %1$s nor %2$s option exist', 'symfony-app-dir', 'symfony-bin-dir' ) );
173
	}
174
175
176
	/**
177
	 * Returns the available options defined in the composer file.
178
	 *
179
	 * @param CommandEvent $event Command event object
180
	 * @return array Associative list of option keys and values
181
	 */
182
	protected static function getOptions( CommandEvent $event )
183
	{
184
		return $event->getComposer()->getPackage()->getExtra();
185
	}
186
187
188
	/**
189
	 * Returns the path to the PHP interpreter.
190
	 *
191
	 * @return string Path to the PHP command
192
	 * @throws \RuntimeException If PHP interpreter couldn't be found
193
	 */
194
	protected static function getPhp()
195
	{
196
		$phpFinder = new PhpExecutableFinder;
197
198
		if( !( $phpPath = $phpFinder->find() ) ) {
199
			throw new \RuntimeException( 'The php executable could not be found, add it to your PATH environment variable and try again' );
200
		}
201
202
		return $phpPath;
203
	}
204
205
206
	/**
207
	 * Adds the Aimeos shop bundle to the config file of the application.
208
	 *
209
	 * @param string $filename Name of the YAML config file
210
	 * @throws \RuntimeException If file is not found
211
	 */
212
	protected static function updateConfigFile( $filename )
213
	{
214
		if( ( $content = file_get_contents( $filename ) ) === false ) {
215
			throw new \RuntimeException( sprintf( 'File "%1$s" not found', $filename ) );
216
		}
217
218
		if( self::addAsseticBundle( $content ) === true ) {
219
			$fs = new Filesystem();
220
			$fs->dumpFile( $filename, $content );
221
		}
222
	}
223
224
225
	/**
226
	 * Adds the Aimeos shop bundle to the routing file of the application.
227
	 *
228
	 * @param string $filename Name of the YAML config file
229
	 * @throws \RuntimeException If file is not found
230
	 */
231
	protected static function updateRoutingFile( $filename )
232
	{
233
		$update = false;
234
235
		if( ( $content = file_get_contents( $filename ) ) === false ) {
236
			throw new \RuntimeException( sprintf( 'File "%1$s" not found', $filename ) );
237
		}
238
239
		if( strpos( $content, 'aimeos_shop:' ) === false )
240
		{
241
			$content .= "\n" . 'aimeos_shop:
242
    resource: "@AimeosShopBundle/Resources/config/routing.yml"
243
    prefix: /';
244
245
			$update = true;
246
		}
247
248
		if( $update === true )
249
		{
250
			$fs = new Filesystem();
251
			$fs->dumpFile( $filename, $content );
252
		}
253
	}
254
255
256
	/**
257
	 * Adds the AimeosShopBundle to the assetic section of the config file
258
	 *
259
	 * @param string &$content Content of the config.yml file
260
	 * @return boolean True if modified, false if not
261
	 */
262
	protected static function addAsseticBundle( &$content )
263
	{
264
		if( preg_match( "/    bundles:[ ]*\[.*'AimeosShopBundle'.*\]/", $content ) !== 1 )
265
		{
266
			$search = array( "/    bundles:[ ]*\[([^\]]+)\]/", "/    bundles:[ ]*\[([ ]*)\]/" );
267
			$replace = array( "    bundles: [$1,'AimeosShopBundle']", "    bundles: ['AimeosShopBundle']" );
268
269
			if( ( $content = preg_replace( $search, $replace, $content ) ) !== null ) {
270
				return true;
271
			}
272
		}
273
274
		return false;
275
	}
276
}
277