Injecting PHP in HTML in PHP files

Answered

Is it possible to inject using plugin full feature PHP with all inspections and error reporting (and not InjectablePHP) inside <php>echo $a;</php> tag like in example code below using the same context as the first classic php block <?php $a = 1; ?>:

<?php $a = 1; ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<php>echo $a;</php>
</body>
</html>

Is it possible using MultiHostInjector/MultiHostRegistrar ? Or will I have to implement separate template language like php blade templates?

Or do I have to use some preprocessing like explained here? :

https://intellij-support.jetbrains.com/hc/en-us/community/posts/360009710039-support-for-include-file-ext-directive?page=1#community_comment_360002275160

1
11 comments

Hi yoskaldyr ! This is indeed possible, however it won't be exactly the same quality in terms of user experience than using regular <?php …… ?> tags


If you still want to proceed with <php></php> tags, then something like this will work:

package test;

import com.intellij.lang.injection.MultiHostInjector;
import com.intellij.lang.injection.MultiHostRegistrar;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.impl.source.xml.XmlTextImpl;
import com.jetbrains.php.lang.PhpLanguage;
import org.jetbrains.annotations.NotNull;

import java.util.List;

public class PhpExampleInjector implements MultiHostInjector {
  @Override
  public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
    if (context.getParent() instanceof HtmlTag tag && tag.getName().equals("php")) {
      registrar.startInjecting(PhpLanguage.INSTANCE);
      registrar.addPlace("<?php ", " ?>", ((XmlTextImpl)context), TextRange.create(0, context.getTextLength() - 1));
      registrar.doneInjecting();
    }
  }

  @Override
  public @NotNull List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
    return List.of(XmlTextImpl.class);
  }
}

1

Thank you!

Will this injection be similar to injectablePhp created in Language Injection settings (no inspections/auto complete and errors checks) or more like some preprocessor explained in link in the first post. Will it be the same php visibility context?

Correctly I want to get more like some preprocessor (that internally  expands some macros in html to the full php), not language injection

P.S. I will check you example today

0

It will have some autocomplete and some inspections:

1

perfect! Thank you!

0

Just checked this example above. And yes autocomplete and inspections are working, but only with local scope of the contents of each  `<php>` tag, because it has own visibility/context and separate visibility from classic `<?php ?>` sections. 

Is it possible to do a one visibility scope of variables/classes/etc between all tags and classic php sections?

0

It is not possible out of the box. resolve/autocomplete/inspections should work fine with definitions from other files, but probably will struggle within one file. You could try to hack over those things that don't work :)

As you can see – type inference works properly and injection sees definitions from testing1. Only inspection shows red code, probably some other corner cases don't work as expected too:

0

I created addon with only 1 extension with extension class provided by you. And variables from classic php block `<?php ?>` aren't visible in `<php>` tags

Is it possible that your tests hack visibility scope of injected languages? 

Also maybe is it better to do this on lexer level as explained here ?

https://intellij-support.jetbrains.com/hc/en-us/community/posts/360009710039-support-for-include-file-ext-directive?page=1#community_comment_360002275160

I need some kind of preprocessor with macros, written in pure html

0

Oh, ok, I see. This is the limitation of injected fragments right now. But you can extend existing facilities through respective APIs (extension points)

-1

“existing facilities” is too abstract :(

What classes do I have to extend?

Because I can find a lot of examples how to use MultiHostInjector, I can find examples how to extend lexer or parser.

But I haven't seen any examples for removing such limitations. 

0

Please sign in to leave a comment.