diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 8cb34f9..5f7cc86 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -9,6 +9,9 @@ class PhpFpm public $brew; public $cli; public $files; + public $config; + public $site; + public $nginx; public $taps = [ 'homebrew/homebrew-core', @@ -21,22 +24,27 @@ class PhpFpm * @param Brew $brew * @param CommandLine $cli * @param Filesystem $files + * @param Configuration $config + * @param Site $site + * @param Nginx $nginx * @return void */ - public function __construct(Brew $brew, CommandLine $cli, Filesystem $files) + public function __construct(Brew $brew, CommandLine $cli, Filesystem $files, Configuration $config, Site $site, Nginx $nginx) { $this->cli = $cli; $this->brew = $brew; $this->files = $files; + $this->config = $config; + $this->site = $site; + $this->nginx = $nginx; } /** * Install and configure PhpFpm. * - * @param string|null $phpVersion * @return void */ - public function install($phpVersion = null) + public function install() { if (! $this->brew->hasInstalledPhp()) { $this->brew->ensureInstalled('php', [], $this->taps); @@ -44,9 +52,9 @@ public function install($phpVersion = null) $this->files->ensureDirExists(VALET_HOME_PATH.'/Log', user()); - $this->updateConfiguration($phpVersion); + $this->updateConfiguration(); - $this->restart($phpVersion); + $this->restart(); } /** @@ -181,11 +189,19 @@ public function stopRunning() /** * Stop PHP, if a specific version isn't being used globally or by any sites. * - * @param string $phpVersion + * @param string|null $phpVersion * @return void */ public function maybeStop($phpVersion) { + if (! $phpVersion) { + return; + } + + if (strpos($phpVersion, 'php') === false) { + $phpVersion = 'php'.$phpVersion; + } + $phpVersion = $this->normalizePhpVersion($phpVersion); if (! in_array($phpVersion, $this->utilizedPhpVersions())) { @@ -198,11 +214,29 @@ public function maybeStop($phpVersion) * * @param $version * @param bool $force - * @param string|null $site - * @return string + * @param string|null $directory + * @return string|void */ - public function useVersion($version, $force = false, $site = null) + public function useVersion($version, $force = false, $directory = null) { + if ($directory) { + $site = $this->site->getSiteUrl($directory); + + if (! $site) { + warning(sprintf('The [%s] site could not be found in valet site list.', $directory)); + exit(); + } + + if ($version == 'default') { // Remove isolation for this site + $customPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" + $this->site->removeIsolation($site); + $this->maybeStop($customPhpVersion); + $this->nginx->restart(); + info(sprintf('The [%s] site is now using default php version.', $site)); + exit(); + } + } + $version = $this->validateRequestedVersion($version); try { @@ -220,40 +254,55 @@ public function useVersion($version, $force = false, $site = null) } // Delete old Valet sock files, install the new version, and, if this is a global change, unlink and link PHP - if ($site) { + if ($directory && $site) { + $customPhpVersion = $this->site->customPhpVersion($site); // Example output: "74" $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/'.$this->fpmSockName($version)); - $this->install($version); - } else { - // Unlink the current global PHP if there is one installed - if ($this->brew->hasLinkedPhp()) { - $linkedPhp = $this->brew->linkedPhp(); + $this->updateConfiguration($version); + $this->site->installSiteConfig($site, $this->fpmSockName($version), $version); - // Update the old FPM to keep running, using a custom sock file, so existing isolated sites aren't broken - $this->updateConfiguration($linkedPhp); - - // Update existing custom Nginx config files; if they're using the old or new PHP version, - // update them to the new correct sock file location - $this->updateConfigurationForGlobalUpdate($version, $linkedPhp); - - $currentVersion = $this->brew->getLinkedPhpFormula(); - info(sprintf('Unlinking current version: %s', $currentVersion)); - $this->brew->unlink($currentVersion); - } - - info(sprintf('Linking new version: %s', $version)); - $this->brew->link($version, true); - - $this->stopRunning(); - - // remove any orphaned valet.sock files that PHP didn't clean up due to version conflicts - $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); - $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet*.sock'); - - // ensure configuration is correct and start the linked version - $this->install(); + $this->maybeStop($customPhpVersion); + $this->restart($version); + $this->nginx->restart(); + info(sprintf('The [%s] site is now using %s.', $site, $version)); + exit(); } - return $version === 'php' ? $this->brew->determineAliasedVersion($version) : $version; + // Unlink the current global PHP if there is one installed + if ($this->brew->hasLinkedPhp()) { + $linkedPhp = $this->brew->linkedPhp(); + + // Update the old FPM to keep running, using a custom sock file, so existing isolated sites aren't broken + $this->updateConfiguration($linkedPhp); + + // Update existing custom Nginx config files; if they're using the old or new PHP version, + // update them to the new correct sock file location + $this->updateConfigurationForGlobalUpdate($version, $linkedPhp); + + $currentVersion = $this->brew->getLinkedPhpFormula(); + info(sprintf('Unlinking current version: %s', $currentVersion)); + $this->brew->unlink($currentVersion); + } + + info(sprintf('Linking new version: %s', $version)); + $this->brew->link($version, true); + + $this->stopRunning(); + + // remove any orphaned valet.sock files that PHP didn't clean up due to version conflicts + $this->files->unlink(VALET_HOME_PATH.'/valet.sock'); + $this->cli->quietly('sudo rm '.VALET_HOME_PATH.'/valet*.sock'); + + // ensure configuration is correct and start the linked version + $this->install(); + + $newVersion = $version === 'php' ? $this->brew->determineAliasedVersion($version) : $version; + + $this->nginx->restart(); + + info(sprintf('Valet is now using %s.', $newVersion).PHP_EOL); + info('Note that you might need to run composer global update if your PHP version change affects the dependencies of global packages required by Composer.'); + + return $newVersion; } /** diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index f98b234..06df7d3 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -191,17 +191,26 @@ public function proxies() } /** - * Determine if the provided site is a valid site, whether parked or linked. + * Determine if the provided site is a valid site, whether parked or linked and get the site url. * - * @param string $valetSite - * @return bool + * @param string $directory + * @return string|false */ - public function isValidSite($valetSite) + public function getSiteUrl($directory) { - // Remove .tld from sitename if it was provided - $siteName = str_replace('.'.$this->config->read()['tld'], '', $valetSite); + $tld = $this->config->read()['tld']; - return $this->parked()->merge($this->links())->where('site', $siteName)->count() > 0; + if ($directory == '.') { // Allow user to use dot as current dir's site `--site=.` + $directory = $this->host(getcwd()); + } + + $directory = str_replace('.'.$tld, '', $directory); // Remove .tld from sitename if it was provided + + if ($this->parked()->merge($this->links())->where('site', $directory)->count() > 0) { + return $directory.'.'.$tld; + } + + return false; // Invalid directory provided } /** @@ -692,7 +701,7 @@ public function buildSecureNginxServer($url, $siteConf = null) * * @param string $valetSite * @param string $fpmSockName - * @param $phpVersion + * @param string $phpVersion * @return void */ public function installSiteConfig($valetSite, $fpmSockName, $phpVersion) @@ -1091,11 +1100,8 @@ public function customPhpVersion($url) public function replaceSockFile($siteConf, $sockFile, $phpVersion) { $siteConf = preg_replace('/valet[0-9]*.sock/', $sockFile, $siteConf); + $siteConf = preg_replace('/# Valet isolated PHP version.*\n/', '', $siteConf); // Remove `Valet isolated PHP version` line from config - if (! starts_with($siteConf, '# Valet isolated PHP version')) { - $siteConf = '# Valet isolated PHP version : '.$phpVersion.PHP_EOL.$siteConf; - } - - return $siteConf; + return '# Valet isolated PHP version : '.$phpVersion.PHP_EOL.$siteConf; } } diff --git a/cli/valet.php b/cli/valet.php index fe54f53..f558f0b 100755 --- a/cli/valet.php +++ b/cli/valet.php @@ -509,45 +509,7 @@ } } - if ($site) { - $tld = Configuration::read()['tld']; - - if ($site == '.') { // Allow user to use dot as current dir's site `--site=.` - $site = Site::host(getcwd()).'.'.$tld; - } - - if (false === strpos($site, '.'.$tld)) { - $site = $site.'.'.$tld; // Allow user to pass just the site's directory name - } - - if (! Site::isValidSite($site)) { - return warning(sprintf('Site %s could not be found in valet site list.', $site)); - } - - if ($phpVersion == 'default') { - $customPhpVersion = Site::customPhpVersion($site); // Example output: "74" - Site::removeIsolation($site); - if ($customPhpVersion) { - PhpFpm::maybeStop('php'.$customPhpVersion); - } - - Nginx::restart(); - - info(sprintf('The [%s] site is now using default php version.', $site)); - } else { - $newVersion = PhpFpm::useVersion($phpVersion, $force, $site); - - Site::installSiteConfig($site, PhpFpm::fpmSockName($phpVersion), $phpVersion); - Nginx::restart(); - - info(sprintf('The [%s] site is now using %s.', $site, $newVersion)); - } - } else { - $newVersion = PhpFpm::useVersion($phpVersion, $force); - Nginx::restart(); - info(sprintf('Valet is now using %s.', $newVersion).PHP_EOL); - info('Note that you might need to run composer global update if your PHP version change affects the dependencies of global packages required by Composer.'); - } + PhpFpm::useVersion($phpVersion, $force, $site); })->descriptions('Change the version of PHP used by valet', [ 'phpVersion' => 'The PHP version you want to use, e.g php@7.3', '--site' => 'Isolate PHP version of a specific valet site. e.g: --site=site.test', diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index 22124c9..5a000da 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -3,9 +3,12 @@ use Illuminate\Container\Container; use Valet\Brew; use Valet\CommandLine; +use Valet\Configuration; use Valet\Filesystem; +use Valet\Nginx; use Valet\PhpFpm; use function Valet\resolve; +use Valet\Site; use function Valet\swap; use function Valet\user; @@ -65,10 +68,16 @@ public function test_stopRunning_will_pass_filtered_result_of_getRunningServices public function test_use_version_will_convert_passed_php_version() { $brewMock = Mockery::mock(Brew::class); + $nginxMock = Mockery::mock(Nginx::class); + $siteMock = Mockery::mock(Site::class); + $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, resolve(CommandLine::class), resolve(Filesystem::class), + resolve(Configuration::class), + $siteMock, + $nginxMock, ])->makePartial(); $phpFpmMock->shouldReceive('install'); @@ -86,6 +95,8 @@ public function test_use_version_will_convert_passed_php_version() $brewMock->shouldReceive('getAllRunningServices')->andReturn(collect()); $brewMock->shouldReceive('stopService'); + $nginxMock->shouldReceive('restart'); + // Test both non prefixed and prefixed $this->assertSame('php@7.2', $phpFpmMock->useVersion('php7.2')); $this->assertSame('php@7.2', $phpFpmMock->useVersion('php72')); @@ -109,11 +120,18 @@ public function test_use_version_will_throw_if_version_not_supported() public function test_use_version_if_already_linked_php_will_unlink_before_installing() { $brewMock = Mockery::mock(Brew::class); + $nginxMock = Mockery::mock(Nginx::class); + $siteMock = Mockery::mock(Site::class); + $phpFpmMock = Mockery::mock(PhpFpm::class, [ $brewMock, resolve(CommandLine::class), resolve(Filesystem::class), + resolve(Configuration::class), + $siteMock, + $nginxMock, ])->makePartial(); + $phpFpmMock->shouldReceive('install'); $phpFpmMock->shouldReceive('updateConfigurationForGlobalUpdate'); @@ -132,6 +150,8 @@ public function test_use_version_if_already_linked_php_will_unlink_before_instal $brewMock->shouldReceive('getAllRunningServices')->andReturn(collect()); $brewMock->shouldReceive('stopService'); + $nginxMock->shouldReceive('restart'); + // Test both non prefixed and prefixed $this->assertSame('php@7.2', $phpFpmMock->useVersion('php@7.2')); }