From d8ab4bc35fef6ea2698eaad28cbadb940cb479c7 Mon Sep 17 00:00:00 2001 From: Shanto Date: Sun, 2 Nov 2025 13:46:17 +0600 Subject: [PATCH 1/2] Add support for Docker based PHP Environmet Support for Docker based PHP environment configurable with config keys: { "Laravel.dockerService": "php", // from `docker compose config --services` "Laravel.dockerBase": "/app", // from `docker compose exec {dockerService} pwd` } This plugin does not auto boot Docker container(s) although it can be implemented in later revisions. For now, ensure that Docker container is running with configured dockerService name and dockerBase path as working directory before attempting to use the plugin with Docker support. --- package.json | 15 ++++++++++++++- src/support/config.ts | 2 ++ src/support/php.ts | 12 +++++++++++- src/support/phpEnvironments.ts | 7 +++++++ src/support/project.ts | 10 +++++++++- 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 3948a51d..2d6f9f02 100644 --- a/package.json +++ b/package.json @@ -232,6 +232,7 @@ "sail", "lando", "ddev", + "docker", "local" ], "enumItemLabels": [ @@ -241,6 +242,7 @@ "Sail", "Lando", "DDEV", + "Docker", "Local" ], "markdownEnumDescriptions": [ @@ -250,6 +252,7 @@ "Sail", "Lando", "DDEV", + "Docker", "Use PHP installed on the local machine." ], "default": "auto", @@ -259,6 +262,16 @@ "type": "string", "description": "Template for running PHP code. Use {code} as an optional placeholder for the php file to run. e.g. `php \"{code}\"`.\n\nIf no {code} is present, code filepath will be appended to the command." }, + "Laravel.dockerService": { + "type": "string", + "default": "php", + "description": "Name of the Docker service container holding PHP executable and Laravel app source code." + }, + "Laravel.dockerBase": { + "type": "string", + "default": "/app", + "description": "Base path of the Laravel app source code inside Docker container." + }, "Laravel.basePath": { "type": "string", "default": "", @@ -674,4 +687,4 @@ "vscode-languageserver-textdocument": "^1.0.11", "vscode-languageserver-types": "^3.17.5" } -} +} \ No newline at end of file diff --git a/src/support/config.ts b/src/support/config.ts index 1b2dc3e3..3b796812 100644 --- a/src/support/config.ts +++ b/src/support/config.ts @@ -6,6 +6,8 @@ type ConfigKey = | "basePath" | "phpEnvironment" | "phpCommand" + | "dockerService" + | "dockerBase" | "tests.docker.enabled" | "tests.ssh.enabled" | "tests.suiteSuffix" diff --git a/src/support/php.ts b/src/support/php.ts index 72002dca..91508348 100644 --- a/src/support/php.ts +++ b/src/support/php.ts @@ -1,6 +1,7 @@ import { getTemplate, TemplateName } from "@src/templates"; import * as cp from "child_process"; import * as fs from "fs"; +import { sep as pathsep } from "path"; import * as vscode from "vscode"; import { BoundedFileCache } from "./cache"; import { config } from "./config"; @@ -110,6 +111,15 @@ const getPhpCommand = (): string => { let check = checks.shift(); let result = ""; + if (key === "docker") { + const dockerService = config("dockerService", "php"); + check = check?.replace("{dockerService}", dockerService); + option.command = option.command.replace( + "{dockerService}", + dockerService, + ); + } + while (check) { info(`Checking ${key} PHP installation: ${check}`); @@ -251,7 +261,7 @@ export const runInLaravel = ( export const fixFilePath = (path: string) => { if (phpEnvironmentsThatUseRelativePaths.includes(phpEnvKey!)) { - return relativePath(path); + return relativePath(path).replaceAll(pathsep, "/"); } return path; diff --git a/src/support/phpEnvironments.ts b/src/support/phpEnvironments.ts index f88fb7d1..b6905785 100644 --- a/src/support/phpEnvironments.ts +++ b/src/support/phpEnvironments.ts @@ -14,6 +14,7 @@ export type PhpEnvironment = | "sail" | "lando" | "ddev" + | "docker" | "local"; export const phpEnvironments: Record = { @@ -52,6 +53,12 @@ export const phpEnvironments: Record = { command: "ddev php", relativePath: true, }, + docker: { + label: "Docker", + check: "docker compose exec {dockerService} which php", + command: 'docker compose exec {dockerService} "{binaryPath}"', + relativePath: true, + }, local: { label: "Local", description: "Use PHP installed on the local machine.", diff --git a/src/support/project.ts b/src/support/project.ts index 8ff0e30a..30f76163 100644 --- a/src/support/project.ts +++ b/src/support/project.ts @@ -2,7 +2,7 @@ import * as fs from "fs"; import * as path from "path"; import * as vscode from "vscode"; import { config } from "./config"; -import { isPhpEnv } from "./php"; +import { getPhpEnv, isPhpEnv } from "./php"; let internalVendorExists: boolean | null = null; @@ -35,6 +35,14 @@ export const pathForPhpEnv = (srcPath: string): string => { return srcPath.replace(new RegExp("^/var/www/html/"), ""); } + if (srcPath.match(/^\//) && getPhpEnv() === "docker") { + const dockerBase = config("dockerBase", "/app").replace( + /\/$/, + "", + ); + return projectPath(srcPath.replace(new RegExp(`^${dockerBase}/?`), "")); + } + return srcPath; }; From 1f279e1615232a2ffe50ec8c06e32e67a47eb06e Mon Sep 17 00:00:00 2001 From: Shanto Date: Tue, 4 Nov 2025 16:18:52 +0600 Subject: [PATCH 2/2] Execute pint inside active PHP environment, e.g. when not in local --- src/commands/pint.ts | 14 +++++++++++--- src/support/php.ts | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/commands/pint.ts b/src/commands/pint.ts index d36f40a0..a571a43d 100644 --- a/src/commands/pint.ts +++ b/src/commands/pint.ts @@ -1,4 +1,4 @@ -import { fixFilePath } from "@src/support/php"; +import { fixFilePath, getPhpCommand, getPhpEnv } from "@src/support/php"; import { statusBarError, statusBarSuccess, @@ -12,6 +12,7 @@ import { showErrorPopup } from "../support/popup"; import { getWorkspaceFolders, projectPath, + pathForPhpEnv, projectPathExists, } from "../support/project"; @@ -27,7 +28,8 @@ const runPintCommand = ( ): Promise => { return new Promise((resolve, reject) => { // Check if pint exists in vendor/bin - const pintPath = projectPath("vendor/bin/pint"); + const pintBin = "vendor/bin/pint"; + const pintPath = projectPath(pintBin); if (!projectPathExists("vendor/bin/pint")) { const errorMessage = @@ -37,7 +39,13 @@ const runPintCommand = ( return; } - const command = `"${pintPath}" ${args}`.trim(); + let command = `"${pintPath}" ${args}`.trim(); + + if (getPhpEnv() !== "local") { + const phpcmd = getPhpCommand(); + const pintInEnv = pathForPhpEnv("vendor/bin/pint"); + command = `${phpcmd} "${pintInEnv}" ${args}`.trim(); + } cp.exec( command, diff --git a/src/support/php.ts b/src/support/php.ts index 91508348..c8282702 100644 --- a/src/support/php.ts +++ b/src/support/php.ts @@ -92,7 +92,7 @@ export const initVendorWatchers = () => { registerWatcher(autoloadWatcher); }; -const getPhpCommand = (): string => { +export const getPhpCommand = (): string => { const phpEnv = config("phpEnvironment", "auto"); for (const [key, option] of Object.entries(phpEnvironments)) {