emGee Software Solutions Custom Database Applications

Share this

Drupal CMS

Droptica: 13 lectures and presentations worth seeing at DrupalEurope 2018

Drupal.org aggregator - Sun, 08/26/2018 - 22:33
DrupalEurope is this year’s largest European conference devoted to Drupal. In previous years, each edition of the conference (formerly known as DrupalCon) was attended by about 2000 participants. We already know the programme of the conference with 162 hours of lectures over the course of three days! I decided to go through the programme and make a list of 13 lectures that I think are worth seeing. 1. Driesnote On Wednesday, 12th of September at 9:00 a.m. Dries Buytaert will talk about the status of Drupal 8. This is a lecture I always attend at DrupalCon. You can learn interesting things about Drupal usage statistics and the system development plans. It's definitely worth attending if you want to know what will happen with Drupal in the coming months.
Categories: Drupal CMS

ActiveLAMP: Deploying Docker containers - Introduction to Kubernetes

Drupal.org aggregator - Sun, 08/26/2018 - 18:44

We are going to take the Drupal image that I created from my last post “Creating a deployable Docker image with Jenkins” and deploy it. You can find the image that we created last time up on Docker Hub, that is where we pushed the image last time. You have several options on how to deploy Docker images to production, whether that be manually, using a service like AWS ECS, or OpenShift, etc… Today, I’m going to walk you through a deployment process using Kubernetes also known as simply k8s.

Read more...
Categories: Drupal CMS

Hook 42: August Accessibility (A11Y) Talks - A11Y Meetups, Camps, and Beyond

Drupal.org aggregator - Sun, 08/26/2018 - 11:26

Dennis Deacon has been involved in digital accessibility for the past four years, most recently as an Accessibility Engineer with The Paciello Group. He’s led the Chicago Digital Accessibility & Inclusive Design Meetup since December 2014. He is organizing Chicago's first Accessibility Camp later this year. And, he leads the curation of the 24 Accessibility article series.

Dennis Deacon spoke about starting the Chicago Digital Accessibility and Inclusive Design Meetup. He spoke about digital accessibility but focused on delivering the most accessible events possible.

Categories: Drupal CMS

Zhilevan Blog: Drupal Global Services, How to use global services in Drupal 8

Drupal.org aggregator - Sat, 08/25/2018 - 10:08
One of the significant improvements of Drupal 8 that got me excited was the services & dependency-injection throughout the entire Drupal system. From aspects like routing, templating, managing configuration, querying and persisting data, you name it everything is done with services. it's fantastic because it grants developers a level of flexibility in extending Drupal that is far greater than what Drupal 7 was able to. by using well-disposed structure developers get ride of ravioli coding.
Categories: Drupal CMS

Ashday's Digital Ecosystem and Development Tips: Drupal Module Spotlight: Reroute Email

Drupal.org aggregator - Fri, 08/24/2018 - 14:00
 

“Excuse me, Mr./Mrs. Client, I’m so sorry but I accidentally just sent your 3000 users a fake purchase email receipt when I was testing.”

Ugh.

Big complex systems are a lot to keep track of, especially when it comes to email. There are emails for resetting passwords, emails for new users, email receipts, email notifications for workflows, etc, and it’s frankly a little terrifying to rely on yourself to remember all the implications of what’s going on when working on local environments, or test servers or anywhere but production. All you have to do to experience this pain is trigger an accidental FAKE email send to REAL people. 

That’s where modules like today’s spotlight comes in. 

Categories: Drupal CMS

OPTASY: 10 Drupal SEO Mistakes You Do Not Want to Make on Your Website: From Least to Most Harmful- Part 1

Drupal.org aggregator - Fri, 08/24/2018 - 10:17
10 Drupal SEO Mistakes You Do Not Want to Make on Your Website: From Least to Most Harmful- Part 1 adriana.cacoveanu Fri, 08/24/2018 - 17:17

You have made, are currently making and will continue to make various Drupal SEO mistakes. From those easy to overlook gaffes to (truly) dumb neglects, to critical mistakes severely impacting your site's ranking... 

Just face it and... fix it! 

And what better way of becoming aware of their impact on your site than by... getting them exposed, right? By bringing them into the spotlight...

Therefore, here are the 10 SEO mistakes you really don't want to make on your website: the “culprits” for your site's poor ranking.

Take note of them, assess their occurrence/risks for your Drupal site's SEO and strive to avoid them:
 

1. Overlooking or Misusing Header Tags

Do it for the crawlers or do it for your site visitors.

Categories: Drupal CMS

OpenSense Labs: A Tryst With Drupal And Virtual Reality

Drupal.org aggregator - Fri, 08/24/2018 - 05:41
A Tryst With Drupal And Virtual Reality Shankar Fri, 08/24/2018 - 18:11

Ever felt so intrigued by the movie that you were watching in a cinema hall and were completely immersed in it? Not only sometimes it can make you reminisce about instances from your own life but let you identify yourself with the characters in the film. You can start feeling like you are part of the film only to realise in the end it was just a film after all. Immersive experiences can happen in a spectacularly made film. To take the immersive experience to the next level, virtual reality is the answer.

Categories: Drupal CMS

Eelke Blok: Quick tip: generating a site hash for Drupal 8

Drupal.org aggregator - Fri, 08/24/2018 - 04:39

Drupal 8 will actively complain when your site does not have a hash_salt configured, which usually gets generated when installing the site. (The complaint, mind you, might be fairly obscure; your site might just say "The website encountered an unexpected error. Please try again later." Depending on your error reporting settings, the message might be a bit more helpful). If, for example, you "install" a site by copying over a database and files, you will not have this.

Categories: Drupal CMS

OPTASY: What Are Some Good Ways to Write Secure Drupal Code? Most Common Vulnerabilities and Secure Coding Practices

Drupal.org aggregator - Fri, 08/24/2018 - 01:44
What Are Some Good Ways to Write Secure Drupal Code? Most Common Vulnerabilities and Secure Coding Practices radu.simileanu Fri, 08/24/2018 - 08:44

With the Drupalgeddon2 "trauma" still “haunting” us all — both Drupal developers and Drupal end-users — we've convinced ourselves that prevention is, indeed, (way) better than recovery. And, after we've put together, here on this blog, a basic security checklist for Drupal websites and revealed to you the 10 post-hack “emergency” steps to take, we've decided to dig a bit deeper.

Categories: Drupal CMS

OpenSense Labs: How NLP & Drupal Can Be Combined To Provide The Best User Experience

Drupal.org aggregator - Thu, 08/23/2018 - 19:51
How NLP & Drupal Can Be Combined To Provide The Best User Experience Akshita Fri, 08/24/2018 - 08:21 Knowledge and reasoning have enabled machines to beat even humans while bringing new power to the web.

Inspired by complex human autonomy, Artificial Intelligence (AI) is the perfect mix of science and art. The application of machine learning has advanced to an extent that it can read, understand, analyze and process the language. Siri, Cortana, Echo, and the Google Assistant are all great examples.

Categories: Drupal CMS

OSTraining: 5 New Features You'll See in Drupal 8.6

Drupal.org aggregator - Thu, 08/23/2018 - 10:41

Every six months, Drupal releases a new version.

Drupal 8.6 is not ready yet and is scheduled for release on September 5.

However, we already know what features will be in the final version. A Release Candidate is now available and at this point, the core is frozen and no new features will be added. 

So, now is a great time to dive in and discover what new features we'll see. Some of these features are outstanding!

Categories: Drupal CMS

Palantir: The MIT Press

Drupal.org aggregator - Thu, 08/23/2018 - 08:26
The MIT Press brandt Thu, 08/23/2018 - 10:26

How we developed a Drupal 8 site and integrated with a custom API for the MIT Press to showcase their collection.

mitpress.mit.edu Providing Readers New Ways to Discover Timeless Works of Literature On

The MIT Press is known for publishing works that showcase iconic design, rigorous scholarship, and creative technology. Their collection represents a strong heritage of art, science, and technology, which is displayed by their catalog of over 8,000 unique, significant works by pioneering authors including Noam Chomsky, Paul Krugman, and Patricia Churchland. The Press advances knowledge by publishing work that serves a global audience, and they have been committed to this effort for almost 60 years.

In late 2016, change was afoot at the Press. The marketing team was energized by the addition of a new director to their lineup, their website was long overdue for a modernization, and they had recently partnered with a design agency (Pentagram) to begin a brand overhaul.

And so they began their search for a seasoned agency to undertake their website redesign process. Enter Palantir.

The Key Results
  • Prototyping a semantic HTML framework for a responsive, mobile-first experience.
  • Developing a Drupal 8 website that provides the MIT Press with marketing tools for the promotion of their catalog.
  • Integrating MIT’s book data services into the Drupal site, so that editors can leverage existing tools along with those required for web publishing.
  • Supporting an e-commerce experience that provides the best user experience for customers.
The Challenge

The former MIT Press website was a Drupal 6 instance last designed in 2012, and aside from having an outdated technical stack, it suffered in overall user experience. The new site needed to make it easy for visitors to peruse the Press’ catalog of beautiful books with amazing covers. It needed to offer new and exciting ways to present content and enhance the search experience. Most importantly, it needed to continue driving that pursuit of knowledge that the Press endeavored to promote when they set-up shop in 1962.

Creating a Living Style Guide

We were fortunate to work with Pentagram, a design partner who authentically showcased the MIT Press’ refreshed brand identity. They provided a brand guide that we were able to adapt beautifully for the web. Palantir’s design implementation process began on a foundation of static compositions that we received from Pentagram.

Our design team expanded on these comps to build out a living style guide that addresses web accessibility standards and documents responsive content layouts, all while maintaining the integrity and feel of the original designs.

The Ability to Market Their Collection

Mitpress.mit.edu is intended to be the canonical source for all information relating to MIT Press’ published works. At the forefront of their team’s minds was one important question: how do we make it easier for readers to find the titles they are looking for, and ultimately, start curating their own collection of books?

Palantir addressed this need by building out a suite of marketing tools that the MIT Press publishing team had never before had. These tools allowed them to create new kinds of content to showcase information about the collection in new, visually exciting ways.

The MIT Press team can now create book landing pages, self-managed static pages, campaign landing pages and custom microsites.

Custom API Integration

MIT Press’ internal database already housed a record of all of their books, including information like when a title was published, cover image files, and more. Because it was already part of their workflow as a publishing house, MIT Press needed to continue maintaining book information using that specific system.

The main challenge they faced was how to pull all of that book data in from their publishing system and expose it on the new website. Their previous workflow involved exporting a large file from the publishing database and then importing that data into the website, but this produced challenges as there was no control over editorial workflow or how information appeared on the site. It also meant updates to titles on the site only happened when they had time to import massive files to their site.

After migrating the site to Drupal 8, Palantir integrated custom Drupal entities with MIT Press’ custom API which provides all of their book data. Nearly all of the information about books and contributors comes from the MIT Press API, even related book titles. The MIT Press marketing team can now use information pulled in through the API to spin up the landing pages and other content that help showcase their collection.

The API integration between the internal publishing system and the Drupal website allows MIT Press content authors to continue using their existing editorial workflows, which frees up precious time for their team to concentrate on higher level strategic objectives.

We have quite a few different audience types, and Palantir has helped make the website accessible to all of them. They made sure the pathways are clear and prominent, making them easier to navigate, which will hopefully lead to higher conversions and more books being purchased.

Sara Fleming

Consultant

The End Result

Having a streamlined user interface has been the biggest win for the Press. Many of the titles they publish are ones that are considered timeless references in the fields of architecture, design, science, and technology, and the new site not only puts those works in context but also makes it easier for visitors to discover new ones as well.  

This project was recognized in the 2018 Webby Awards as an Official Honoree in the category of Corporate Communications Websites.

Categories: Drupal CMS

Web Wash: Drupal CLI: Drush and Drupal Console

Drupal.org aggregator - Thu, 08/23/2018 - 06:30

Drupal Console and Drush are two command line (CLI) tools built for Drupal. For a long time Drush was the only CLI tool and it was very useful for managing Drupal sites. Common tasks you’d do with Drush are rebuild caching, installing sites, import/export configuration and so much more.

Then Drupal Console came onto the scene and offered other goodies such as the ability to generate boilerplate code, which Drush 9 can now do as well. People often ask "Can you run Drush and Drupal Console together" and the answer is yes, I personally use both. If you install Drupal using drupal-composer/drupal-project then you get both Drush and Drupal

In the video above, you'll learn how to use Drush and Drupal Console.

Categories: Drupal CMS

Issue 353

TheWeeklyDrop - Thu, 08/23/2018 - 01:47
Issue 353 - August, 23rd 2018

I'm fresh back from the Decoupled Drupal Days conference in New York. It was a great event of which I was honored to be a co-organizer and speaker. I hope to highlight some of the sessions in next week's issue. They were all recorded. Though I didn't get to see very many of them, I've heard many positive comments. On to the links.

~ Bob

Categories: Drupal CMS

Drupal Europe: The Inspiration of our Blockchain Panel:

Drupal.org aggregator - Thu, 08/23/2018 - 01:38
Image by LuckyStep @shutterstock
  • to revolutionize publishing, with a new rewarding model in an environment which can build trust and allows community governance.
  • to reshape open source communities, with a better engagement and rewarding system.
  • to free digital identity, thus killing the need of middlemen at the protocol layer.

Blockchain is an universal tool and can be applied in many different areas.

Communities, like the Drupal Community, can find new ways to flourish. Even larger and risky projects can be financed in new ways, with ICO (Initial Coin Offer). Taco Potze (Co-Founder Open Social) has a 10 year Drupal background and is an expert on Communities. He is working on blockchain technology to build a better engagement and rewarding systems for communities. Wouldn’t that be really nice for us?

See also Taco’s session: ICOs, a revolutionary way to raise money for your company

Publishing and its classic monetization model is challenged. Intermediates are about to disrupt the relationship between authors and publishers and their readers. This is based on a troublesome business model, with massive tracking and profile building, to turn our engagement in advertisement money. At the same time poor content and fake news has become a threat to our society. Gagik Yeghiazarian (CEO, Co-Founder Publiq) is looking for new ways to address these problems, with a non profit, distributed media platform based on blockchain.

See also Gagik’s session: Blockchain Distributed Media — A Future for good publishing

The Internet is broken and blockchain can fix it. The biggest promise with blockchain is to make middlemen obsolete, by creating trusted identities in an open protocol. This is to break the monopoly of the middlemen and to retain a free web. We recognize aribnb, amazon, ebay, netflix, itunes as middlemen. We understand, when we by or book, they get their share. With Google, Facebook and YouTube there are some other huge monopoly middlemen, they get their share based on our attention and personal data. They know how to transfer our attention into dollars, by selling it to advertisers. Ingo Rübe (CEO Bot Lab) is working on a protocol, which will allow people to gain control of their digital identity. It will be called KILT Protocol. (Ingo is well known in the Drupal Community and a Member of Drupal’s Advisory Board. As a former CTO of Burda he was the Initiator of the Drupal Thunder Distribution)

Our Panel will be moderated by Audra Martin Merrick, a board member of Drupal Association.

signed
Drupal Europe
Your Track Chairs

Categories: Drupal CMS

Appnovation Technologies: How Software Requirements Affect Each Stage of a Project

Drupal.org aggregator - Thu, 08/23/2018 - 00:00
How Software Requirements Affect Each Stage of a Project By: Michael Cooper, Appnovation Frontend Dev  When it comes to completing large software projects, one of the most important factors in achieving success is to lay the requirements out clearly. Unfortunately, this is a lot easier said than done. This article will outline a few of the ways that requirements affect development...
Categories: Drupal CMS

Early Rendering: A Lesson in Debugging Drupal 8

Lullabot - Wed, 08/22/2018 - 17:55

I came across the following error the other day on a client's Drupal 8 website:

LogicException: The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early.

Leaked? That sounded bad. Rendering content too early? I didn't know what that meant, but it also sounded bad. Worst of all, this was causing a PHP fatal error along with a 500 response code. Fortunately, I caught the error during development, so there was time to figure out exactly what was going on. In so doing, I learned some things that can deepen our understanding of Drupal’s cache API.

Down the rabbit hole

I knew that this error was being caused by our code. We were writing a custom RestResource plugin, which is supposed to fetch some data from the entity API and return that data, ready to be serialized and complete with cacheability metadata. This custom RestResource was the only route that would trigger the error, and it only started happening part way through development as the codebase grew complex. It had been working fine, until the error noted above, which I include here in full with a stack trace:

The website encountered an unexpected error. Please try again later. LogicException: The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\rest\ResourceResponse. in Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (line 154 of core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php). Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 135) Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 57) Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57) Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 119) Drupal\cdn\StackMiddleware\DuplicateContentPreventionMiddleware->handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 50) Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23) Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 663) Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

I was confused that our code didn't appear in the stack trace; this is all Drupal core code. We need to go deeper.

As I do when this kind of situation arises, I took to the debugger. I set a breakpoint at the place in core where the exception was being thrown looking for clues. Here were my immediate surroundings:

// ... elseif ($response instanceof AttachmentsInterface || $response instanceof CacheableResponseInterface || $response instanceof CacheableDependencyInterface) { throw new \LogicException(sprintf('The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: %s.', get_class($response))); } // ...

Foreign land. Knowing a smidgen about the Cache API in Drupal 8 and the context of what we were trying to do, I understood that we were ending up here in part because we were returning a response object that has cacheability metadata on it. That is, we were returning a ResourceResponse object that implements CacheableResponseInterface, including the relevant cacheability metadata with it. I could see from Xdebug that the $response variable in the snippet above corresponded to the ResourceResponse object we were returning, and it was packed with our data object and ready to be serialized. 

undefined

So as far as I knew, I was playing nice and adding cacheability metadata like a good Drupal developer should. What gives?

Seeing the forest for the trees

It was at this point I felt myself getting lost in the weeds. I needed to take a step back and reread the error message. When I did, I realized that I didn't understand what “early rendering” was.

I knew it had some connection to caching, so I started by reading through all the Cache API docs on drupal.org. I’ve read these several times in the past, but it’s just one of those topics, at least for me, that requires constant reinforcement. Another relevant doc I found was CachebleResponseInterface. These provided a good background and laid out some terminology for me, but nothing here talks about early rendering. I also reviewed the Render API docs but again, no mention of early rendering, and nothing getting me closer to a resolution.

So then I zoomed back in a little bit, to the parent class of the code which threw the error: \Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber

As is often the case in Drupal 8 core code, there was an excellent and descriptive doc block for the class. I often find this to be key to understanding Drupal 8. Core committers take great care to document the code they write which makes it worth getting comfortable with reading through core and contrib code.

When controllers call drupal_render() (RendererInterface::render()) outside of a render context, we call that "early rendering." Controllers should return only render arrays, but we cannot prevent controllers from doing early rendering. The problem with early rendering is that the bubbleable metadata (cacheability & attachments) are lost.

At last a definition for early rendering! However, our code wasn't (at least directly) inside a controller, it never called drupal_render() that I could tell, and what in the world is a render context?

Nobody to blame

Still, in need of some context for understanding what was going on here, I looked at git blame to find out where the code that was throwing the error about early rendering came from. Ever since I started to do Drupal 8 development, I’ve always found it useful to use a clone of Drupal locally for such occasions. PHPStorm makes using git blame quite easy. In the file you’re interested in—opened in the editor—just right click the line numbers column and click Annotate. Once the annotations display, click the one that corresponds to the line that you’re interested in to see the commit message. 

undefined

Most, if not all, Drupal core commits will have an issue number in the description, in this case, here is what I found:

Issue #2450993 by Wim Leers, Fabianx, Crell, dawehner, effulgentsia: Rendered Cache Metadata created during the main controller request gets lost

Loading up the issue, I’m faced with a wall of text, 159 comments. Although I did eventually wade through it out of morbid curiosity, what I immediately do when faced with a giant closed core issue, is check for a change record. The Drupal 8 dev cycle has been really excellent about documenting changes, and change records have really helped in the transition from earlier Drupal 7 concepts and explaining new concepts in Drupal 8. For any core issue, first, take a look in the right sidebar of the issue for “Change records for this issue”, and follow any that are linked to get a birds-eye view of the change. If you haven’t already, it’s also handy to bookmark the Change records for Drupal core listing as it's a great place to look when you're stuck on something Drupal 8.

undefined

The change record was very helpful, so if you’re interested, I recommend you definitely give it a read. In short, early rendering used to be rampant (in core and contrib), and this was a problem because cacheability metadata was lost. The change introduced a way to wrap all controllers, detect early rendering, catch and merge the cacheability metadata into the controllers' return (usually a render array). That’s all well and good, but wait! You might think, "If it’s handling the cacheabillity metadata from early rendering, why is it still throwing an error!?" Well, going back to the snippet where the exception is thrown from earlier:

// ... elseif ($response instanceof AttachmentsInterface || $response instanceof CacheableResponseInterface || $response instanceof CacheableDependencyInterface) { throw new \LogicException(sprintf('The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: %s.', get_class($response))); } // ...

What this boils down to is if your controller is returning a response object of type, AttachementsInterfaceCacheableResponseInterface, or CacheableDependencyInterface, Drupal does not give you a pass, nor does it handle cacheability metadata from early rendering for you. Drupal takes the position that since you are returning this type of response, you should also be responsible, be aware of and handle early rendering yourself. From the change log:

Since you're returning responses, you want to fully control what is sent, so you should also be a responsible citizen and not do any early rendering. I solemnly swear not to early render

Ok, so no early rendering, got it. But, what if it’s out of our control? In our case, the code we were working in didn't have any direct calls to drupal_render() (RendererInterface::render()). My next tactic was to understand more about what was triggering early rendering. 

To do this, I set a breakpoint in the sole implementation of RendererInterface::render() and then hit the REST endpoint that was triggering the error. Xdebug immediately broke at that line, and inspecting the stack trace, we saw some of our code! Proof that we broke it! Progress. 

undefined

As it turns out, some code in another custom module was being called. This code is meant to wrap entity queries, massaging the return data into something more palpable and concise for the development team that wrote it. Deep in this code, in processing node entities, it was including a call to $node→url(), where $node is a \Drupal\node\Entity\Node object. Turns out, that triggers early rendering. To this, you might ask, "Why would something as innocuous as getting the URL for a node trigger early rendering?" The answer, and I’m only 80% sure after studying this for a while (do correct me if I’m wrong), is that URLs can vary by context based on language or the site URL. They can also have dependencies, such as the language configuration. Finally, URLs can have CSRF tokens embedded in them, which vary by session. All of which is important cacheability metadata that you want to be included in the response. OK, so what’s a responsible Drupal developer to do?

The complete (and verbose) solution, courtesy of ohthehugemanatee (indeed), is to replace your $node→url() call with something like:

// 1. Confusing: the method is called toString, yet passing TRUE for the first param nets you a \Drupal\Core\GeneratedUrl object. $url = $node->toUrl()->toString(TRUE); // 2. The generated URL string, as before. $url_string = $url->getGeneratedUrl(); // Add the $url object as a dependency of whatever you're returning. Maybe a response? $response = new CacheableResponse($url_string, Response::HTTP_OK); $response->addCacheableDependency($url); return $response;

That’s a lot, and it’ll be different depending on what you're doing. It’s broken down into 3 parts. First, you want to call $node->toUrl()->toString(TRUE);. This will essentially tell Drupal to track any cacheability metadata, which is part of generating the URL, and return an object from which you can get that cacheability metadata so you can deal with it. The second part is just getting the actual URL string, $url_string = $url->getGeneratedUrl();, to do with as you please. Finally, you need to account for any encountered cacheability metadata. In the context of a response as above, that means adding the $url object as a cacheable dependency. In the context of a render array, it might mean merging the $url cacheability metadata into the render array. (eg. CacheableMetadata::createFromObject($url)→applyTo($render_array))

Wrap it up

OK so now I understood where the exception was coming from and why. I also understand how I might change the code that is triggering an early rendering. But as I mentioned before, what if you don’t control the code that is triggering an early rendering? Is all hope lost? Not quite. What you can do is wrap the code triggering the early render in a render context. Let’s look at some code:

$context = new RenderContext(); /* @var \Drupal\Core\Cache\CacheableDependencyInterface $result */ $result = \Drupal::service('renderer')->executeInRenderContext($context, function() { // do_things() triggers the code that we don't don't control that in turn triggers early rendering. return do_things(); }); // Handle any bubbled cacheability metadata. if (!$context->isEmpty()) { $bubbleable_metadata = $context->pop(); BubbleableMetadata::createFromObject($result) ->merge($bubbleable_metadata); }

Let’s break this down:

$context = new RenderContext();

Here, I instantiate a new render context. A render context is a stack containing bubbleable rendering metadata. It’s a mechanism for collecting cacheability metadata recursively, aggregating or “bubbling” it all up. By creating and passing it in the next line, the render context is able to capture what would have otherwise been lost cacheability metadata.

/* @var \Drupal\Core\Cache\CacheableDependencyInterface $result */ $result = \Drupal::service('renderer')->executeInRenderContext($context, function() { // do_things() triggers the code that we don't don't control that in turn triggers early rendering. return do_things(); });

Here I run some arbitrary code within the render context I created. The arbitrary code, somewhere along its execution path that we have no control over, triggers early rendering. When that early rendering occurs, since I’m wrapping the code in a render context, the cacheability metadata will bubble up to the render context I setup and allow me to do something with it.

// Handle any bubbled cacheability metadata. if (!$context->isEmpty()) { $bubbleable_metadata = $context->pop(); BubbleableMetadata::createFromObject($result) ->merge($bubbleable_metadata); }

Now I check if the context is non-empty. In other words, did it catch some cacheability metadata from something that did early rendering? If it did, I get the captured cacheability metadata with $context→pop() and merge it with my \Drupal\Core\Cache\CacheableDependencyInterface object which will be returned. BubbleableMetadata is a helper class for dealing with cacheability metadata. This merge part may look different depending on your context, but the idea is to incorporate it into the response somehow. Take a look at the static methods in \Drupal\Core\Render\BubbleableMetadata  and its parent class for\Drupal\Core\Cache\CacheableMetadata some helpers to merge your cacheability metadata.

Really wrapping up

That was a heavy, long, complex debug session. I learned a lot digging into it and I hope you did as well. Let me know in the comments if you’ve ever run into something similar and came to a resolution in a different way. I’d love to continue furthering my understanding.

While it was great to figure this out, I was left wanting a better DX. In particular, improving the fact that Drupal auto-magically handles early rendering in some cases, but not others. There is also the odd workaround to capture cacheability metadata when cacheability metadata when calling $node→url() that could use some work. A quick search on the issue queue told me I wasn’t alone. Hopefully, with time and consideration, this can be made better. Certainly, there are good reasons for the complexity, but it would be great to balance that against the DX to avoid more epic debug sessions.

Acknowledgements
Categories: Drupal CMS

Oliver Davies: Examples of using Laravel Collections in Drupal

Drupal.org aggregator - Wed, 08/22/2018 - 17:00

Since starting to work with Laravel as well as Drupal and Symfony, watching Adam Wathan’s Refactoring to Collections course as well as lessons on Laracasts, I’ve become a fan of Laravel’s Illuminate Collections and the object-orientated pipeline approach for interacting with PHP arrays.

In fact I’ve given a talk on using Collections outside Laravel and have written a Collection class module for Drupal 7.

I’ve also tweeted several examples of code that I’ve written within Drupal that use Collections, and I thought it would be good to collate them all here for reference.

Categories: Drupal CMS

Agiledrop.com Blog: AGILEDROP: Top Drupal blog posts from July 2018

Drupal.org aggregator - Wed, 08/22/2018 - 16:25
Each month, we revisit out top Drupal blog posts of the month, giving you the chance to check out some of our favourites. Here’s a look at the top blog posts from July 2018.    First one on the list is Kevin Thull's unique contribution to Drupal by Dries Buytaert. Kevin Thull has contributed to Drupal a lot by recording hundreds and hundreds of sessions on different Drupal events and share them with us over Youtube. This blog post and the 2018 Aaron Winborn Award are a big thank you for all the effort.    We continue our list with Decoupled Back Ends in the Age of Brand Consistency by… READ MORE
Categories: Drupal CMS

Lullabot: Early Rendering: A Lesson in Debugging Drupal 8

Drupal.org aggregator - Wed, 08/22/2018 - 10:54

I came across the following error the other day on a client's Drupal 8 website:

LogicException: The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early.

Leaked? That sounded bad. Rendering content too early? I didn't know what that meant, but it also sounded bad. Worst of all, this was causing a PHP fatal error along with a 500 response code. Fortunately, I caught the error during development, so there was time to figure out exactly what was going on. In so doing, I learned some things that can deepen our understanding of Drupal’s cache API.

Down the rabbit hole

I knew that this error was being caused by our code. We were writing a custom RestResource plugin, which is supposed to fetch some data from the entity API and return that data, ready to be serialized and complete with cacheability metadata. This custom RestResource was the only route that would trigger the error, and it only started happening part way through development as the codebase grew complex. It had been working fine, until the error noted above, which I include here in full with a stack trace:

The website encountered an unexpected error. Please try again later. LogicException: The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\rest\ResourceResponse. in Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (line 154 of core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php). Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 135) Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 57) Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57) Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 119) Drupal\cdn\StackMiddleware\DuplicateContentPreventionMiddleware->handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 50) Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23) Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 663) Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

I was confused that our code didn't appear in the stack trace; this is all Drupal core code. We need to go deeper.

As I do when this kind of situation arises, I took to the debugger. I set a breakpoint at the place in core where the exception was being thrown looking for clues. Here were my immediate surroundings:

// ... elseif ($response instanceof AttachmentsInterface || $response instanceof CacheableResponseInterface || $response instanceof CacheableDependencyInterface) { throw new \LogicException(sprintf('The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: %s.', get_class($response))); } // ...

Foreign land. Knowing a smidgen about the Cache API in Drupal 8 and the context of what we were trying to do, I understood that we were ending up here in part because we were returning a response object that has cacheability metadata on it. That is, we were returning a ResourceResponse object that implements CacheableResponseInterface, including the relevant cacheability metadata with it. I could see from Xdebug that the $response variable in the snippet above corresponded to the ResourceResponse object we were returning, and it was packed with our data object and ready to be serialized. 

undefined

So as far as I knew, I was playing nice and adding cacheability metadata like a good Drupal developer should. What gives?

Seeing the forest for the trees

It was at this point I felt myself getting lost in the weeds. I needed to take a step back and reread the error message. When I did, I realized that I didn't understand what “early rendering” was.

I knew it had some connection to caching, so I started by reading through all the Cache API docs on drupal.org. I’ve read these several times in the past, but it’s just one of those topics, at least for me, that requires constant reinforcement. Another relevant doc I found was CachebleResponseInterface. These provided a good background and laid out some terminology for me, but nothing here talks about early rendering. I also reviewed the Render API docs but again, no mention of early rendering, and nothing getting me closer to a resolution.

So then I zoomed back in a little bit, to the parent class of the code which threw the error: \Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber

As is often the case in Drupal 8 core code, there was an excellent and descriptive doc block for the class. I often find this to be key to understanding Drupal 8. Core committers take great care to document the code they write which makes it worth getting comfortable with reading through core and contrib code.

When controllers call drupal_render() (RendererInterface::render()) outside of a render context, we call that "early rendering." Controllers should return only render arrays, but we cannot prevent controllers from doing early rendering. The problem with early rendering is that the bubbleable metadata (cacheability & attachments) are lost.

At last a definition for early rendering! However, our code wasn't (at least directly) inside a controller, it never called drupal_render() that I could tell, and what in the world is a render context?

Nobody to blame

Still, in need of some context for understanding what was going on here, I looked at git blame to find out where the code that was throwing the error about early rendering came from. Ever since I started to do Drupal 8 development, I’ve always found it useful to use a clone of Drupal locally for such occasions. PHPStorm makes using git blame quite easy. In the file you’re interested in—opened in the editor—just right click the line numbers column and click Annotate. Once the annotations display, click the one that corresponds to the line that you’re interested in to see the commit message. 

undefined

Most, if not all, Drupal core commits will have an issue number in the description, in this case, here is what I found:

Issue #2450993 by Wim Leers, Fabianx, Crell, dawehner, effulgentsia: Rendered Cache Metadata created during the main controller request gets lost

Loading up the issue, I’m faced with a wall of text, 159 comments. Although I did eventually wade through it out of morbid curiosity, what I immediately do when faced with a giant closed core issue, is check for a change record. The Drupal 8 dev cycle has been really excellent about documenting changes, and change records have really helped in the transition from earlier Drupal 7 concepts and explaining new concepts in Drupal 8. For any core issue, first, take a look in the right sidebar of the issue for “Change records for this issue”, and follow any that are linked to get a birds-eye view of the change. If you haven’t already, it’s also handy to bookmark the Change records for Drupal core listing as it's a great place to look when you're stuck on something Drupal 8.

undefined

The change record was very helpful, so if you’re interested, I recommend you definitely give it a read. In short, early rendering used to be rampant (in core and contrib), and this was a problem because cacheability metadata was lost. The change introduced a way to wrap all controllers, detect early rendering, catch and merge the cacheability metadata into the controllers' return (usually a render array). That’s all well and good, but wait! You might think, "If it’s handling the cacheabillity metadata from early rendering, why is it still throwing an error!?" Well, going back to the snippet where the exception is thrown from earlier:

// ... elseif ($response instanceof AttachmentsInterface || $response instanceof CacheableResponseInterface || $response instanceof CacheableDependencyInterface) { throw new \LogicException(sprintf('The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: %s.', get_class($response))); } // ...

What this boils down to is if your controller is returning a response object of type, AttachementsInterfaceCacheableResponseInterface, or CacheableDependencyInterface, Drupal does not give you a pass, nor does it handle cacheability metadata from early rendering for you. Drupal takes the position that since you are returning this type of response, you should also be responsible, be aware of and handle early rendering yourself. From the change log:

Since you're returning responses, you want to fully control what is sent, so you should also be a responsible citizen and not do any early rendering. I solemnly swear not to early render

Ok, so no early rendering, got it. But, what if it’s out of our control? In our case, the code we were working in didn't have any direct calls to drupal_render() (RendererInterface::render()). My next tactic was to understand more about what was triggering early rendering. 

To do this, I set a breakpoint in the sole implementation of RendererInterface::render() and then hit the REST endpoint that was triggering the error. Xdebug immediately broke at that line, and inspecting the stack trace, we saw some of our code! Proof that we broke it! Progress. 

undefined

As it turns out, some code in another custom module was being called. This code is meant to wrap entity queries, massaging the return data into something more palpable and concise for the development team that wrote it. Deep in this code, in processing node entities, it was including a call to $node→url(), where $node is a \Drupal\node\Entity\Node object. Turns out, that triggers early rendering. To this, you might ask, "Why would something as innocuous as getting the URL for a node trigger early rendering?" The answer, and I’m only 80% sure after studying this for a while (do correct me if I’m wrong), is that URLs can vary by context based on language or the site URL. They can also have dependencies, such as the language configuration. Finally, URLs can have CSRF tokens embedded in them, which vary by session. All of which is important cacheability metadata that you want to be included in the response. OK, so what’s a responsible Drupal developer to do?

The complete (and verbose) solution, courtesy of ohthehugemanatee (indeed), is to replace your $node→url() call with something like:

// 1. Confusing: the method is called toString, yet passing TRUE for the first param nets you a \Drupal\Core\GeneratedUrl object. $url = $node->toUrl()->toString(TRUE); // 2. The generated URL string, as before. $url_string = $url->getGeneratedUrl(); // Add the $url object as a dependency of whatever you're returning. Maybe a response? $response = new CacheableResponse($url_string, Response::HTTP_OK); $response->addCacheableDependency($url); return $response;

That’s a lot, and it’ll be different depending on what you're doing. It’s broken down into 3 parts. First, you want to call $node->toUrl()->toString(TRUE);. This will essentially tell Drupal to track any cacheability metadata, which is part of generating the URL, and return an object from which you can get that cacheability metadata so you can deal with it. The second part is just getting the actual URL string, $url_string = $url->getGeneratedUrl();, to do with as you please. Finally, you need to account for any encountered cacheability metadata. In the context of a response as above, that means adding the $url object as a cacheable dependency. In the context of a render array, it might mean merging the $url cacheability metadata into the render array. (eg. CacheableMetadata::createFromObject($url)→applyTo($render_array))

Wrap it up

OK so now I understood where the exception was coming from and why. I also understand how I might change the code that is triggering an early rendering. But as I mentioned before, what if you don’t control the code that is triggering an early rendering? Is all hope lost? Not quite. What you can do is wrap the code triggering the early render in a render context. Let’s look at some code:

$context = new RenderContext(); /* @var \Drupal\Core\Cache\CacheableDependencyInterface $result */ $result = \Drupal::service('renderer')->executeInRenderContext($context, function() { // do_things() triggers the code that we don't don't control that in turn triggers early rendering. return do_things(); }); // Handle any bubbled cacheability metadata. if (!$context->isEmpty()) { $bubbleable_metadata = $context->pop(); BubbleableMetadata::createFromObject($result) ->merge($bubbleable_metadata); }

Let’s break this down:

$context = new RenderContext();

Here, I instantiate a new render context. A render context is a stack containing bubbleable rendering metadata. It’s a mechanism for collecting cacheability metadata recursively, aggregating or “bubbling” it all up. By creating and passing it in the next line, the render context is able to capture what would have otherwise been lost cacheability metadata.

/* @var \Drupal\Core\Cache\CacheableDependencyInterface $result */ $result = \Drupal::service('renderer')->executeInRenderContext($context, function() { // do_things() triggers the code that we don't don't control that in turn triggers early rendering. return do_things(); });

Here I run some arbitrary code within the render context I created. The arbitrary code, somewhere along its execution path that we have no control over, triggers early rendering. When that early rendering occurs, since I’m wrapping the code in a render context, the cacheability metadata will bubble up to the render context I setup and allow me to do something with it.

// Handle any bubbled cacheability metadata. if (!$context->isEmpty()) { $bubbleable_metadata = $context->pop(); BubbleableMetadata::createFromObject($result) ->merge($bubbleable_metadata); }

Now I check if the context is non-empty. In other words, did it catch some cacheability metadata from something that did early rendering? If it did, I get the captured cacheability metadata with $context→pop() and merge it with my \Drupal\Core\Cache\CacheableDependencyInterface object which will be returned. BubbleableMetadata is a helper class for dealing with cacheability metadata. This merge part may look different depending on your context, but the idea is to incorporate it into the response somehow. Take a look at the static methods in \Drupal\Core\Render\BubbleableMetadata  and its parent class for\Drupal\Core\Cache\CacheableMetadata some helpers to merge your cacheability metadata.

Really wrapping up

That was a heavy, long, complex debug session. I learned a lot digging into it and I hope you did as well. Let me know in the comments if you’ve ever run into something similar and came to a resolution in a different way. I’d love to continue furthering my understanding.

While it was great to figure this out, I was left wanting a better DX. In particular, improving the fact that Drupal auto-magically handles early rendering in some cases, but not others. There is also the odd workaround to capture cacheability metadata when cacheability metadata when calling $node→url() that could use some work. A quick search on the issue queue told me I wasn’t alone. Hopefully, with time and consideration, this can be made better. Certainly, there are good reasons for the complexity, but it would be great to balance that against the DX to avoid more epic debug sessions.

Acknowledgements
Categories: Drupal CMS

Pages