diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3f82dff..47540d8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: true matrix: - php: ['8.0', 8.1, 8.2] + php: ['8.0', 8.1, 8.2, 8.3] name: PHP ${{ matrix.php }} diff --git a/CHANGELOG.md b/CHANGELOG.md index bd8646e..d4f5e5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ # Release Notes -## [Unreleased](https://github.com/laravel/valet/compare/v4.1.4...master) +## [Unreleased](https://github.com/laravel/valet/compare/v4.4.0...master) + +## [v4.4.0](https://github.com/laravel/valet/compare/v4.3.0...v4.4.0) - 2023-09-26 + +- Allow LaravelValetDriver to serve other /public/*.php files by [@drbyte](https://github.com/drbyte) in https://github.com/laravel/valet/pull/1439 +- Support static caching in Statamic by [@jasonvarga](https://github.com/jasonvarga) in https://github.com/laravel/valet/pull/1440 +- Fix link command's `--isolate` argument with custom name by [@mcaskill](https://github.com/mcaskill) in https://github.com/laravel/valet/pull/1428 + +## [v4.3.0](https://github.com/laravel/valet/compare/v4.1.4...v4.3.0) - 2023-09-05 + +- Add "valet stop dnsmasq" option by [@drbyte](https://github.com/drbyte) in https://github.com/laravel/valet/pull/1422 +- Drop Mailhog and Redis from default logs list, since Valet doesn't install them by [@mattstauffer](https://github.com/mattstauffer) in https://github.com/laravel/valet/pull/1438 ## [v4.1.4](https://github.com/laravel/valet/compare/v4.1.3...v4.1.4) - 2023-08-14 diff --git a/cli/Valet/Brew.php b/cli/Valet/Brew.php index d7e5109..121a139 100644 --- a/cli/Valet/Brew.php +++ b/cli/Valet/Brew.php @@ -11,6 +11,7 @@ class Brew // This is the array of PHP versions that Valet will attempt to install/configure when requested const SUPPORTED_PHP_VERSIONS = [ 'php', + 'php@8.3', 'php@8.2', 'php@8.1', 'php@8.0', diff --git a/cli/Valet/DnsMasq.php b/cli/Valet/DnsMasq.php index 1932d6c..a0d74eb 100644 --- a/cli/Valet/DnsMasq.php +++ b/cli/Valet/DnsMasq.php @@ -52,6 +52,14 @@ public function uninstall(): void } } + /** + * Stop the dnsmasq service. + */ + public function stop(): void + { + $this->brew->stopService(['dnsmasq']); + } + /** * Tell Homebrew to restart dnsmasq. */ @@ -70,7 +78,7 @@ public function ensureUsingDnsmasqDForConfigs(): void // set primary config to look for configs in /usr/local/etc/dnsmasq.d/*.conf $contents = $this->files->get($this->dnsmasqMasterConfigFile); // ensure the line we need to use is present, and uncomment it if needed - if (false === strpos($contents, 'conf-dir='.BREW_PREFIX.'/etc/dnsmasq.d/,*.conf')) { + if (strpos($contents, 'conf-dir='.BREW_PREFIX.'/etc/dnsmasq.d/,*.conf') === false) { $contents .= PHP_EOL.'conf-dir='.BREW_PREFIX.'/etc/dnsmasq.d/,*.conf'.PHP_EOL; } $contents = str_replace('#conf-dir='.BREW_PREFIX.'/etc/dnsmasq.d/,*.conf', 'conf-dir='.BREW_PREFIX.'/etc/dnsmasq.d/,*.conf', $contents); diff --git a/cli/Valet/Drivers/LaravelValetDriver.php b/cli/Valet/Drivers/LaravelValetDriver.php index f5b8ded..22b576c 100644 --- a/cli/Valet/Drivers/LaravelValetDriver.php +++ b/cli/Valet/Drivers/LaravelValetDriver.php @@ -52,6 +52,11 @@ public function isStaticFile(string $sitePath, string $siteName, string $uri)/*: */ public function frontControllerPath(string $sitePath, string $siteName, string $uri): ?string { + if (file_exists($staticFilePath = $sitePath.'/public'.$uri) + && $this->isActualFile($staticFilePath)) { + return $staticFilePath; + } + return $sitePath.'/public/index.php'; } } diff --git a/cli/Valet/Drivers/Specific/ContaoValetDriver.php b/cli/Valet/Drivers/Specific/ContaoValetDriver.php index 293e62a..6649b1b 100644 --- a/cli/Valet/Drivers/Specific/ContaoValetDriver.php +++ b/cli/Valet/Drivers/Specific/ContaoValetDriver.php @@ -35,7 +35,7 @@ public function frontControllerPath(string $sitePath, string $siteName, string $ return $sitePath.'/web/install.php'; } - if (0 === strncmp($uri, '/app_dev.php', 12)) { + if (strncmp($uri, '/app_dev.php', 12) === 0) { $_SERVER['SCRIPT_NAME'] = '/app_dev.php'; $_SERVER['SCRIPT_FILENAME'] = $sitePath.'/app_dev.php'; diff --git a/cli/Valet/Drivers/Specific/Magento2ValetDriver.php b/cli/Valet/Drivers/Specific/Magento2ValetDriver.php index 1651926..c6c7d43 100644 --- a/cli/Valet/Drivers/Specific/Magento2ValetDriver.php +++ b/cli/Valet/Drivers/Specific/Magento2ValetDriver.php @@ -7,16 +7,7 @@ class Magento2ValetDriver extends ValetDriver { /** - * Holds the MAGE_MODE from app/etc/config.php or $ENV. - * - * Can't be correctly typed yet because PHP 7.3. - * - * @param string|null - */ - private $mageMode = null; - - /** - * Determine if the driver serves the request. + * {@inheritdoc} */ public function serves(string $sitePath, string $siteName, string $uri): bool { @@ -24,44 +15,24 @@ public function serves(string $sitePath, string $siteName, string $uri): bool } /** - * Determine if the incoming request is for a static file. + * {@inheritdoc} */ public function isStaticFile(string $sitePath, string $siteName, string $uri)/*: string|false */ { - $this->checkMageMode($sitePath); + $uri = preg_replace('/^\/static(\/version[\d]+)/', '/static', $uri); - $uri = $this->handleForVersions($uri); - $route = parse_url(substr($uri, 1))['path']; - - $pub = ''; - if ('developer' === $this->mageMode) { - $pub = 'pub/'; + if (file_exists($staticFilePath = $sitePath.'/pub'.$uri)) { + return $staticFilePath; } - if (! $this->isPubDirectory($sitePath, $route, $pub)) { - return false; - } - - $magentoPackagePubDir = $sitePath; - if ('developer' !== $this->mageMode) { - $magentoPackagePubDir .= '/pub'; - } - - $file = $magentoPackagePubDir.'/'.$route; - - if (file_exists($file)) { - return $magentoPackagePubDir.$uri; - } - - if (strpos($route, $pub.'static/') === 0) { - $route = preg_replace('#'.$pub.'static/#', '', $route, 1); - $_GET['resource'] = $route; - include $magentoPackagePubDir.'/'.$pub.'static.php'; + if (strpos($uri, '/static/') === 0) { + $_GET['resource'] = preg_replace('#static/#', '', $uri, 1); + include $sitePath.'/pub/static.php'; exit; } - if (strpos($route, $pub.'media/') === 0) { - include $magentoPackagePubDir.'/'.$pub.'get.php'; + if (strpos($uri, '/media/') === 0) { + include $sitePath.'/pub/get.php'; exit; } @@ -69,75 +40,12 @@ public function isStaticFile(string $sitePath, string $siteName, string $uri)/*: } /** - * Rewrite URLs that look like "versions12345/" to remove - * the versions12345/ part. - */ - private function handleForVersions($route): string - { - return preg_replace('/version\d*\//', '', $route); - } - - /** - * Determine the current MAGE_MODE. - */ - private function checkMageMode($sitePath): void - { - if (null !== $this->mageMode) { - // We have already figure out mode, no need to check it again - return; - } - - if (! file_exists($sitePath.'/index.php')) { - $this->mageMode = 'production'; // Can't use developer mode without index.php in project root - - return; - } - - $mageConfig = []; - - if (file_exists($sitePath.'/app/etc/env.php')) { - $mageConfig = require $sitePath.'/app/etc/env.php'; - } - - if (array_key_exists('MAGE_MODE', $mageConfig)) { - $this->mageMode = $mageConfig['MAGE_MODE']; - } - } - - /** - * Checks to see if route is referencing any directory inside pub. This is a dynamic check so that if any new - * directories are added to pub this driver will not need to be updated. - */ - private function isPubDirectory($sitePath, $route, $pub = ''): bool - { - $sitePath .= '/pub/'; - $dirs = glob($sitePath.'*', GLOB_ONLYDIR); - - $dirs = str_replace($sitePath, '', $dirs); - - foreach ($dirs as $dir) { - if (strpos($route, $pub.$dir.'/') === 0) { - return true; - } - } - - return false; - } - - /** - * Get the fully resolved path to the application's front controller. + * {@inheritdoc} */ public function frontControllerPath(string $sitePath, string $siteName, string $uri): ?string { - $this->checkMageMode($sitePath); - - if ('developer' === $this->mageMode) { - $_SERVER['DOCUMENT_ROOT'] = $sitePath; - - return $sitePath.'/index.php'; - } - - $_SERVER['DOCUMENT_ROOT'] = $sitePath.'/pub'; + $_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST']; + $_SERVER['DOCUMENT_ROOT'] = $sitePath; return $sitePath.'/pub/index.php'; } diff --git a/cli/Valet/Drivers/Specific/StatamicV2ValetDriver.php b/cli/Valet/Drivers/Specific/StatamicV2ValetDriver.php new file mode 100644 index 0000000..4eee35c --- /dev/null +++ b/cli/Valet/Drivers/Specific/StatamicV2ValetDriver.php @@ -0,0 +1,127 @@ +isActualFile($staticFilePath = $sitePath.$uri)) { + return $staticFilePath; + } elseif ($this->isActualFile($staticFilePath = $sitePath.'/public'.$uri)) { + return $staticFilePath; + } + + return false; + } + + /** + * Get the fully resolved path to the application's front controller. + */ + public function frontControllerPath(string $sitePath, string $siteName, string $uri): ?string + { + if ($_SERVER['REQUEST_METHOD'] === 'GET' && $this->isActualFile($staticPath = $this->getStaticPath($sitePath))) { + return $staticPath; + } + + if ($uri === '/installer.php') { + return $sitePath.'/installer.php'; + } + + $scriptName = '/index.php'; + + if ($this->isActualFile($sitePath.'/index.php')) { + $indexPath = $sitePath.'/index.php'; + } + + if ($isAboveWebroot = $this->isActualFile($sitePath.'/public/index.php')) { + $indexPath = $sitePath.'/public/index.php'; + } + + $sitePathPrefix = ($isAboveWebroot) ? $sitePath.'/public' : $sitePath; + + if ($locale = $this->getUriLocale($uri)) { + if ($this->isActualFile($localeIndexPath = $sitePathPrefix.'/'.$locale.'/index.php')) { + // Force trailing slashes on locale roots. + if ($uri === '/'.$locale) { + header('Location: '.$uri.'/'); + exit; + } + + $indexPath = $localeIndexPath; + $scriptName = '/'.$locale.'/index.php'; + } + } + + $_SERVER['SCRIPT_NAME'] = $scriptName; + $_SERVER['SCRIPT_FILENAME'] = $sitePathPrefix.$scriptName; + + return $indexPath; + } + + /** + * Get the locale from this URI. + */ + public function getUriLocale(string $uri): ?string + { + $parts = explode('/', $uri); + $locale = $parts[1]; + + if (count($parts) < 2 || ! in_array($locale, $this->getLocales())) { + return null; + } + + return $locale; + } + + /** + * Get the list of possible locales used in the first segment of a URI. + */ + public function getLocales(): array + { + return [ + 'af', 'ax', 'al', 'dz', 'as', 'ad', 'ao', 'ai', 'aq', 'ag', 'ar', 'am', 'aw', 'au', 'at', 'az', 'bs', 'bh', + 'bd', 'bb', 'by', 'be', 'bz', 'bj', 'bm', 'bt', 'bo', 'bq', 'ba', 'bw', 'bv', 'br', 'io', 'bn', 'bg', 'bf', + 'bi', 'cv', 'kh', 'cm', 'ca', 'ky', 'cf', 'td', 'cl', 'cn', 'cx', 'cc', 'co', 'km', 'cg', 'cd', 'ck', 'cr', + 'ci', 'hr', 'cu', 'cw', 'cy', 'cz', 'dk', 'dj', 'dm', 'do', 'ec', 'eg', 'sv', 'gq', 'er', 'ee', 'et', 'fk', + 'fo', 'fj', 'fi', 'fr', 'gf', 'pf', 'tf', 'ga', 'gm', 'ge', 'de', 'gh', 'gi', 'gr', 'gl', 'gd', 'gp', 'gu', + 'gt', 'gg', 'gn', 'gw', 'gy', 'ht', 'hm', 'va', 'hn', 'hk', 'hu', 'is', 'in', 'id', 'ir', 'iq', 'ie', 'im', + 'il', 'it', 'jm', 'jp', 'je', 'jo', 'kz', 'ke', 'ki', 'kp', 'kr', 'kw', 'kg', 'la', 'lv', 'lb', 'ls', 'lr', + 'ly', 'li', 'lt', 'lu', 'mo', 'mk', 'mg', 'mw', 'my', 'mv', 'ml', 'mt', 'mh', 'mq', 'mr', 'mu', 'yt', 'mx', + 'fm', 'md', 'mc', 'mn', 'me', 'ms', 'ma', 'mz', 'mm', 'na', 'nr', 'np', 'nl', 'nc', 'nz', 'ni', 'ne', 'ng', + 'nu', 'nf', 'mp', 'no', 'om', 'pk', 'pw', 'ps', 'pa', 'pg', 'py', 'pe', 'ph', 'pn', 'pl', 'pt', 'pr', 'qa', + 're', 'ro', 'ru', 'rw', 'bl', 'sh', 'kn', 'lc', 'mf', 'pm', 'vc', 'ws', 'sm', 'st', 'sa', 'sn', 'rs', 'sc', + 'sl', 'sg', 'sx', 'sk', 'si', 'sb', 'so', 'za', 'gs', 'ss', 'es', 'lk', 'sd', 'sr', 'sj', 'sz', 'se', 'ch', + 'sy', 'tw', 'tj', 'tz', 'th', 'tl', 'tg', 'tk', 'to', 'tt', 'tn', 'tr', 'tm', 'tc', 'tv', 'ug', 'ua', 'ae', + 'gb', 'us', 'um', 'uy', 'uz', 'vu', 've', 'vn', 'vg', 'vi', 'wf', 'eh', 'ye', 'zm', 'zw', 'en', 'zh', + ]; + } + + /** + * Get the path to a statically cached page. + */ + protected function getStaticPath(string $sitePath): string + { + $parts = parse_url($_SERVER['REQUEST_URI']); + $query = isset($parts['query']) ? $parts['query'] : ''; + + return $sitePath.'/static'.$parts['path'].'_'.$query.'.html'; + } +} diff --git a/cli/Valet/Drivers/Specific/StatamicValetDriver.php b/cli/Valet/Drivers/Specific/StatamicValetDriver.php index 7392a6a..cb233d5 100644 --- a/cli/Valet/Drivers/Specific/StatamicValetDriver.php +++ b/cli/Valet/Drivers/Specific/StatamicValetDriver.php @@ -2,126 +2,45 @@ namespace Valet\Drivers\Specific; -use Valet\Drivers\ValetDriver; +use Valet\Drivers\LaravelValetDriver; -class StatamicValetDriver extends ValetDriver +class StatamicValetDriver extends LaravelValetDriver { /** * Determine if the driver serves the request. */ public function serves(string $sitePath, string $siteName, string $uri): bool { - return is_dir($sitePath.'/statamic'); - } - - /** - * Determine if the incoming request is for a static file. - */ - public function isStaticFile(string $sitePath, string $siteName, string $uri)/*: string|false */ - { - if (strpos($uri, '/site') === 0 && strpos($uri, '/site/themes') !== 0) { - return false; - } elseif (strpos($uri, '/local') === 0 || strpos($uri, '/statamic') === 0) { - return false; - } elseif ($this->isActualFile($staticFilePath = $sitePath.$uri)) { - return $staticFilePath; - } elseif ($this->isActualFile($staticFilePath = $sitePath.'/public'.$uri)) { - return $staticFilePath; - } - - return false; + return file_exists($sitePath.'/please') + && parent::serves($sitePath, $siteName, $uri); } /** * Get the fully resolved path to the application's front controller. */ - public function frontControllerPath(string $sitePath, string $siteName, string $uri): ?string + public function frontControllerPath(string $sitePath, string $siteName, string $uri): string { - if ($_SERVER['REQUEST_METHOD'] === 'GET' && $this->isActualFile($staticPath = $this->getStaticPath($sitePath))) { + $staticPath = $this->getStaticPath($sitePath); + + if ($staticPath && $this->isActualFile($staticPath)) { return $staticPath; } - if ($uri === '/installer.php') { - return $sitePath.'/installer.php'; - } - - $scriptName = '/index.php'; - - if ($this->isActualFile($sitePath.'/index.php')) { - $indexPath = $sitePath.'/index.php'; - } - - if ($isAboveWebroot = $this->isActualFile($sitePath.'/public/index.php')) { - $indexPath = $sitePath.'/public/index.php'; - } - - $sitePathPrefix = ($isAboveWebroot) ? $sitePath.'/public' : $sitePath; - - if ($locale = $this->getUriLocale($uri)) { - if ($this->isActualFile($localeIndexPath = $sitePathPrefix.'/'.$locale.'/index.php')) { - // Force trailing slashes on locale roots. - if ($uri === '/'.$locale) { - header('Location: '.$uri.'/'); - exit; - } - - $indexPath = $localeIndexPath; - $scriptName = '/'.$locale.'/index.php'; - } - } - - $_SERVER['SCRIPT_NAME'] = $scriptName; - $_SERVER['SCRIPT_FILENAME'] = $sitePathPrefix.$scriptName; - - return $indexPath; + return parent::frontControllerPath($sitePath, $siteName, $uri); } /** - * Get the locale from this URI. + * Get the path to the static file. */ - public function getUriLocale(string $uri): ?string + private function getStaticPath(string $sitePath) { - $parts = explode('/', $uri); - $locale = $parts[1]; - - if (count($parts) < 2 || ! in_array($locale, $this->getLocales())) { - return null; + if (! $uri = $_SERVER['REQUEST_URI'] ?? null) { + return; } - return $locale; - } + $parts = parse_url($uri); + $query = $parts['query'] ?? ''; - /** - * Get the list of possible locales used in the first segment of a URI. - */ - public function getLocales(): array - { - return [ - 'af', 'ax', 'al', 'dz', 'as', 'ad', 'ao', 'ai', 'aq', 'ag', 'ar', 'am', 'aw', 'au', 'at', 'az', 'bs', 'bh', - 'bd', 'bb', 'by', 'be', 'bz', 'bj', 'bm', 'bt', 'bo', 'bq', 'ba', 'bw', 'bv', 'br', 'io', 'bn', 'bg', 'bf', - 'bi', 'cv', 'kh', 'cm', 'ca', 'ky', 'cf', 'td', 'cl', 'cn', 'cx', 'cc', 'co', 'km', 'cg', 'cd', 'ck', 'cr', - 'ci', 'hr', 'cu', 'cw', 'cy', 'cz', 'dk', 'dj', 'dm', 'do', 'ec', 'eg', 'sv', 'gq', 'er', 'ee', 'et', 'fk', - 'fo', 'fj', 'fi', 'fr', 'gf', 'pf', 'tf', 'ga', 'gm', 'ge', 'de', 'gh', 'gi', 'gr', 'gl', 'gd', 'gp', 'gu', - 'gt', 'gg', 'gn', 'gw', 'gy', 'ht', 'hm', 'va', 'hn', 'hk', 'hu', 'is', 'in', 'id', 'ir', 'iq', 'ie', 'im', - 'il', 'it', 'jm', 'jp', 'je', 'jo', 'kz', 'ke', 'ki', 'kp', 'kr', 'kw', 'kg', 'la', 'lv', 'lb', 'ls', 'lr', - 'ly', 'li', 'lt', 'lu', 'mo', 'mk', 'mg', 'mw', 'my', 'mv', 'ml', 'mt', 'mh', 'mq', 'mr', 'mu', 'yt', 'mx', - 'fm', 'md', 'mc', 'mn', 'me', 'ms', 'ma', 'mz', 'mm', 'na', 'nr', 'np', 'nl', 'nc', 'nz', 'ni', 'ne', 'ng', - 'nu', 'nf', 'mp', 'no', 'om', 'pk', 'pw', 'ps', 'pa', 'pg', 'py', 'pe', 'ph', 'pn', 'pl', 'pt', 'pr', 'qa', - 're', 'ro', 'ru', 'rw', 'bl', 'sh', 'kn', 'lc', 'mf', 'pm', 'vc', 'ws', 'sm', 'st', 'sa', 'sn', 'rs', 'sc', - 'sl', 'sg', 'sx', 'sk', 'si', 'sb', 'so', 'za', 'gs', 'ss', 'es', 'lk', 'sd', 'sr', 'sj', 'sz', 'se', 'ch', - 'sy', 'tw', 'tj', 'tz', 'th', 'tl', 'tg', 'tk', 'to', 'tt', 'tn', 'tr', 'tm', 'tc', 'tv', 'ug', 'ua', 'ae', - 'gb', 'us', 'um', 'uy', 'uz', 'vu', 've', 'vn', 'vg', 'vi', 'wf', 'eh', 'ye', 'zm', 'zw', 'en', 'zh', - ]; - } - - /** - * Get the path to a statically cached page. - */ - protected function getStaticPath(string $sitePath): string - { - $parts = parse_url($_SERVER['REQUEST_URI']); - $query = isset($parts['query']) ? $parts['query'] : ''; - - return $sitePath.'/static'.$parts['path'].'_'.$query.'.html'; + return $sitePath.'/public/static'.$parts['path'].'_'.$query.'.html'; } } diff --git a/cli/Valet/Drivers/ValetDriver.php b/cli/Valet/Drivers/ValetDriver.php index 7ce2498..9d6fff1 100644 --- a/cli/Valet/Drivers/ValetDriver.php +++ b/cli/Valet/Drivers/ValetDriver.php @@ -45,8 +45,9 @@ public static function assign(string $sitePath, string $siteName, string $uri): $drivers = array_merge($drivers, static::customDrivers()); // Queue Valet-shipped drivers + $drivers[] = 'Specific\StatamicValetDriver'; $drivers[] = 'LaravelValetDriver'; - $drivers = array_merge($drivers, $specificDrivers); + $drivers = array_unique(array_merge($drivers, $specificDrivers)); $drivers[] = 'BasicWithPublicValetDriver'; $drivers[] = 'BasicValetDriver'; diff --git a/cli/Valet/PhpFpm.php b/cli/Valet/PhpFpm.php index 0f2d8f4..75c92d8 100644 --- a/cli/Valet/PhpFpm.php +++ b/cli/Valet/PhpFpm.php @@ -112,6 +112,7 @@ public function restart(string $phpVersion = null): void */ public function stop(): void { + info('Stopping phpfpm...'); call_user_func_array( [$this->brew, 'stopService'], Brew::SUPPORTED_PHP_VERSIONS @@ -138,6 +139,7 @@ public function fpmConfigPath(string $phpVersion = null): string */ public function stopRunning(): void { + info('Stopping phpfpm...'); $this->brew->stopService( $this->brew->getAllRunningServices() ->filter(function ($service) { @@ -222,7 +224,7 @@ public function useVersion(string $version, bool $force = false): ?string $version = $this->validateRequestedVersion($version); try { - if ($this->brew->linkedPhp() === $version && ! $force) { + if ($version === $this->brew->linkedPhp() && ! $force) { output(sprintf('Valet is already using version: %s. To re-link and re-configure use the --force parameter.'.PHP_EOL, $version)); exit(); diff --git a/cli/Valet/Server.php b/cli/Valet/Server.php index 85c37ed..0436f5c 100644 --- a/cli/Valet/Server.php +++ b/cli/Valet/Server.php @@ -168,7 +168,7 @@ public function sitePath(string $siteName): ?string $dirs = []; - while (false !== ($file = readdir($handle))) { + while (($file = readdir($handle)) !== false) { if (is_dir($path.'/'.$file) && ! in_array($file, ['.', '..'])) { $dirs[] = $file; } @@ -178,12 +178,12 @@ public function sitePath(string $siteName): ?string // Note: strtolower used below because Nginx only tells us lowercase names foreach ($dirs as $dir) { - if (strtolower($dir) === $siteName) { + if ($siteName === strtolower($dir)) { // early return when exact match for linked subdomain return $path.'/'.$dir; } - if (strtolower($dir) === $domain) { + if ($domain === strtolower($dir)) { // no early return here because the foreach may still have some subdomains to process with higher priority $valetSitePath = $path.'/'.$dir; } diff --git a/cli/Valet/Site.php b/cli/Valet/Site.php index c2096f0..122610e 100644 --- a/cli/Valet/Site.php +++ b/cli/Valet/Site.php @@ -52,7 +52,7 @@ private function getLinkNameByCurrentDir(): ?string public function host(string $path): ?string { foreach ($this->files->scandir($this->sitesPath()) as $link) { - if (realpath($this->sitesPath($link)) === $path) { + if ($path === realpath($this->sitesPath($link))) { return $link; } } diff --git a/cli/app.php b/cli/app.php index 3aa416b..98252b1 100644 --- a/cli/app.php +++ b/cli/app.php @@ -10,6 +10,7 @@ use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\EventDispatcher\EventDispatcher; use Valet\Drivers\ValetDriver; + use function Valet\info; use function Valet\output; use function Valet\table; @@ -32,7 +33,7 @@ */ Container::setInstance(new Container); -$version = '4.1.4'; +$version = '4.4.0'; $app = new Application('Laravel Valet', $version); @@ -116,7 +117,7 @@ function (ConsoleCommandEvent $event) { false ); - if (false === $helper->ask($input, $output, $question)) { + if ($helper->ask($input, $output, $question) === false) { return warning('No new Valet tld was set.'); } @@ -196,12 +197,12 @@ function (ConsoleCommandEvent $event) { info('A ['.$name.'] symbolic link has been created in ['.$linkPath.'].'); if ($secure) { - $this->runCommand('secure'); + $this->runCommand('secure '.$name); } if ($isolate) { - if (Site::phpRcVersion($name)) { - $this->runCommand('isolate'); + if (Site::phpRcVersion($name, getcwd())) { + $this->runCommand('isolate --site='.$name); } else { warning('Valet could not determine which PHP version to use for this site.'); } @@ -408,7 +409,7 @@ function (ConsoleCommandEvent $event) { $helper = $this->getHelperSet()->get('question'); $question = new ConfirmationQuestion('Would you like to install Expose now? [y/N] ', false); - if (false === $helper->ask($input, $output, $question)) { + if ($helper->ask($input, $output, $question) === false) { info('Proceeding without installing Expose.'); return; @@ -424,7 +425,7 @@ function (ConsoleCommandEvent $event) { $helper = $this->getHelperSet()->get('question'); $question = new ConfirmationQuestion('Would you like to install ngrok via Homebrew now? [y/N] ', false); - if (false === $helper->ask($input, $output, $question)) { + if ($helper->ask($input, $output, $question) === false) { info('Proceeding without installing ngrok.'); return; @@ -506,7 +507,13 @@ function (ConsoleCommandEvent $event) { PhpFpm::stopRunning(); Nginx::stop(); - return info('Valet services have been stopped.'); + return info('Valet core services have been stopped. To also stop dnsmasq, run: valet stop dnsmasq'); + case 'all': + PhpFpm::stopRunning(); + Nginx::stop(); + Dnsmasq::stop(); + + return info('All Valet services have been stopped.'); case 'nginx': Nginx::stop(); @@ -515,10 +522,14 @@ function (ConsoleCommandEvent $event) { PhpFpm::stopRunning(); return info('PHP has been stopped.'); + case 'dnsmasq': + Dnsmasq::stop(); + + return info('dnsmasq has been stopped.'); } return warning(sprintf('Invalid valet service name [%s]', $service)); - })->descriptions('Stop the Valet services'); + })->descriptions('Stop the core Valet services, or all services by specifying "all".'); /** * Uninstall Valet entirely. Requires --force to actually remove; otherwise manual instructions are displayed. @@ -529,7 +540,7 @@ function (ConsoleCommandEvent $event) { $helper = $this->getHelperSet()->get('question'); $question = new ConfirmationQuestion('Are you sure you want to proceed? [y/N]', false); - if (false === $helper->ask($input, $output, $question)) { + if ($helper->ask($input, $output, $question) === false) { return warning('Uninstall aborted.'); } @@ -717,8 +728,6 @@ function (ConsoleCommandEvent $event) { $defaultLogs = [ 'php-fpm' => BREW_PREFIX.'/var/log/php-fpm.log', 'nginx' => VALET_HOME_PATH.'/Log/nginx-error.log', - 'mailhog' => BREW_PREFIX.'/var/log/mailhog.log', - 'redis' => BREW_PREFIX.'/var/log/redis.log', ]; $configLogs = data_get(Configuration::read(), 'logs'); diff --git a/composer.json b/composer.json index c72ddd3..26dcddf 100644 --- a/composer.json +++ b/composer.json @@ -34,11 +34,14 @@ "tests/Drivers/BaseDriverTestCase.php" ] }, + "conflict": { + "mnapoli/silly": ">=1.8.1 <1.8.3" + }, "require": { "php": "^7.1|^8.0", "illuminate/collections": "^8.0|^9.0|^10.0", "illuminate/container": "~5.1|^6.0|^7.0|^8.0|^9.0|^10.0", - "mnapoli/silly": "^1.0", + "mnapoli/silly": "^1.5", "symfony/console": "^3.0|^4.0|^5.0|^6.0", "symfony/process": "^3.0|^4.0|^5.0|^6.0", "guzzlehttp/guzzle": "^6.0|^7.4", diff --git a/tests/BrewTest.php b/tests/BrewTest.php index f2cbee1..51b7b78 100644 --- a/tests/BrewTest.php +++ b/tests/BrewTest.php @@ -5,6 +5,7 @@ use Valet\Brew; use Valet\CommandLine; use Valet\Filesystem; + use function Valet\resolve; use function Valet\swap; use function Valet\user; diff --git a/tests/CliTest.php b/tests/CliTest.php index 3ffe395..59ece07 100644 --- a/tests/CliTest.php +++ b/tests/CliTest.php @@ -11,9 +11,11 @@ use Valet\Ngrok; use Valet\PhpFpm; use Valet\Site as RealSite; -use function Valet\swap; use Valet\Valet; +use function Valet\resolve; +use function Valet\swap; + /** * @requires PHP >= 8.0 */ @@ -253,6 +255,70 @@ public function test_link_command_with_secure_flag_secures() $this->assertStringContainsString('site has been secured', $tester->getDisplay()); } + public function test_link_command_with_isolate_flag_isolates() + { + [$app, $tester] = $this->appAndTester(); + + $cwd = getcwd(); + $name = 'tighten'; + $host = $name.'.test'; + + $customPhpVersion = '82'; + $phpRcVersion = '8.2'; + $fullPhpVersion = 'php@8.2'; + + $brewMock = Mockery::mock(Brew::class); + $nginxMock = Mockery::mock(Nginx::class); + $siteMock = Mockery::mock(RealSite::class); + + $phpFpmMock = Mockery::mock(PhpFpm::class, [ + $brewMock, + resolve(CommandLine::class), + resolve(Filesystem::class), + resolve(RealConfiguration::class), + $siteMock, + $nginxMock, + ])->makePartial(); + + swap(Brew::class, $brewMock); + swap(Nginx::class, $nginxMock); + swap(PhpFpm::class, $phpFpmMock); + swap(RealSite::class, $siteMock); + + $brewMock->shouldReceive('supportedPhpVersions')->andReturn(collect([ + 'php@8.2', + 'php@8.1', + ])); + + $brewMock->shouldReceive('ensureInstalled')->with($fullPhpVersion, [], $phpFpmMock->taps); + $brewMock->shouldReceive('installed')->with($fullPhpVersion); + $brewMock->shouldReceive('determineAliasedVersion')->with($fullPhpVersion)->andReturn($fullPhpVersion); + + $siteMock->shouldReceive('link')->with($cwd, $name)->once(); + $siteMock->shouldReceive('getSiteUrl')->with($name)->andReturn($host); + $siteMock->shouldReceive('phpRcVersion')->with($name, $cwd)->andReturn($phpRcVersion); + $siteMock->shouldReceive('customPhpVersion')->with($host)->andReturn($customPhpVersion); + $siteMock->shouldReceive('isolate')->with($host, $fullPhpVersion); + + $phpFpmMock->shouldReceive('stopIfUnused')->with($customPhpVersion)->once(); + $phpFpmMock->shouldReceive('createConfigurationFiles')->with($fullPhpVersion)->once(); + $phpFpmMock->shouldReceive('restart')->with($fullPhpVersion)->once(); + + $nginxMock->shouldReceive('restart')->once(); + + // These should only run when doing global PHP switches + $brewMock->shouldNotReceive('stopService'); + $brewMock->shouldNotReceive('link'); + $brewMock->shouldNotReceive('unlink'); + $phpFpmMock->shouldNotReceive('stopRunning'); + $phpFpmMock->shouldNotReceive('install'); + + $tester->run(['command' => 'link', 'name' => 'tighten', '--isolate' => true]); + $tester->assertCommandIsSuccessful(); + + $this->assertStringContainsString('is now using '.$fullPhpVersion, $tester->getDisplay()); + } + public function test_links_command() { [$app, $tester] = $this->appAndTester(); @@ -776,7 +842,7 @@ public function test_stop_command() $tester->run(['command' => 'stop']); $tester->assertCommandIsSuccessful(); - $this->assertStringContainsString('Valet services have been stopped.', $tester->getDisplay()); + $this->assertStringContainsString('Valet core services have been stopped.', $tester->getDisplay()); } public function test_stop_command_stops_nginx() @@ -809,6 +875,21 @@ public function test_stop_command_stops_php() $this->assertStringContainsString('PHP has been stopped', $tester->getDisplay()); } + public function test_stop_all_command_stops_dnsmasq() + { + [$app, $tester] = $this->appAndTester(); + + $phpfpm = Mockery::mock(DnsMasq::class); + $phpfpm->shouldReceive('stop'); + + swap(DnsMasq::class, $phpfpm); + + $tester->run(['command' => 'stop', 'service' => 'dnsmasq']); + $tester->assertCommandIsSuccessful(); + + $this->assertStringContainsString('dnsmasq has been stopped', $tester->getDisplay()); + } + public function test_stop_command_handles_bad_services() { [$app, $tester] = $this->appAndTester(); diff --git a/tests/ComposerTest.php b/tests/ComposerTest.php index ad36428..808ab40 100644 --- a/tests/ComposerTest.php +++ b/tests/ComposerTest.php @@ -3,6 +3,7 @@ use Illuminate\Container\Container; use Valet\CommandLine; use Valet\Composer; + use function Valet\resolve; use function Valet\swap; use function Valet\user; diff --git a/tests/ConfigurationTest.php b/tests/ConfigurationTest.php index 187e302..34acd4d 100644 --- a/tests/ConfigurationTest.php +++ b/tests/ConfigurationTest.php @@ -4,10 +4,11 @@ use Valet\Brew; use Valet\Configuration; use Valet\Filesystem; +use Valet\Valet; + use function Valet\resolve; use function Valet\swap; use function Valet\user; -use Valet\Valet; class ConfigurationTest extends Yoast\PHPUnitPolyfills\TestCases\TestCase { diff --git a/tests/DnsMasqTest.php b/tests/DnsMasqTest.php index 5f9b581..a6c99cf 100644 --- a/tests/DnsMasqTest.php +++ b/tests/DnsMasqTest.php @@ -6,6 +6,7 @@ use Valet\Configuration; use Valet\DnsMasq; use Valet\Filesystem; + use function Valet\resolve; use function Valet\swap; use function Valet\user; diff --git a/tests/Drivers/StatamicV2ValetDriverTest.php b/tests/Drivers/StatamicV2ValetDriverTest.php new file mode 100644 index 0000000..630e6d1 --- /dev/null +++ b/tests/Drivers/StatamicV2ValetDriverTest.php @@ -0,0 +1,31 @@ +assertTrue($driver->serves($this->projectDir('statamicv2'), 'my-site', '/')); + } + + public function test_it_doesnt_serve_non_statamic_projects() + { + $driver = new StatamicV2ValetDriver(); + + $this->assertFalse($driver->serves($this->projectDir('public-with-index-non-laravel'), 'my-site', '/')); + } + + public function test_it_gets_front_controller() + { + $driver = new StatamicV2ValetDriver(); + + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['REQUEST_URI'] = '/about/'; + + $projectPath = $this->projectDir('statamicv2'); + $this->assertEquals($projectPath.'/index.php', $driver->frontControllerPath($projectPath, 'my-site', '/')); + } +} diff --git a/tests/Drivers/StatamicValetDriverTest.php b/tests/Drivers/StatamicValetDriverTest.php index ecd0eed..5d2f0ee 100644 --- a/tests/Drivers/StatamicValetDriverTest.php +++ b/tests/Drivers/StatamicValetDriverTest.php @@ -11,21 +11,38 @@ public function test_it_serves_statamic_projects() $this->assertTrue($driver->serves($this->projectDir('statamic'), 'my-site', '/')); } - public function test_it_doesnt_serve_non_statamic_projects() + public function test_it_doesnt_serve_non_statamic_projects_with_public_directory() { $driver = new StatamicValetDriver(); $this->assertFalse($driver->serves($this->projectDir('public-with-index-non-laravel'), 'my-site', '/')); } + public function test_it_doesnt_serve_laravel_projects() + { + $driver = new StatamicValetDriver(); + + $this->assertFalse($driver->serves($this->projectDir('laravel'), 'my-site', '/')); + } + public function test_it_gets_front_controller() { $driver = new StatamicValetDriver(); - $_SERVER['REQUEST_METHOD'] = 'GET'; - $_SERVER['REQUEST_URI'] = '/about/'; + $projectPath = $this->projectDir('statamic'); + $this->assertEquals($projectPath.'/public/index.php', $driver->frontControllerPath($projectPath, 'my-site', '/')); + } - $projectPath = $this->projectDir('statamicv1'); - $this->assertEquals($projectPath.'/index.php', $driver->frontControllerPath($projectPath, 'my-site', '/')); + public function test_it_serves_statically_cached_pages() + { + $driver = new StatamicValetDriver(); + + $projectPath = $this->projectDir('statamic'); + + $_SERVER['REQUEST_URI'] = '/test'; + $this->assertEquals($projectPath.'/public/static/test_.html', $driver->frontControllerPath($projectPath, 'my-site', '/test')); + + $_SERVER['REQUEST_URI'] = '/test?foo=bar&baz=qux'; + $this->assertEquals($projectPath.'/public/static/test_foo=bar&baz=qux.html', $driver->frontControllerPath($projectPath, 'my-site', '/test')); } } diff --git a/tests/Drivers/ValetDriverTest.php b/tests/Drivers/ValetDriverTest.php index 4f71bfc..74360a9 100644 --- a/tests/Drivers/ValetDriverTest.php +++ b/tests/Drivers/ValetDriverTest.php @@ -30,6 +30,15 @@ public function test_it_prioritizes_non_basic_matches() $this->assertNotEquals('Valet\Drivers\BasicValetDriver', get_class($assignedDriver)); } + public function test_it_prioritizes_statamic() + { + $assignedDriver = ValetDriver::assign($this->projectDir('statamic'), 'my-site', '/'); + $this->assertEquals('Valet\Drivers\Specific\StatamicValetDriver', get_class($assignedDriver)); + + $assignedDriver = ValetDriver::assign($this->projectDir('laravel'), 'my-site', '/'); + $this->assertEquals('Valet\Drivers\LaravelValetDriver', get_class($assignedDriver)); + } + public function test_it_checks_composer_dependencies() { $driver = new BasicValetDriver; diff --git a/tests/Drivers/projects/statamic/statamic/.gitkeep b/tests/Drivers/projects/statamic/artisan similarity index 100% rename from tests/Drivers/projects/statamic/statamic/.gitkeep rename to tests/Drivers/projects/statamic/artisan diff --git a/tests/Drivers/projects/statamic/please b/tests/Drivers/projects/statamic/please new file mode 100644 index 0000000..e69de29 diff --git a/tests/Drivers/projects/statamic/public/index.php b/tests/Drivers/projects/statamic/public/index.php new file mode 100644 index 0000000..e69de29 diff --git a/tests/Drivers/projects/statamic/public/static/test_.html b/tests/Drivers/projects/statamic/public/static/test_.html new file mode 100644 index 0000000..e69de29 diff --git a/tests/Drivers/projects/statamic/public/static/test_foo=bar&baz=qux.html b/tests/Drivers/projects/statamic/public/static/test_foo=bar&baz=qux.html new file mode 100644 index 0000000..e69de29 diff --git a/tests/Drivers/projects/statamicv2/index.php b/tests/Drivers/projects/statamicv2/index.php new file mode 100644 index 0000000..e69de29 diff --git a/tests/Drivers/projects/statamicv2/statamic/.gitkeep b/tests/Drivers/projects/statamicv2/statamic/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/NginxTest.php b/tests/NginxTest.php index 6b0141b..facf948 100644 --- a/tests/NginxTest.php +++ b/tests/NginxTest.php @@ -4,8 +4,9 @@ use Valet\Configuration; use Valet\Filesystem; use Valet\Nginx; -use function Valet\resolve; use Valet\Site; + +use function Valet\resolve; use function Valet\swap; use function Valet\user; diff --git a/tests/NgrokTest.php b/tests/NgrokTest.php index 23e61b7..7f37da6 100644 --- a/tests/NgrokTest.php +++ b/tests/NgrokTest.php @@ -2,6 +2,7 @@ use Illuminate\Container\Container; use Valet\Ngrok; + use function Valet\resolve; use function Valet\user; diff --git a/tests/PhpFpmTest.php b/tests/PhpFpmTest.php index eaea2bf..9d4e503 100644 --- a/tests/PhpFpmTest.php +++ b/tests/PhpFpmTest.php @@ -7,8 +7,9 @@ use Valet\Filesystem; use Valet\Nginx; use Valet\PhpFpm; -use function Valet\resolve; use Valet\Site; + +use function Valet\resolve; use function Valet\swap; use function Valet\user; diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 8c4b16d..55243a9 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -2,6 +2,7 @@ use Illuminate\Container\Container; use Valet\Server; + use function Valet\user; class ServerTest extends Yoast\PHPUnitPolyfills\TestCases\TestCase diff --git a/tests/SiteTest.php b/tests/SiteTest.php index cefa4ce..d941b25 100644 --- a/tests/SiteTest.php +++ b/tests/SiteTest.php @@ -5,8 +5,9 @@ use Valet\CommandLine; use Valet\Configuration; use Valet\Filesystem; -use function Valet\resolve; use Valet\Site; + +use function Valet\resolve; use function Valet\swap; use function Valet\user; diff --git a/tests/StatusTest.php b/tests/StatusTest.php index d0bfb1d..e1d196e 100644 --- a/tests/StatusTest.php +++ b/tests/StatusTest.php @@ -2,8 +2,9 @@ use Illuminate\Container\Container; use Valet\CommandLine; -use function Valet\resolve; use Valet\Status; + +use function Valet\resolve; use function Valet\swap; use function Valet\user;