Matthias NobackDefining a custom filter and sorter for Sculpin content types (11.12.2019, 15:30 UTC)

This blog runs on Sculpin, a static site generator. The generator itself runs on Symfony, which for me makes it easy to extend. However, I find that if you want something special, it can usually be done, but it may take several hours to get it right. In the end though, the solution is often quite elegant.

A custom content type for events

One custom feature I wanted for this website was a list of events (conference talks, trainings, etc.). Sculpin's documentation suggests using a custom content type for that. This allows you to create a directory with files, each of which will be considered an "event". Setting up a custom content type is usually quite easy:

# in app/config/sculpin_kernel.yml

sculpin_content_types:
    events:
        permalink: event/:year/:month/:slug_title

The default configuration values that Sculpin calculates for this setup are good in this case (it will look in source/_events/ for the HTML or Markdown files describing the events; it will look for the _layouts/event.html file for the layout of each event's page, etc.). However, I wasn't interested in how "detail" pages were generated for each event; I just wanted a list of all events. The HTML for the events page would have to look something like this:

---
layout: default
title: Events
use: [events] # load the collection of "events"
---

<h2>Events</h2>

{% for event in data.events %}
    {{ event.content|raw }}
{% endfor %}

A sample event file would look something like this (front matter first, allowing some meta-data to be provided, then the content of the page):

# in source/_events/php-benelux-2020-workshop-decoupling-from-infrastructure.html

---
title: Decoupling from infrastructure
date: 2020-01-24
---

<p>Most application code freely mixes domain logic [...]</p>

This, again, just works great out-of-the-box.

Custom sorting

But now I wanted to change the sort order for the events. The default sorting is on date, descending. This doesn't feel like a natural ordering for upcoming events, which would show events far in the future first.

I didn't find a way to configure the sorting of events in app/config/sculpin_kernel.yml, so I looked at the source code of the SculpinContentTypesExtension class. I found out that the easiest thing to manually configure sorting would be to override the sorter service that Sculpin automatically defines for every content type:

services:

  # This sorter overrides the one Sculpin automatically configures for "events"
  sculpin_content_types.types.events.collection.sorter:
    class: Sculpin\Contrib\ProxySourceCollection\Sorter\MetaSorter
    arguments:
      - 'date'
      - 'desc' # I don't know why but "desc" works (I expected "asc")

The MetaSorter ships with Sculpin. I figured out the name of the service by reading through the code in SculpinContentTypesExtension. As you can see, I provide 'desc' as the second argument, even though I would expect the correct value to be 'asc'; 'desc' had the desired effect of showing the earliest events first.

Creating two filtered collections: upcoming and past events

I then realised it would be useful to have a list of upcoming events, sorted by date, ascending, and a list of past events, sorted by date, descending (oldest last). Upon regenerating the site, past events should automatically move to the list of past events. I figured I'd have to define two content types now: upcoming_events and past_events. These collections should both load the files in source/_events/, so the resulting configuration looks like this:

# in app/config/sculpin_kernel.yml

sculpin_content_types:
    upcoming_events:
        permalink: event/:year/:month/:slug_title
        path: event/
        layout: event
    past_events:
        permalink: event/:year/:month/:slug_title
        path: event/ # same path as "upcoming_events"
        layout: event

Which events end up in which collection should be determined by some kind of filter based on the current timestamp. Again, it turned out that Sculpin already has a built-in type for defining filters (FilterInterface), but it doesn't provide easy ways of setting it up for your custom content types.

The way I did it was write a compiler pass that modified Sculpin's own filter service definitio

Truncated by Planet PHP, read more at the original (another 4397 bytes)

Link
Voices of the ElePHPantInterview with Francesca Marano (10.12.2019, 12:30 UTC) Link
Derick RethansXdebug Update: November 2019 (10.12.2019, 09:17 UTC)

Xdebug Update: November 2019

Another month, another monthly update where I explain what happened with Xdebug development in this past month. It will be published on the first Tuesday after the 5th of each month. Patreon supporters will get it earlier, on the first of each month. You can become a patron here to support my work on Xdebug. If you are leading a team or company, then it is also possible to support Xdebug through a subscription.

In November, I worked on Xdebug for about 30 hours, on the following things:

Website Redesign

Matt Brown contacted me a few months ago, suggesting that I should consider cleaning up the design and content of Xdebug's website. He spend countless hours both redoing my atrocious (and old!) code that powers the website, and creating a new design for it. During November we put this new design online, and I upgraded the server to run PHP 7.4 too. There are still a few rough edges, and there are a few thins I still want to improve, but I believe that the new design (and code!) are much cleaner. Thanks Matt!

Xdebug 3 development

I only spent a little time on Xdebug 3 this month, mostly due to travel to speak at conferences. I did finished the modularizing of the Xdebug code base, and now have moved on to cleaning code up and refactoring it even more to continue to make it more maintainable.

Beyond that, I have started to remove a few things from Xdebug as well. I removed the aggregated profiler feature, which was never documented, and prepared an uncommitted patch to remove the xdebug.remote_handler setting. This setting could only ever have one value (dbgp), and it seems very unlikely that in the future Xdebug will support other debugging protocols. The underlying code for being able to have more protocols continues to exist. This is mainly because it enforces better design and less coupling between the different parts of Xdebug.

Xdebug 2.8.1 Release

I was right to think last month that it would be likely to have to make a bug fix release. A user commented on Twitter that the code coverage functionality was drastically slower. In Xdebug 2.8 I changed how the coverage functionality remembers which classes and their methods it had already analysed. In 2.7 and earlier, it sets a specific flag on the class entry, but that was always a hack, which stopped working (again) with PHP 7.4. Instead of using that flag, I now use a hash table to do so.

However, I had inadvertently negated the check, so instead of only analysing classes and their methods on the first visit, Xdebug ended up analysing it every single time. The fix for this was therefore small (and embarrassing).

During the testing of this new "fix", I noticed that code coverage was still a lot slower than in Xdebug 2.7.2, so I did some more research to improve this. Instead of allocating memory to create the hash key, I use stack memory instead.

For Xdebug 3 I have a few further ideas to speed up code coverage.

The bug fix for the performance degradation is the only ticket that made it into Xdebug 2.8.1.

Update: Xdebug 2.8.1 was released on December 2nd (so not actually in November).

Business Supporter Scheme and Funding

I have had further, but minimal, interest for the Business Supporter Scheme that I launched in September.

This month's new supporter is

Truncated by Planet PHP, read more at the original (another 1396 bytes)

Link
Derick RethansCrafty Code Coverage (9.12.2019, 13:30 UTC)

Crafty Code Coverage

Xdebug's code coverage functionality has had dead code analysis for years. It is used to be able to mark lines of as having executable code on it, as well as lines which can not be reached. In order to provide this functionality it runs an algorithm code after each file has been compiled. For each class and function it checks whether the algorithm to analyse executable lines and dead code has already been run, as it makes no sense to check it for the same class, method, or function twice.

Until PHP 7.4, Xdebug stored this information on whether it has seen a class with a special flag on the class entry of a class, PHP's internal structure that contains all the information the engine needs to be able to instantiate objects and run methods.

PHP 7.4 changes the values of these flags, which prompted me to ask Nikita whether it was actually safe to use a flag like this as a marker of whether Xdebug has already analysed that class (and its methods). He said no and suggested that instead I should use a hash table to store this information instead. I implemented that for Xdebug 2.8, that was released just before PHP 7.4 came out.

Soon after PHP 7.4 came out, I received a bug report that code coverage was now now significantly slower. A specific run went from 8 minutes to more than 3.5 hours. I tried this out for myself with the test suite of the Document package of Zeta Components, and indeed, with PHP 7.3 and Xdebug 2.7.2 it took about 2.83 minutes, and with PHP 7.3 and Xdebug 2.8.0 46 minutes — a slow down of about 16 times.

I quickly discovered that I had forgotten a ! in the code, which meant that the analyses would run for every class after a new file was loaded/compiled. I fixed that in Xdebug 2.8.1. This did improve the code coverage timings, but it still took 22.26 minutes, instead of the original 8 minutes.

I started talking to twitter user Anthony to try out a few more speed improvements, and although we were making improvements, I was not getting anywhere near the original timings of Xdebug 2.7. At this point I referred back to Nikita to ask whether he had a good idea to improve on this. He mentioned that classes and functions are always added to the end of the class/function tables, and that they are never removed either. He also hinted at a method to only loop over the newly added classes and functions after each PHP file was compiled: loop over the table backwards up to the point where the size of the list was the previous time that we looped. This resulted in a patch that did exactly that. Xdebug now longer needs the hash table mechanism to check whether we have analysed classes with their methods, and functions already, and also no longer loops over the whole list of classes after each file. As most people use one class per file, the algorithm went from O(n²) to O(n) approximately.

This cut down the time to run the test suite with code coverage for the Document package to 1.21 minutes. About 2½ times faster as Xdebug 2.7 and earlier. Anthony was also pleased and surprised:

Although I tend to make an Xdebug release only once a month, in this case I thought it warranted to expedite this. So here is your end-of-year present: Xdebug 2.9.

⛄ ❄️ ✨

Become a Patron!
Link
Matthew Weier O'PhinneyMore Changes Coming for the Laminas Project (5.12.2019, 16:45 UTC)

Progress has been happening at a furious pace on the Zend Framework to Laminas transition, with major changes still dropping even now.

Most recently, we decided to rename the subprojects. Apigility will become the Laminas API Tools, and Expressive will become Mezzio.

For more background, read the Zend by Perforce blog post.

mwopMore Changes Coming for the Laminas Project was originally published on https://mwop.net by .
Link
Voices of the ElePHPantInterview with Chris Hartjes (4.12.2019, 12:34 UTC)
Link
Voices of the ElePHPantInterview with Chris Hartjes (3.12.2019, 18:03 UTC)
Link
Remi ColletInstall PHP 7.4 on CentOS, RHEL or Fedora (3.12.2019, 15:26 UTC)

Here is a quick howto upgrade default PHP version provided on Fedora, RHEL or CentOS with latest version 7.4.

 

Repositories configuration:

On Fedora, standards repositories are enough, on Enterprise Linux (RHEL, CentOS) the Extra Packages for Enterprise Linux (EPEL) repository must be configured, and on RHEL the optional channel must be enabled.

Fedora 31

dnf install https://rpms.remirepo.net/fedora/remi-release-31.rpm

Fedora 30

dnf install https://rpms.remirepo.net/fedora/remi-release-30.rpm

RHEL version 8.1

dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm

RHEL version 7.7

wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
wget https://rpms.remirepo.net/enterprise/remi-release-7.rpm
rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm
subscription-manager repos --enable=rhel-7-server-optional-rpms

CentOS version 8.0

dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm

CentOS version 7.7

wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
wget https://rpms.remirepo.net/enterprise/remi-release-7.rpm
rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm

 

php module usage

With Fedora modular and RHEL / CentOS 8, you can simply use the remi-7.4 stream of the php module

dnf module reset php
dnf module install php:remi-7.4

 

remi-php74 repository activation

Needed packages are in the remi-safe (enabled by default) and remi-php74 repositories, the latest is not enabled by default (administrator choice according to the desired PHP version).

RHEL or CentOS 7

yum install yum-utils
yum-config-manager --enable remi-php74

Fedora

dnf config-manager --set-enabled remi-php74

 

PHP upgrade

By choice, the packages have the same name than in the distribution, so a simple update is enough:

yum update

That's all :)

$ php -v
PHP 7.4.0 (cli) (built: Nov 26 2019 20:13:36) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.0, Copyright (c), by Zend Technologies

 

Known issues

The upgrade can fail (by design) when some installed extensions are not yet compatible with  PHP 7.4.

See the compatibility tracking list: PECL extensions RPM status

If these extensions are not mandatory, you can remove them before the upgrade, else, you will have to be patient.

Warning: some extensions are still under development, but it seems useful to provide them to allow upgrade to more people, and to allow user to give feedback to the authors.

 

More d'information

If you prefer to install PHP 7.4 beside default PHP version, this can be achieved using the php74 prefixed packages, see the PHP 7.4 as Software Collection post.

You can also try the configuration wizard.

The packages available in the repository was used as source for Fedora 32 (self contained change proposal, is already accepted and testable).

By providing a full feature PHP stack, with about 130 available extensions, 6 PHP versions, as base and SCL packages, for Fedora and Enterprise Linux, and with 200 000 download per day, remi repository became in the last 14 years a reference for PHP users on RPM based distributions, maintained by an active contributor to the projects (Fedora, PHP, PECL...).

See also:

Truncated by Planet PHP, read more at the original (another 845 bytes)

Link
Voices of the ElePHPantInterview with Gabriela D’Ávila Ferrara (3.12.2019, 12:30 UTC) Link
Voices of the ElePHPantInterview with Shawn Mayzes (1.12.2019, 13:01 UTC)
Link
LinksRSS 0.92   RDF 1.
Atom Feed   100% Popoon
PHP5 powered   PEAR
ButtonsPlanet PHP   Planet PHP
Planet PHP