Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ All notable changes of the PHP Mode 1.19.1 release series are documented in this

## Unreleased

### Added

* `php-project-get-root-dir` falls back to `project-current` when no PHP-specific marker is found, so `project.el` backends (Projectile 3, `project-vc-extra-root-markers`, etc.) can contribute project detection

### Changed

* Add `readonly` class modifier to [Imenu] ([#802])
* Add `enum` support to `php-current-class` ([#802])
* Remove hardcoding of implicit paths in `php` that are not guaranteed to exist ([#803])

### Fixed

* `php-project-project-find-function` now returns a `project.el` value valid on Emacs 28+; it previously built a `(vc . ROOT)` cons that broke the 3-element `(vc BACKEND ROOT)` representation and made `project-root` signal an error

### Deprecated

* `php-project-use-projectile-to-detect-root` is obsolete; Projectile 3 registers itself on `project-find-functions`, which `php-project-get-root-dir` now consults automatically

[Imenu]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Imenu.html
[#802]: https://github.com/emacs-php/php-mode/pull/802
[#803]: https://github.com/emacs-php/php-mode/pull/803
Expand Down
18 changes: 18 additions & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,24 @@ M-x package-install php-mode
(php-project-coding-style . psr2)))
```

### `project.el`・Projectileとの連携

`php-project-get-root-dir`は、まずPHP固有のマーカー(`.projectile`、`composer.json`/`composer.lock`、続いてVCSディレクトリ)を探索します。モノレポではパッケージ単位の`vendor/autoload.php`やコーディングスタイルが`php-mode`にとって重要なため、VCSルートより`composer.json`を優先します。これらのマーカーが見つからない場合は`project-current`にフォールバックするので、任意の[`project.el`](https://www.gnu.org/software/emacs/manual/html_node/emacs/Projects.html)バックエンドが検出に寄与できます。

* **Projectile 3**は`projectile-mode`有効時に自身を`project-find-functions`へ登録するため、その検出結果が自動的に利用されます。従来の`php-project-use-projectile-to-detect-root`オプションはこのため廃止予定です。
* Projectileなしでも`project-vc-extra-root-markers`(Emacs 29以降)で追加のルートマーカーを宣言できます。例えば`.dir-locals.el`に次のように記述します。

```lisp
((nil
(project-vc-extra-root-markers . ("composer.json"))))
```

逆に、PHP固有の検出(上記の`composer.json`優先ルール)をEglotや`project-find-file`などの`project.el`利用側に見せたい場合は、組み込みのVC検出を補完するだけになるよう、低い優先度で`php-project-project-find-function`を登録します。

```lisp
(add-hook 'project-find-functions #'php-project-project-find-function 90)
```

## HTMLとPHPが混在するファイルの編集

`php-mode`は純粋なPHPスクリプトのためのメジャーモードです。テンプレートのようにHTMLの中にPHPを埋め込んだファイルは、両方の言語を理解するメジャーモードで編集するほうが適しています。特にインデントは、HTML部分を素の`php-mode`で編集すると正しく動作しません。
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,24 @@ You can add project-specific settings by creating a `.dir-locals.el` or `.dir-lo
(php-project-coding-style . psr2)))
```

### Integration with `project.el` and Projectile

`php-project-get-root-dir` first looks for a PHP-specific marker (`.projectile`, `composer.json`/`composer.lock`, then a VCS directory). Preferring `composer.json` over the VCS root matters in monorepos, where per-package `vendor/autoload.php` and coding styles are what `php-mode` cares about. When none of those markers is found, it now falls back to `project-current`, so any [`project.el`](https://www.gnu.org/software/emacs/manual/html_node/emacs/Projects.html) backend can contribute detection:

* **Projectile 3** registers itself on `project-find-functions` when `projectile-mode` is enabled, so its detection is picked up automatically. The old `php-project-use-projectile-to-detect-root` option is therefore obsolete.
* **Extra root markers** can be declared without Projectile via `project-vc-extra-root-markers` (Emacs 29+), for example in `.dir-locals.el`:

```lisp
((nil
(project-vc-extra-root-markers . ("composer.json"))))
```

Conversely, to expose PHP-specific detection (the `composer.json`-first precedence above) to `project.el` consumers such as Eglot or `project-find-file`, register `php-project-project-find-function` with a low priority so it only supplements the built-in VC detection:

```lisp
(add-hook 'project-find-functions #'php-project-project-find-function 90)
```

## Editing files that mix HTML and PHP

`php-mode` is designed for pure PHP scripts. Files that embed PHP inside HTML, such as templates, are better edited in a major mode that understands both languages. Indentation in particular is unreliable when the HTML part of a file is edited in plain `php-mode`.
Expand Down
57 changes: 48 additions & 9 deletions lisp/php-project.el
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@
(eval-when-compile
(require 'cl-lib))
(require 'php-core)
(require 'projectile nil t)
(require 'project)
;; Projectile is optional and only used at runtime through `fboundp' guards.
;; `projectile-mode' being active already implies the library is loaded, so we
;; deliberately avoid pulling in the whole of Projectile just by requiring us.

;; Constants
(defconst php-project-composer-autoloader "vendor/autoload.php")
Expand All @@ -77,9 +80,18 @@
:type 'boolean)

(defcustom php-project-use-projectile-to-detect-root nil
"If `T' and projectile-mode is activated, use Projectile for root detection."
"If `T' and projectile-mode is activated, use Projectile for root detection.

This option predates Projectile 3, which registers itself on
`project-find-functions'. `php-project-get-root-dir' now falls back to
`project-current' when no PHP marker is found, so Projectile (and any other
`project.el' backend) is consulted automatically. Prefer that path instead."
:tag "PHP Project Use Projectile To Detect Root"
:type 'boolean)
(make-obsolete-variable 'php-project-use-projectile-to-detect-root
"rely on `project-find-functions'; \
`php-project-get-root-dir' falls back to `project-current' automatically."
"1.28.0")

;; Variables
(defvar php-project-available-root-files
Expand Down Expand Up @@ -260,14 +272,24 @@ Typically it is `pear', `drupal', `wordpress', `symfony2' and `psr2'.")

;;;###autoload
(defun php-project-project-find-function (dir)
"Return path to current PHP project from DIR.
"Return the PHP project containing DIR.

This function is compatible with `project-find-functions'. Register it with a
low priority so that it only supplements the built-in detection, for example:

(add-hook \\='project-find-functions #\\='php-project-project-find-function 90)

This function is compatible with `project-find-functions'."
When the detected root is under version control the result is delegated to
`project-try-vc', which yields the representation expected by the running
Emacs (a plain \\='(vc . ROOT) cons is only valid on Emacs 27 and breaks the
3-element \\='(vc BACKEND ROOT) form used since Emacs 28). Otherwise a
`transient' project rooted at the PHP project directory is returned."
(let ((default-directory dir))
(when-let* ((root (php-project-get-root-dir)))
(if (file-exists-p (expand-file-name ".git" root))
(cons 'vc root)
(cons 'transient root)))))
(or (and (file-exists-p (expand-file-name ".git" root))
(fboundp 'project-try-vc)
(project-try-vc root))
(cons 'transient root)))))

(defun php-project--detect-root-dir ()
"Return detected project root."
Expand All @@ -282,8 +304,25 @@ This function is compatible with `project-find-functions'."
(cl-loop for m in php-project-available-root-files
append (cdr m)))
(t (cdr-safe (assq php-project-root php-project-available-root-files))))))
(cl-loop for m in detect-method
thereis (locate-dominating-file default-directory m)))))
(or (cl-loop for m in detect-method
thereis (locate-dominating-file default-directory m))
(php-project--detect-root-by-project-el)))))

(defun php-project--detect-root-by-project-el ()
"Return the root reported by `project.el', or nil.

Used as a last resort when no PHP-specific marker is found. This lets
`project.el' backends contribute their own detection, including Projectile 3
\(which registers itself on `project-find-functions') and
`project-vc-extra-root-markers'. `php-project-project-find-function' is
temporarily removed from the hook to avoid recursing back into this function."
;; `project-root' only exists on Emacs 28.1+; on Emacs 27 there is no
;; non-obsolete accessor, so the fallback simply does nothing there.
(when (fboundp 'project-root)
(let ((project-find-functions
(remq #'php-project-project-find-function project-find-functions)))
(when-let* ((project (project-current)))
(project-root project)))))

(provide 'php-project)
;;; php-project.el ends here
Loading