Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough
May 19 2020
May 19

Hi friends. I’m very excited about DrupalSpoons, and would love you to give it a try. DrupalSpoons is a model and a movement. It shows how great development for Drupal Contrib modules can be. DrupalSpoons is a particular configuration of groups and projects built at Gitlab.com. DrupalSpoons offers Issues, Merge Requests (same as PRs), and CI to Contrib projects. It uses zero custom code (except for the issue migration), since I have no special access to gitlab.com.

Please read its README.md and click through the many links there. There you will learn the goals of the project, and more about its implementation. Devel and KeyCDN modules are now developed on DrupalSpoons. For example, observe that all of Devel’s open issues were migrated.

If you maintain a Contrib module, please consider moving it to DrupalSpoons. If you are a contributor, open a “Move to DrupalSpoons” issue for your favorite module. We can be done with rolling and re-rolling patches like its 1999. If we get enough momentum, I’m hoping that the DA will adopt a similar approach for its Gitlab instance and all projects can move back to git.drupalcode.org.

If you like my proposal, please retweet and join! I led prior movements in Drupal like groups.drupal.org and #D7CX pledge, and Drupal Code of Conduct. These movements only succeed with early vocal support.

To discuss this blog post and DrupalSpoons in general, lets use this issue or #drupalspoons on Drupal Slack. Please bring your most positive self :)

P.S. I never set out to build a Drupal project platform. A Devel co-maintainer asked me to fix our Travis tests. I did so on Gitlab.com and it Corona-spiralled from there. “If you wish to make an apple pie from scratch, you must first invent the universe” – Carl Sagan.

Devel issues

Sep 29 2017
Sep 29

Drush 9 features a deep rewrite of our app, both user facing and internals. We created and open sourced AnnotatedCommand (example), OutputFormatters, and Config. We leveraged Symfony Console for our CLI fundamentals. For details on Drush9, see the video or slides from our Drupalcon Vienna presentation.

Annotated Command example

Unfortunately, old commandfiles such as example.drush.inc no longer load in Drush 9 (since beta5). We’ve made it relatively painless to port this code to Drush 9. The video below shows the drush generate command porting the migrate commands. Detailed instructions are below the video.

  1. Using Drush 9 on a working site, run drush generate drush-command-file. generate is a wrapper for the Drupal Code Generator library.
  2. You will be prompted for 2 pieces of information:
    1. Module name: example
    2. Absolute path to legacy Drush command file: /path/to/example.drush.inc
  3. Drush writes 2 files to the Example module:
    1. drush.services.yml. No edits are needed unless you want to inject Drupal dependencies into your class (e.g. yml, class.
    2. ExampleCommands.php: Each item in example_drush_command() in your old commandfile has been transformed into an Annotated method in a new ExampleCommands file. Copy the body of your command callback functions into the corresponding method in ExampleCommands. Then modernize the code as below. Compare the Drush9 commands versus the Drush8 commands for guidance.
      1. Replace drush_log() with $this->logger()->info() or $this->logger()->warning() or similar.
      2. Replace drush_get_option('foo') with $options['foo'']
      3. Replace drush_set_error() with throw new \Exception()
      4. Replace drush_print() with $this->output()->writeln()
      5. Replace drush_sitealias_get_record() as with $this->siteAliasManager()->getSelf(). From there you can call getRoot(), getUri(), legacyRecord(), and other handy methods. In order for this to work, edit your class to implement SiteAliasManagerAwareInterface (LoginCommands is an example).
      6. Optional - move user interaction to a @hook interact. Also, note the new $this-io()->confirm() and $this->io()->ask() methods.
  4. Run drush cr to add your commandfile to the Drupal container.
  5. Congrats - your commands are now runnable in Drush9!
    1. Please post a patch if Example is a Contrib module.
    2. Please leave example.drush.inc in your module so that Drush 8 users may still use it.

I’m in #drush on IRC and Slack in case anyone wants help with porting.

Note that drush generate knows how to generate controllers, plugins, config, services, libraries, etc. A blog post about generate is coming soon.

Moshe is available for hire as a consultant. Moshe has worked on Drupal core since 2001, and loves mentoring Drupal teams. Moshe loves to set up CI and developer workflows for PHP/JS teams.

Aug 14 2017
Aug 14

With pride and pleasure, the Devel maintainers have released 1.0 for Drupal 8. Even at the ripe age of 14, Devel is an active, popular, and nimble project. Devel has been downloaded 3.5M times, and 200,000 sites currently report Devel as an enabled project. Devel’s whole codebase was deeply improved in this release. A few highlights are below, with annotated screenshots and gifs below each section. Please upgrade and report your success or failure using the new features!

Webprofiler

  • A new submodule in Devel that reports all sorts of useful details abut a Drupal response.
  • Dive into Cache-hit ratio, DB queries, Events, Forms, Session, Assets, and much more.
  • Add your own data collectors.
  • Learn more at our demo video.

WebprofilerWebprofiler toolbar expandedWebprofiler toolbarWebprofiler databaseWebprofiler widgets list

Devel Module

  • Integrated into the new toolbar as a top level menu (configurable).
  • New pages and Drush commands list available Services, Routes, Events, etc.
  • New State and Configuration editors
  • 3 Twig extensions for debugging
  • A new plugin system for showing dumps like dpm(). Enable and configure the new Kint submodule for pretty dumps.
  • Supports Drush 8 and Drush 9.

Devel configurationDevel drush servicesDevel drush uuidDevel dumpersDevel state editorDevel toolbarDevel toolbar items list

Devel Generate

  • We moved the generation of text/int/bool/etc. for Fields into Drupal 8 core. Now all field types, even custom and obscure ones, are supported.
  • Supports Drush 8 and Drush 9.

Moshe is available for hire as a consultant. Moshe has worked on Drupal core since 2001, and loves mentoring Drupal teams. Moshe loves to set up CI and developer workflows for PHP/JS teams.

Jul 26 2017
Jul 26

It is a repeating need for me to debug Drush commands that run at Acquia Cloud. When I say “debug”, I refer to step-wise debugging via Xdebug. This is the best and only way to slay hard bugs. Down with print_r() debugging!

This blog is a terse “how-to”. Refer to Acquia - Configuring Xdebug with PhpStorm for more detail.

  1. SSH with a tunnel: drush @massgov.prod -v --ssh-options="-R 9000:localhost:9000" ssh
    1. Replace @massgov.prod with your own site alias
    2. This command connects to Acquia via SSH AND opens a tunnel from Acquia’s port 9000 to your laptop’s port 9000. This allows PHP on Acquia to connect to your PHPStorm no matter what firewall separates you. If your site alias (e.g. @massgov.prod) already defines ssh-options option, then above needs to be changed as follows:
      1. If using Drush9, you may make a CLI request with --ssh-options='-R 9000:localhost:9000 ADD STUFF FROM ALIAS HERE'.
      2. If using Drush8, you must edit your alias to add the -R 9000:localhost:9000. You can’t add that from the CLI.
    3. To verify that the tunnel is working, you can run netstat -nlt | grep 9000 in same terminal window. If you see output, you are good.
  2. In your local PHPStorm project, Run => Start listening for PHP Debug Connections
  3. In your local PHPStorm project, Run => Break at the first line in PHP scripts
  4. Back in your terminal window that is ssh-ed into Acquia, run XDEBUG_CONFIG= php -dzend_extension=xdebug.so -dxdebug.remote_enable=1 ../vendor/bin/drush core-status
    1. The environment variable XDEBUG_CONFIG= has no value because none is needed. This nudges XDebug to connect back to PHPStorm.
    2. The two -d options enable and configure XDebug extension for the current request.
    3. The /vendor/bin/drush path points to the site-local Drush. Older Drupal sites that are not built with Composer can just use drush instead.
    4. core-status is just an example command. Replace with your own command and arguments/options.
  5. If all went well, your PhpStorm should be debugging at line 1 of drush. If PHPStorm has a red warning about Path Mappings, click that link to set them up.

Debugging Drush commands at Acquia

May 17 2017
May 17

I’ve long preferred doing web development on my local laptop. Unfortunately, my current consulting gig has strict requirements. Specifically, I’m again migrating content from an Oracle database into Drupal 8. This time, the Oracle database is behind an IP based VPN - I can only connect to it via a specific AWS instance that’s running our Drupal 8 site. My PHP has to run at AWS, and can’t run locally. Happily, PHPStorm thrives in this situation. PHPStorm Deployments sync code from my laptop to AWS via SSH. Further, I’ll show how to configure the Debugger to step through remote execution of PHP CLI scripts. Remember kids, the debugger is your friend.

This blog is a terse “how-to”. Refer to Sync changes and automatic upload to a deployment server in PhpStorm and Remote Debugging in PHPStorm via SSH Tunnel for more detail.

Remote Deployment

  1. Start creating a new Deployment configuration: Tools => Deployment => Configuration
  2. Enter a name and pick SFTP for the type.
  3. On the connection tab, enter the SSH details for remote server.
  4. On the Mappings tab, tell PHP storm how the remote path maps to the local path. In my case:
    Local path: /Users/moshe.weitzman/reps/b4
    Remote path: /var/www/drupal
    
    
  5. Test by browsing the remote host: Tools => Deployment => Browse Remote Hosts
  6. You may now upload from local to remote via Tools => Deployment => Upload To [name]. Explore other options in this menu that may better suit your use case.

Remote Deployment example

Remote CLI Debugging over an SSH Tunnel

On your local machine:
  1. Run => Start listening for PHP Debug Connections
  2. Run => Break at the first line in PHP scripts
  3. In a terminal on local machine, run a command like ssh -R 9000:localhost:9000 -A [email protected]. The -R arguments creates a SSH tunnel such that port 9000 on the remote server forwards all traffic to port 9000 on your local machine. This neatly bypasses any networking challenges between you and the remote machine. Customize [email protected] for your own needs.
On the remote server:
  1. Enable and configure the Xdebug PHP extension on the remote server. Use php --ini to figure out which ini file to edit. Then add:
    zend_extension=xdebug.so
    xdebug.remote_enable=1
    xdebug.remote_host=127.0.0.1
    xdebug.remote_port=9000
    
    
  2. Use php -i | grep -i xdebug to verify that your edits are working (i.e. remote_enable is enabled).
  3. In a terminal on the remote server, run a PHP CLI script such as XDEBUG_CONFIG= vendor/bin/drush st. The first clause sets a required environment variable to null value. We only need this variable to be defined. It triggers XDebug to connect back to PHPStorm.
  4. If prompted about Path Mappings, choose to pull them from the Deployment specified above.

Troubleshooting

If you get stuck, I refer you again to these longer documents: Sync changes and automatic upload to a deployment server in PhpStorm and Remote Debugging in PHPStorm via SSH Tunnel.

Mar 01 2016
Mar 01

Drupal.org uses a patch based workflow in order to improve its software. Today I present a concrete instance where this significantly slowed us down. Views performance work is blocked when it didn’t have to be.

Today, Dries committed a fine patch by Sun which moved a lot of test files into a happier place. After that commit, Dries reviewed Daniel’s Views patch which changed a couple of those same test files. Daniel’s patch failed to apply so Dries changed the issue to Needs Work. This doesn’t need to happen anymore. Git knows about file moves and can overcome this problem when we use it fully. If Daniel’s change was a merge instead of a patch, git uses its ancestry to apply changes to the moved test files. Try for yourself - the commands I ran are below.

We could all increase our velocity by using a merge workflow. Think of all the patches that need reroll currently which would not need reroll. Think of all the patches considered disruptive when they don’t need to be. I know that we can’t avoid all ‘Needs reroll’ events, but we can avoid a lot.

For now, I encourage folks to use d.o. sandboxes or Github to host their forks, and to post git merge commands into the issue queue instead of uploaded patches. Discussion of these changes should remain in the main issue queue. I think we should document this workflow at Drupal.org Git tutorials.

Feedback welcome.

Start from a clean 8.0.x:

# Create  branch whose tip is the commit before Sun's
$ git checkout -b daniel ebace9e
#Apply Daniel's patch
$ wget -O tmp.patch https://www.drupal.org/files/issues/1849822-view_render-19.patch; git apply tmp.patch;
$git commit -am "Fix #1849822. Convert (HTML) view rendering to a render array"
#Switch to main branch
$ git co 8.0.x
#Merge Daniel's patch and watch git's work its magic
$ git merge daniel
Auto-merging core/modules/views/tests/src/Unit/Routing/ViewPageControllerTest.php
Auto-merging core/modules/views/tests/src/Unit/Plugin/Block/ViewsBlockTest.php
Merge made by the 'recursive' strategy.
 core/modules/rest/src/Plugin/views/display/RestExport.php 
 core/modules/user/src/Tests/UserBlocksTest.php
 core/modules/views/src/Annotation/ViewsDisplay.php
 core/modules/views/src/Plugin/Block/ViewsBlock.php
 core/modules/views/src/Plugin/views/display/Attachment.php
 core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
 core/modules/views/src/Plugin/views/display/Feed.php
 core/modules/views/src/Routing/ViewPageController.php
 core/modules/views/src/ViewExecutable.php
 core/modules/views/tests/src/Unit/Plugin/Block/ViewsBlockTest.php
 core/modules/views/tests/src/Unit/Routing/ViewPageControllerTest.php
 core/modules/views/views.module
 core/modules/views/views.theme.inc
 13 files changed, 147 insertions(+), 32 deletions(-)
Mar 19 2015
Mar 19

The Drush team is thrilled to announce the release of Drush 6. Full release notes are there. The highlight of Drush 6 is the new outputformat system. You can now request Drush output in easily parsed formats like json, csv, yaml etc.

Please come to our lab at Drupalcon Prague for in-depth discussion and hand-on learning about Drush 6.

Note: if you are using Drupal 8, you should stick with a frequently updated clone of master branch. Drush 6 supports Drupal 6+7 but not Drupal 8.

Drush Project Moves to Github

The Drush project has moved to Github. Update your clones!

See our wiki page which details the motivations and details surrounding this move.

Drush loves Github

Aug 19 2013
Aug 19

Drupal.org uses a patch based workflow in order to improve its software. Today I present a concrete instance where this significantly slowed us down. Views performance work is blocked when it didn’t have to be.

Today, Dries committed a fine patch by Sun which moved a lot of test files into a happier place. After that commit, Dries reviewed Daniel’s Views patch which changed a couple of those same test files. Daniel’s patch failed to apply so Dries changed the issue to Needs Work. This doesn’t need to happen anymore. Git knows about file moves and can overcome this problem when we use it fully. If Daniel’s change was a merge instead of a patch, git uses its ancestry to apply changes to the moved test files. Try for yourself - the commands I ran are below.

We could all increase our velocity by using a merge workflow. Think of all the patches that need reroll currently which would not need reroll. Think of all the patches considered disruptive when they don’t need to be. I know that we can’t avoid all ‘Needs reroll’ events, but we can avoid a lot.

For now, I encourage folks to use d.o. sandboxes or Github to host their forks, and to post git merge commands into the issue queue instead of uploaded patches. Discussion of these changes should remain in the main issue queue. I think we should document this workflow at Drupal.org Git tutorials.

Feedback welcome.

Start from a clean 8.0.x:

# Create  branch whose tip is the commit before Sun's
$ git checkout -b daniel ebace9e
#Apply Daniel's patch
$ wget -O tmp.patch https://www.drupal.org/files/issues/1849822-view_render-19.patch; git apply tmp.patch;
$git commit -am "Fix #1849822. Convert (HTML) view rendering to a render array"
#Switch to main branch
$ git co 8.0.x
#Merge Daniel's patch and watch git's work its magic
$ git merge daniel
Auto-merging core/modules/views/tests/src/Unit/Routing/ViewPageControllerTest.php
Auto-merging core/modules/views/tests/src/Unit/Plugin/Block/ViewsBlockTest.php
Merge made by the 'recursive' strategy.
 core/modules/rest/src/Plugin/views/display/RestExport.php 
 core/modules/user/src/Tests/UserBlocksTest.php
 core/modules/views/src/Annotation/ViewsDisplay.php
 core/modules/views/src/Plugin/Block/ViewsBlock.php
 core/modules/views/src/Plugin/views/display/Attachment.php
 core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
 core/modules/views/src/Plugin/views/display/Feed.php
 core/modules/views/src/Routing/ViewPageController.php
 core/modules/views/src/ViewExecutable.php
 core/modules/views/tests/src/Unit/Plugin/Block/ViewsBlockTest.php
 core/modules/views/tests/src/Unit/Routing/ViewPageControllerTest.php
 core/modules/views/views.module
 core/modules/views/views.theme.inc
 13 files changed, 147 insertions(+), 32 deletions(-)

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web