The syntax highlighting feature it's essential for every programming blog or project where there's some code to share with someone else. Due to simplicity, developers use JavaScript libraries to highlight code on the browser of the client without any kind of problem or stress. But sometimes, you may want a work-everywhere solution where even with JavaScript disabled, you will get an awesome syntax highlight effect.
In this article, we are going to show you how to highlight code on the server side without any kind of command line tool but just plain PHP in your Symfony 3 project.
Requirements
To highlight code in the server side with pure PHP (without needing pygments or other command line tools), we recommend you to use the Highlight.php library. highlight.php is a server side code highlighter written in PHP that currently supports over 135 languages. It's a port of highlight.js by Ivan Sagalaev written by Geert Bergman that makes full use of the language and style definitions of the original JavaScript project.
Important note
In our opinion, this library is very underrated, so please don't forget to show your support to the developer by Starring the project on Github, thanks !
To install this library in your Symfony 3 project, run the following command in your terminal (once located in the directory of your project):
composer require scrivo/highlight.php
After the installation, you will be able to use the Highlighter class of the library in your Symfony 3 project. Visit the official repository of the library at Github for more information.
A. From a controller into view
The first way to achieve it, is through the straightforward process controller-view:
1. Prepare highlight ready markup in your controller
The library works as follow: create an instance of the highlighter class, use the highlight method to create the markup ready to highlight on the view. The highlight method expects as first argument the identifier of the programming language to highlight and as second argument the code that will be highlighted.
In your controller, you'll need to include the Highlighter class on the top of your controller and follow the previous mentioned process. Note that in the following example we are sending the ready to highlight markup to a Twig view:
Note
The EOF is obviously not required. It's just an example of a string that contains some code to highlight.
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
// Include the Highlighter class
use Highlight\Highlighter;
class DefaultController extends Controller
{
/**
* @Route("/", name="homepage")
*/
public function indexAction()
{
// Create a new instance of Highlighter
$highlighter = new Highlighter();
// Define the language that you want to use to highlight
$language = "javascript";
/**
* Some example code to highlight in JavaScript
*/
$code = <<<EOF
var DebugLibExample = {
toggleDebug = function(s) {
_f.debug = s ? !!s.debug : false;
},
logger = function(msg, type) {
if (_f.debug) {
type = type || 'log';
var logAction = {
'error': function(m) {
console.error('Chameleon.js:', m);
},
'warn': function(m) {
console.warn('Chameleon.js:', m);
},
'log': function(m) {
console.log('Chameleon.js:', m);
}
};
if (typeof msg === 'undefined') {
logAction.error('Msg given to logger is undefined!');
} else {
if (logAction.hasOwnProperty(type)) {
logAction[type](msg);
} else {
logAction.error(['Unknown logAction type!', type]);
}
}
}
}
};
EOF;
// Create the markup with styles ready to highlight in the view
// as first argument the language type and as second the code
$markupHighlightedCodeObject = $highlighter->highlight($language, $code);
// Send the markup with styles to some twig view that you want
// In this case the parameter "code" contains our code in the twig view
return $this->render("default/index.html.twig", [
"code" => $markupHighlightedCodeObject
]);
}
}
As you can see, it sends a parameter namely code
to the following Twig view. This value will be used in the Twig view of the following step.
2. Render and style markup on Twig View
This view will render the Markup following the guidelines of Highlight.js (code
tag with class hljs <lang>
inside a pre
tag). The code parameter accesible in twig due to our controller is an object that contains 2 properties namely language and value that contains the used language to highlight the code on the server and the generated code respectively.
It's important to see that once you render the ready to highlight markup in the view, you need to use the raw filter of twig. The raw filter marks the value as being "safe", which means that in an environment with automatic escaping enabled this variable will not be escaped (generated HTML will be really HTML instead of HTML entities).
Note
Remember that the markup generated by PHP doesn't contain any styles, only markup that can be highlighted with CSS in the view, so don't forget to include (or create) any of the highlight themes of Highligh.js in the Twig view. As shown in the following example, we are using the CSS Atelier Heath Dark theme from the CDN to test it:
{# default/index.html.twig #}
{% extends "base.html.twig" %}
{% block body -%}
{#
Insert Highlight.js styles from CDN
or your own local css file
#}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atelier-heath-dark.min.css" />
{#
Render the pre element with the code tag inside and respective classes.
Note: don't forget to use the raw filter
#}
<pre>
<code class="hljs {{code.language}}">{{code.value|raw}}</code>
</pre>
{% endblock %}
As result in the view, our highlighted code will look like:
Awesome isn't? and you didn't need JavaScript to get the same result for your code.
B. Inside a Twig view using a filter
If you want to make it in the Symfony way, you can create a Twig filter for this to highligh the code directly on the Twig views, so you only would need to do in your views:
{{ "alert('Hello World');console.log('Some demo code');"|highlightCode("javascript")|raw }}
And you code would be automatically highlighted on your views without messing up your controllers !
1. Create Twig Extension
The first you need to do is to create an extension that simplifies all the logic created in the controller of the previous option. This extension creates the new twig filter highlightCode
, that expects as first argument the language (and obviously the variable with the code to apply the filter) that will be used to highlight:
<?php
// The namespace according to the bundle and the path
namespace AppBundle\Extensions;
// Include the highlighter class
use Highlight\Highlighter;
class TwigExtensions extends \Twig_Extension
{
protected $highlighter;
public function getFilters()
{
return array(
new \Twig_SimpleFilter('highlightCode', array($this, 'highlightCode')),
);
}
public function __construct(){
$this->highlighter = new Highlighter();
}
public function highlightCode($code, $language){
// Create highlight object
$result = $this->highlighter->highlight($language, $code);
// Return ready to render markup
return "<pre>"
."<code class=\"hljs {$result->language}\">{$result->value}</code>"
."</pre>";
}
public function getName()
{
return 'TwigExtensions';
}
}
Then proceed to register the custom Twig extension on your services.yml
file of Symfony:
services:
twig.extension:
# the namespace with the name of the Twig Extensions created class
class: AppBundle\Extensions\TwigExtensions
tags:
- { name: twig.extension }
And then you will be able to use the filter easily on your views. Note that it's very basic, so you can improve it to load automatically the CSS file instead of adding it later manually on the view.
To understand how the filter works, we are going to send some plain C++ code (text format) from the controller to the Twig view and it will be highlighted:
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
/**
* @Route("/", name="homepage")
*/
public function indexAction()
{
/**
* Some example code to highlight in JavaScript
*/
$plainCode = <<<EOF
#include <random>
#include <vector>
int main()
{
std::vector<int> v = {10, 15, 20, 25, 30};
std::random_device random_device;
std::mt19937 engine{random_device()};
std::uniform_int_distribution<int> dist(0, v.size() - 1);
int random_element = v[dist(engine)];
}
EOF;
// Send the markup with styles to some twig view that you want
// In this case the parameter "code" contains our code in the twig view
return $this->render("default/index.html.twig", [
"plainCode" => $plainCode
]);
}
}
As you can see, it's plain text, so you can use it in the same way when you retrieve data from your database etc.
2. Use filter in the view to highlight
Now in your Twig view, you would use the highlightCode
filter as follows to highlight your code:
{# default/index.html.twig #}
{% extends "base.html.twig" %}
{% block body -%}
{#
Insert Highlight.js styles from CDN
or your own local css file
#}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/monokai.min.css" />
{#
Use the highlightCode filter with C++ language
Note: use raw filter to print Pure HTML
#}
{{ plainCode|highlightCode("cpp")|raw }}
{# Which outputs:
<pre><code class="hljs cpp">.. The Code Here..</code></pre>
#}
{% endblock %}
Note that you need to include the CSS too in the view, but as previously mentioned you can modify the Twig filter to include automatically the CSS file. In this case we have made it manually to help you understand how the highlight process works. It's important too that you use the raw filter of twig to escape the generated HTML (which in this case is safe to do), otherwise plain text will appear on your views. The previous view will generate the following output:
Remember that there are more than 135 languages supported, so take a look at the supported languages on the project here.
Happy coding !