Planet Drupal

file_scan_directory() to moved to file_system service in Drupal 8.8.0

file_scan_directory is deprecated and has been moved to the file_system service

karthikkumardk Thursday, 25 July 2019 - 15:29:44 IST
How Do You Structure a Complex Content Architecture in Drupal 8? admin Thu, 07/25/2019 - 13:59

The ideas in this post were originally presented by Suzanne Dergacheva at Drupal North 2018.

If you've opted for Drupal, then you must be dealing with a large amount of content, right? Now, the question that arises is: how do you build out and structure a complex content architecture in Drupal 8?

For you definitely don't run out of options when it comes to organizing your content:

  • content types
  • paragraph types
  • (custom) block types
  • custom fields

And things get even more complex when you start to consider all the various relationships between these entities. 

Conversations concerning accessibility of digital assets tend to fall into one of two categories: the carrot or the stick.  The carrot is the host of business benefits associated with ensuring a great and accessible experience for all users. All too often, though, it’s the stick -- the threat of a lawsuit or actual legal action filed in federal court under Title III of the ADA -- that drives organizations to begrudgingly take steps toward getting their digital assets into compliance with WCAG 2.1 and ADA Section 508.   
Quick Hit: Using Drupal and Symfony Components Without Bootstrapping Drupal jflynn Fri, 07/26/2019 - 01:47 Sometimes we just want to see if a thing works

Recently I ran into a situation while building out the Watson/Silverpop Webform Parser where I just wanted to test and see if a few things worked without having to reload and bootstrap Drupal every time I refreshed a page. I also wanted to utilize some of the classes and methods made available from Symfony and Drupal. Can you feel my dilemma?

Let's be honest, running drush cr and refreshing a page takes time, and I'm an impatient person, so I wanted to see if there was a way to use some of these things without going through the pain of waiting for a Drupal bootstrap. Turns out, the solution wasn't that difficult and it made development on many methods of my module more pleasant than it could have been.

Here's the scenario

I wanted to test a few things that didn't require the database connection. Specifically, Drupal\Core\Serialization\Yaml to parse an array that I was building into YAML. So, what I did was stubbed out what would become my class WatsonFormEntityForm in a file in my docroot that I creatively named test.php. Now I was able to navigate to local.docksal/test.php on my local machine and see things working.

Get to the good stuff, already!

I got to a point in my development where I was able to convert the submitted HTML, in this case from a call to file_get_contents('./test.html'); into an array that I could work with. Xdebug was going great, and so was the module, but I wanted to see if I could convert it into YAML using a native Drupal method. The solution came with one single line of code.

$autoloader = require_once 'autoload.php';

This tells PHP, "Hey, we got a file here that wants to use some of the methods and classes in the Autoloader. Let's go ahead and let it!" This variable doesn't need to be called anywhere in the file. It just needs to exist. Now I was able to update the file with a few friendly use statements from within the Drupal and Symfony ecosystem without having to wait for all the database connections to happen.

The end result was:

<?php use Drupal\Core\Serialization\Yaml; $autoloader = require_once 'autoload.php'; // Do all the things here, including: $yaml = Yaml::encode($array); var_dump($yaml);

It sped up development, and it made it so I didn't have to wonder if something wasn't working because I forgot to drush cr all the things or if it was just because I made some mistakes.


Be sure that any code you're running doesn't rely on database calls or the container. For instance, if you try to run $nodes = \Drupal::entityTypeManager()->getStorage('node')->loadMultiple(); is going to throw a painful error.

Also, this is mainly for rapid prototyping or proving concepts. I don't recommend writing an entire module in procedural code and then trying to refactor later. Maybe take it one function at a time just to make sure it's doing what you want it to do.

Let me know if this helped you out or if you have better suggestions for rapidly testing some Drupal stuff without having to rely on a full bootstrap. As always, feel free to reach out to me on the Drupal Slack, where I'm always Dorf and always willing to help if I can.

Category Development Tags Drupal Drupal Planet Comments

The expanding data landscape is feeding the demand for higher operational agility. This calls for a more responsive, reliable IT infrastructure — that doesn’t rake up millions — minimizes delays and downtime while improving security and making infrastructure more agile.

Between capacity constraints and unpredictable pricing models, AWS offers suited workloads for growing infrastructure needs with a host of services - IaaS, PaaS, SaaS - for Drupal enterprises. 

Here’s how you can run your Drupal up to 40% cheaper.

Drupal-powered enterprises need to constantly understand and adapt to the changing landscape in order to achieve the business objective

You know how important accessibility is, but now what? There are a lot of well intentioned sites on the internet that aren’t accessible.

Is your website accessible?

How do you find out?

Well, it’s not as hard as it seems—and we’re here to help! Here are a few quick ways to measure the accessibility of your website.

1. Automated accessibility tests

While automated tools will only catch about 30% of accessibility bugs, they will give you a general idea of your site’s accessibility and show you some ways to make improvements.

Lighthouse: Chrome’s Accessibility Reporting Tool

Lighthouse is a free tool available right in Chrome. You can use it by simply using chrome’s testing website, in your development tools when you inspect a page, or with a browser plugin. Keep in mind that manual testing is also required to get a full picture of accessibility—we’ll cover that in just a moment.

To use the tool by going to a URL: Visit and paste the URL of the page you want tested into the form field, then click “Run Audit” to see results.

To use the tool through inspect

  1. Right click on the webpage you want to test, and select “Inspect” from the dropdown or from your keyboard press command + option + I. This will open the inspect tool and bring up the last tool you used, so if the last thing you did was run an audit, it will bring you back to the audits panel.

  2. In the inspection window at the top right, click on the button with a double arrow, or expand the window until you see “Audits.” Select “Audits.”

  3. Select your device size (mobile or desktop), and select “Accessibility” from the Audit Type options.
  4. Click “Run Audits.”
  5. A report will pop up in the inspect window with your overall score with information about your score results. Scores are out of 100, and 100 does not mean that a site is completely accessible–it means that it passed all automated tests.
  6. Below the score are details about accessibility errors. Toggle open these errors to see what element is failing and how to make fixes.
WAVE: Firefox and Chrome Extension

WAVE is a browser extension that allows you to run an automated accessibility test on a page of your website. It’s very thorough and one of our favorites for testing and fixing accessibility bugs.

To use WAVE:

  1. Install the WAVE Extension
  2. Go to the webpage you want to test, and click on the WAVE icon in the tools portion of your browser window. A report will pop up and your page will be marked up with the results of the review.

  3. A Summary will show up by default listing the number of Errors, Warnings, and other details on the page.

  4. Click on the Flag icon to see more details. This will include information about what errors are on the page

  5. Clicking on the Tab at the bottom of the page that says “< code >” will show you the code marked up with the errors found.
  6. With the “< code >” tab open, you can click on the errors and warnings in the panel on the left to jump to the errors in the code. In the image below, clicking on the yellow rectangle “Redundant Link” icon in the report panel makes the code jump to the offending code.

2. Manual accessibility tests

A manual test will catch things automated tests can’t quite figure out. Robots are good for some things, but they can’t figure out human intention, so things like tab order, visual theming and good alt tags should be manually tested.

Keyboard testing makes sure that the site works for folks who are blind, who have low vision, who have limited mobility, or the person whose trackpad is broken. Conduct the following tests to see if your site is accessible to those using a keyboard to navigate:

  1. Go to the page you’d like to test. Start with your cursor in the address bar, and hit the “tab” button to navigate through the page. Each time you press tab, you should be moved to the next button, link or form input.
  2. Ideally, the first link you get to on the page is a “skip to main content” link that allows users to skip repeated navigation items.

  3. As you continue to tab through the page, you should be able to see where the focus is as it lands on each button, link and form field. Pro-tip: If you lose track of where it is because there’s not a visual indication that’s an accessibility issue.
  4. Check the order: Does pressing the tab key follow the natural flow of the page, or does it jump around? A good tab order follows the natural flow.
  5. Can you operate all menus, pop-ups, buttons, and forms?
  6. Can you press shift tab and navigate backwards?
  7. Are there items that are clickable that don’t receive focus?

Important Note: Keyboard testing needs to be done on mobile as well as desktop. Why? Some users who are blind don’t use full-sized computers or laptops because they don’t actually need a large display. Other users have low vision and magnify their screens. Which leads us to testing with zoom…

3. Testing with zoom

If you zoom a desktop screen to 400% on a responsive site you get…the mobile site! This is why testing on mobile and desktop is important.

Now that you’ve increased the screen to 400%, browse the page. As you browse ask yourself:

  1. Does text content get cut off?
  2. Do buttons get pushed off of the page?
  3. Is the functionality intact?
  4. Is there key functionality on desktop that’s no longer available on the mobile version?
4. Testing with a Screen Reader

Using a screen reader is a more advanced testing approach, and very helpful in identifying accessibility bugs on a site. If you use a mac, VoiceOver is the built in screen reader. To turn VoiceOver on or off, press command f5. Here’s a quick video tutorial on how to test your page using VoiceOver. The video description includes the full text of the captions as a quick reference.

You can also turn on VoiceOver and tab through the page again to see if icon buttons are labeled properly, if the form labels you’ve applied make sense, and if alt tags on images are useful. If you press “control option a” all at once, VoiceOver will start reading every element from where you are on the page. If you tab, it will read the buttons, links and form inputs.

To sum it up:

Learning about different testing methods can help inform and add clarity to the process of making your site accessible. This is one of the most critical steps in your journey to making a website that everyone can experience. If you want to know how to transform these errors into a site that reads and navigates smoothly for all users, ThinkShout is here to help! Contact us to learn more about how we can partner to make your website more accessible.

The meetup started at 10:30 AM with a brief introduction of every attendee. We covered some of the Drupal news such as recent and upcoming events in India and internationally. We also talked about Drupal 9 and other changes in the technology.

We’re excited to be hosting the August 2019 TC Drupal monthly meeting, the first in the new "Lunch and Learn" format, which will rotate venues and feature a myriad speakers. See Allie's post about the change on the Twin Cities page. We look forward to them each month!

Page objects are a pattern that can be used to write clearer and more resilient test suites. This blog post will explore implementing page objects in PHP with the Mink library.

by Sam Becker / 29 July 2019

There are various PHP libraries for creating and maintaining page objects. In order to create a library that was useful for the current state of PHP functional testing in Drupal, I created a library with the design goals of:

  • Working seamlessly with Drupal core test classes, traits and weitzman/drupal-test-traits.
  • Working with all of Drupal's dev dependency version constraints and not introducing additional dependencies.
  • Exclusively utilising the Mink API, to provide a fast on-ramp for moving existing tests to page objects and for developers to write new page objects using their existing knowledge of Mink.
  • Drawing inspiration from nightwatch.js to provide transferability between PHP and JS functional tests.

Taken from the project page, by implementing page objects:

  • You create tests that are easier to read and maintain.
  • You reduce coupling between test cases and markup.
  • You encourage thorough testing by making the whole process easier.

While these examples will be using sam152/mink-page-objects the principles apply to using any library or indeed plain old objects. First I'll examine a real project test case using Mink directly, written to test a search feature on a Drupal site:

/** * Test how search results appear on the site. */ public function testSearchItemDisplay() { $sample_result = $this->randomMachineName(32); $this->createNode([ 'title' => $sample_result, 'type' => 'news_item', 'body' => ['value' => 'Test news item body'], 'moderation_state' => 'published', ]); $this->searchApiIndexItems(); $this->drupalGet(''); $this->submitForm([ 'query' => $sample_result, ], 'Search'); $this->assertSession()->pageTextContains('1 results for'); $this->assertSession()->elementContains('css', 'h1', $sample_result); $this->assertSession()->elementContains('css', '.sidebar-menu__item--active', 'Show all'); $this->assertSession()->elementContains('css', '.listing', $sample_result); // A news item should not appear when filtering by basic pages. $this->clickLink('Basic page'); $this->assertSession()->pageTextContains('0 results for'); $this->assertSession()->elementContains('css', '.sidebar-menu__item--active', 'Basic page'); $this->clickLink('News item'); $this->assertSession()->elementContains('css', '.sidebar-menu__item--active', 'News item'); $this->assertSession()->elementContains('css', '.listing', $sample_result); }

And now the equivalent test refactored to use a page object:

/** * Test how search results appear on the site. */ public function testSearchItemDisplayPageObject() { $sample_result = $this->randomMachineName(32); $this->createNode([ 'title' => $sample_result, 'type' => 'news_item', 'body' => ['value' => 'Test news item body'], 'moderation_state' => 'published', ]); $this->searchApiIndexItems(); $search_page = SearchPage::create($this); $search_page->executeSearch($sample_result) ->elementContains('@title', $sample_result) ->assertResultCount(1) ->assertResultsContain($sample_result) ->assertActiveFilter('Show all'); $this->clickLink('Basic page'); $search_page->assertActiveFilter('Basic page') ->assertResultCount(0); $this->clickLink('News item'); $search_page->assertActiveFilter('News item') ->assertResultCount(1) ->assertResultsContain($sample_result); }

In the second test, there are a few advantages:

  • The code is more DRY, since selectors on the page aren't repeated. In fact, if the page object was used for all future search tests, they'd never be repeated in a test again!
  • The test uses a more natural language that is easier to parse by readers of the code and communicates the intentions of the author in a clearer fashion.
  • The search page object is type-hinted, making writing new tests fast and reducing the amount of page related knowledge developers must collect and remember.

The cost paid for these benefits is an additional layer of indirection between your test case and the test browser, so to realise the full benefit of such an approach, I'd expect a page object to be written to service at least two different test cases however I haven't experimented implementing this pattern across a large scale test suite.

An annotated version of the page object (for the purposes of demonstration) looks like:

/** * A page object for the search page. */ class SearchPage extends DrupalPageObjectBase { /** * {@inheritdoc} */ protected function getElements() { // Selectors found on the page, these can be referenced from any of the Mink // API calls within this page object. return [ 'title' => 'h1', 'results' => '.listing', 'activeFilter' => '.sidebar-menu__item--active', ]; } /** * Assert the number of results on the search page. * * @param int $count * The number of items. * * @return $this */ public function assertResultCount($count) { $this->assertSession()->pageTextContains("$count results for"); return $this; } /** * Assert a string appears on the page. * * @param string $string * The string that should appear on the page. * * @return $this */ public function assertResultsContain($string) { $this->elementContains('@results', $string); return $this; } /** * Assert a string does not appear on the page. * * @param string $string * The string that should not appear on the page. * * @return $this */ public function assertResultsNotContain($string) { $this->elementNotContains('@results', $string); return $this; } /** * Assert the active filter. * * @param string $filter * The active filter. * * @return $this */ public function assertActiveFilter($filter) { $this->elementContains('@activeFilter', $filter); return $this; } /** * Execute a search query. * * @param string $query * A search query. * * @return $this */ public function executeSearch($query) { $this->drupalGet(''); $this->submitForm([ 'query' => $query, ], 'Search'); return $this; } }

While the library itself is decoupled from Drupal, the DrupalPageObjectBase base class integrates a few additional Drupal features such as UiHelperTrait for methods like ::drupalGet and ::submitForm as well as creating a ::create factory to automatically wire dependencies from Drupal tests into the page object itself.

I would be interested in hearing thoughts on if introducing page objects may benefit Drupal core's own functional test suite and details on how that might be accomplished given the tools available. 

Tagged Testing, Functional Testing, Mink, PHP Libraries
Decoupled Days is a conference for anyone who works with decoupled Drupal technology: developers, architects, executives, and even marketers like me. It’s been around since 2017 and focuses on sharing knowledge about back-end CMS development as a content service as well as front-end development for applications that consume that content.

What our clients are saying

...we just want you to know that we are appreciative!
...provided us with excellent, expert service in a professional and personable manner.
I had a very tight deadline and budget, and they met it, seemingly with ease.
I would highly recommend her for any position requiring IT design and development
... they also made suggestions which showed me that they fully understood what I wanted to accomplish. to take my abstract ideas and add their expertise to bring them to life in a way that was better than I could have imagined!
...your punctuality, your casual and open personalities, and both your hard copy and online portfolios speak very highly of you and your business as well
A great experience and a much improved website.
I realized that I had picked the right company to work with soon after beginning a project with Peerless Design, Inc.
I would highly recommend her for any position requiring IT design and development
...took my less than mediocre site and completely revamped it into a beautiful, professional, and easy-to-navigate site
...very responsive to our questions and needs
I'm so happy we chose to work with PEERLESS Design.
I love directing our customers to our new site knowing that they are going to be able to find exactly what they are looking for...
...creative, independent, responsive...
Thanks so much for everything!
I have seen the first layouts and they are awesome...
...can do anything any other designer can do and generally quicker, cheaper and better. to translate technical information in an accessible way...
...I have no doubt we will have the best site in the 2010 election of any PA candidate
...continued to monitor it closely and is still always available to help me if I have any questions
...a pleasure to work with, combining patience (for my busy schedule and at times overwhelmed brain) with her strong motivation and energy to keep me going
" PDI provides us prompt, effective and efficient service in maintaining our Drupal based website."
... incredibly impressed with what you brought to the table
...dedicated, competent and driven to get the job done and done well.