Skip to main content

Blog

Usted – nuestros clientes, colegas, y admiradores locos – es la razón por la que hacemos lo que hacemos. Nos encantaría saber de usted.

Websites powered by Find It connect people to all that their communities have to offer.  Developed under the guidance of the Cambridge Kids' Council, Find It ensures that people from all backgrounds can easily find activities, services, and resources.

Find It's design was informed by hundreds of hours of research, including over 1,250 resident surveys and over 120 interviews with service providers. Six years of research and development and continuous improvements has resulted in the Find It approach and platform, ready to be implemented in cities and communities around the world.

The platform is Free and Open-source and flexible so that communities can customize it to their own needs. Whether you are city IT staff, a developer that works with cities, or are anyone that could use a Find It in your community, we would love to talk. 

 

Come Monday, March 23rd, for a day devoted to Drupal in healthcare— a relaxed and friendly opening to DrupalCon with information-packed presentations plus two "table talk" sessions which will give everybody a chance to dive deeply into key topics, including privacy and overall takeaways. Whether you are in a state department of health, a non-profit hospital, a public health organization, or anyplace else in the broad healthcare space, there are unique needs in ensuring security, accessibility, compliance, and availability of important information and tools.

Online communication and emerging technologies promise improved access and capabilities for patients and professionals. Useful and inspiring digital experiences, however, must be built on a foundation of privacy, accessibility, and legal compliance. Come listen to healthcare technology practitioners share their experience solving these and more challenges in healthcare.

Get tickets to go to DrupalCon and the Healthcare Summit!

Ticket includes lunch, and we will be all wrapped up by 4pm.

Who Should Attend

Everybody interested in hearing and discussing how companies and the community are creating rich digital experiences in the healthcare space. All levels of colleagues in the pharma, medical, clinical, hospital, payers, caregivers, advocates, and healthcare professional space should go to DrupalCon and the Healthcare Summit!

Bring your needs to the table talks and we will embark on facilitated peer-to-peer problem solving with others who are affected and tech and healthcare industry experts.

COVID-19/DrupalFlu Safer Space

We will have a sensor in the room to monitor CO₂ levels and if they remain between at 800–1000 ppm.

Agaric will also have high-quality N95 masks available to anyone who wants them, and may bring our own MERV-13 Corsi-Rosenthal box fan filter, which provides appropriate filtration for reducing the spread COVID-19.

More about the Healthcare Industry Summit

The Healthcare Industry Summit brings together professionals and innovators to explore how Drupal can drive impact in healthcare. Through expert-led sessions, you’ll gain insights into topics such as the responsible use of AI, personalization, content marketing, and streamlining migrations.

In addition to presentations, roundtable discussions will provide opportunities to share experiences, exchange ideas, and build connections with peers tackling similar challenges. Join us to discover innovative approaches and collaborative strategies that are shaping the future of healthcare with Drupal.

The Healthcare Summit at the 2025 Chicago, Illinois, DrupalCon is organized by Jeanne Cost, Laura Chaparro, and myself.  I am glad to be playing a part in coordinating this summit, especially given Agaric's involvement in and commitment to health and science communities.

Just got back to Boston from GLADCamp, the Greater Los Angeles Drupal Camp, a free community three-day event and one of the best camps I have attended. The theme was "Drupal for Good" and it delivered from the opening keynote to the closing barn raising.

I was glad to present two sessions at this camp, which was organized by volunteers from the Greater Los Angeles Drupal community—whose user group boasts 5 to 10 events a month—such as Christefano Reyes and Lee Vodra of Exaltation of Larks and an extensive list of Drupal community members and participating sponsors.  The free conference took place on March 7th, 8th & 9th, 2014, at the Hilton Pasadena & Convention Center in Pasadena, California. This camp had a lot to offer in the way of sessions and was one of the best camps I have attended due to...

  • Sessions organized into logical tracks.
  • Transparency of finances and process.
  • High level of interaction between attendees and presenters.
  • Top-notch keynote speakers and topics.

Intro to Drupal 1,2,3 - with Lee Vodra - Exhaltaion of LarksThe sessions were set up specifically so that attendees would not have to change conference rooms as often - and it worked, as I heard several people make positive remarks about the schedule. GLADCamp session tracking was chosen very wisely, and lots of them contained valuable information for start-ups, non-profits and people just starting to learn Drupal. The track for advanced developers was also very rich, and well planned. Most of the sessions offered Q+A time and/or hands on learning.

See a list of all the GLADCamp sessions here: https://gladcamp.org/2014/program/sessions

To the right is a pic from the Intro to Drupal 1, 2, 3 session led by Lee Vodra a co-founder of Exaltation of Larks.  

Advanced coders had excellent choices such as:

  • Search API Solr Setup
  • AJAX and jQuery with Drupal: Loading Nodes into the DOM without Reloading the Page
  • Advanced Views
  • Responsive Layouts with Omega4, SingularityGS and Breakpoint
  • The Symfony Way

Beginners and non-coders had choices such as:

  • Drupal Install Fest
  • Intro to Drupal 1, 2, 3 - Two Hour Session
  • Introduction to Views in Drupal 8
  • VoipDrupal - Your Site and a Regular Phone
  • Estimation for Drupal Projects: Reducing Uncertainty & Defining the Client Relationship

As FreeScholar, I presented two sessions - my first was tracked in "Business, Strategy & Case Studies" and was titled: "Drupal Community - The big picture - How do I earn $". This session was mostly a discussion around ways of forming a collective of Drupalists that take on projects that suit their goals and ideas. As a collective people can determine the best way to divide and use their 'collective' profits to fund causes that are near and dear to their hearts - such as FSF.org and EFF.org.  My second session was on VoipDrupal, a suite of modules developed at the MIT Media Lab by Dr. Leo Burd and a team of developers. The session was titled "VoipDrupal - Your Site and a Regular Phone", and it was tracked in "Site Building & Using Drupal".  VoipDrupal allows your website to interact with a regular telephone using a VOIP telephony service. This session was an overview of the core VoipDrupal modules and a live demonstration of the conference calling on the fly feature, some people caught up with me between the next sessions and were actively interested in using VoipDrupal on their current Drupal projects.

A fantastic time was had by all! Pasadena Media captured the whole GLADCamp event and will be incorporating the slides into the footage of the sessions. Of all the sessions, the Barn Raising was one of the MOST impressive. Pasadena Media was the recipient of the effort and they were gifted with about 15-20 developers/designers collaborating on the start of a Drupal 7 site that now has content types and some roles defined along with some custom menus - all created using Drupal's Best Practices!.

Sign up to be notified when Agaric gives a migration training:

Usted – nuestros clientes, colegas, y admiradores locos – es la razón por la que hacemos lo que hacemos. Nos encantaría saber de usted.

 

featured project:

For long-term projects one of the engineering challenges is to cope with technical evolution. The languages, libraries, and third party software like database engines and web servers we are using are under continuous development; new features are only added to the current development branches and security updates are only applied to currently supported releases. Using the example of one of our projects I will point out specific challenges and possible ways to deal with them in a series of posts.

On https://premium.zeit.de the German weekly DIE ZEIT offers subscriptions to digital formats of their newspaper in epub, mobi, pdf and mp3. Since 2011 Drupal 6 with Ubercart was used to take orders and deliver the content. Fulfillment is handled by a third party also providing the service to the company's print publications. User accounts and customer information are stored by a dedicated service running behind the company’s firewall.

In 2013 several challenges slowed down development: The web stack was still running on Ubuntu 8 with PHP 5.2 which had reached end of life. Lack of a comprehensive test suite meant upgrading would be a risky operation or require extensive end-user testing. Also it had turned out Ubercart was not a good fit for the project. Just maintaining a catalog of products and taking orders to be sent to the fulfillment provider does not require a full e-commerce solution.

The first step of reviving the project and upgrading to Drupal 7 was to set up a virtual machine for development, resembling the intended production environment (Debian 7 with Apache, PHP and MySQL). Together with the client and our partners Spry Group, we decided to use Vagrant to create a virtual machine from configuration and provisioning scripts which were committed to the repository. Before writing the provisioning scripts, tests were written to ensure the configuration of the development environment matched expectations.

  /**
   * Tests if a Drupal web site is served on port 80, and there are no errors.
   */
  public function testDrupalWorks() {
    $data = file_get_contents('http://127.0.0.1/');
    $pos = stripos($data, 'name="Generator" content="Drupal 7"');
    $this->assertTrue($pos !== FALSE);
  }

  /**
   * Tests that drush is properly configured.
   */
  public function testDrushWorks() {
    $output = shell_exec('drush st --pipe');
    $this->assertRegExp('#drush_configuration=/etc/drush/drushrc.php#', $output);
  }

Above code sample shows two of our infrastructure tests written in PHPUnit. They are executed inside the virtual machine which is supposed to serve a fully working Drupal installation. The second test asserts drush is available and is using the appropriate configuration file. We chose PHPUnit as our testing framework, and we also used it for functional testing of the Drupal web site later. In one of the upcoming posts I am going to explain the approach we developed with Spry Group. These and other infrastructure test suites proved very useful during our transition to provisioning with Chef.

This combination—of a virtual machine to simulate the production environment with corresponding tests validating its functionality—enabled us to adapt to technological evolution in a well-controlled environment. For example, trying out a new stable release of the operating system or even a different OS is a simple matter of creating a new virtual machine and running the test suite against it. The more code we would cover with tests the more likely it would be to detect any issues introduced by a newer version of PHP for example.

Over the coming months I will share further insights that we have learned from this long-term project.

Micky Metts hablando en Libre Planet.

Micky Metts pronunció discursos en NERD Summit y LibrePlanet sobre Cómo Prevenir El Mundo Digital de 1984.

Tell us how you would like to use the online learning platform. The more details you can give, the easier it will be for us to help your mission!
Agaric logo to the left of the agaric wordmark.

For community shared business, development, and training tools, Agaric throws a little sponsorship at modulecraft.com.

2019 update: Pronovix let the domain expire, but the Wayback machine still has the content.

During a migration, Drupal reads the data from an external source and creates content in our new Drupal Site. While doing that, Drupal executes all hooks and events related to creating the new content. So any implementations of hook_entity_insert() are triggered for every new entity saved on our new site.

This can be a problem if we have some features in our new site which have an effect beyond the site and are executed when any new content is created, such as sending a tweet or sending an email. When we run the migration we will have a ton of emails or tweets from the old content. Usually, that is not the expected nor desired behavior.

Fortunately, in Drupal 8 the migrations are Events and we can create an EventSubscriber (more about EventSubscribers here) which will allow us to create a flag before the migration runs so we can determine in our code if the entity has been created during a migration or not.

The main idea was taken from this Moshe Weitzman gist. (Thanks!) I will add just the missing parts.

First, we generate all the event subscriber related files using this Drupal Console command:

 drupal generate:event:subscriber

The console will ask some questions (in which module do we want to generate the EventSubscriber and the name of the service):

 Enter the module name [config_log]:
 > your_module

 Enter the service name [simple_faq.default]:
 > migration_events.subscriber

 Class name [DefaultSubscriber]:
 > MigrationEvents

 Enter event name [ ]:
 >

 Do you want to load services from the container (yes/no) [no]:
 > no

 Do you confirm generation? (yes/no) [yes]:
 >yes

This will generate two files:

modules/custom/your_module/your_module.services.yml

Which basically lets Drupal know that we have a Subscriber there which needs to be executed and:

modules/custom/your_module/src/EventSubscriber/MigrationEvents.php

With this content:

namespace Drupal\simple_faq\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\Event;

/**
 * Class MigrationEvents.
 *
 * @package Drupal\simple_faq
 */
class MigrationEvents implements EventSubscriberInterface {

  /**
   * Constructs a new MigrationEvents object.
   */
  public function __construct() {

  }

  /**
   * {@inheritdoc}
   */
  static function getSubscribedEvents() {

    return $events;
  }

}

We need to add our flag in this file which will indicate to Drupal that we are running the migration. First, we need to import the Migrate events, at the top of our MigrationEvents.php file:

use Drupal\migrate\Event\MigrateImportEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\migrate\Event\MigrateEvents;

And then after add our methods, within the MigrationEvents class:

   protected $staticCache;

  public function __construct() {
    $this->staticCache = &drupal_static("your_migration");
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      MigrateEvents::PRE_IMPORT => 'onMigratePreImport',
      MigrateEvents::POST_IMPORT => 'onMigratePostImport',
    ];
  }

  /**
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   Import Event.
   */
  public function onMigratePostImport(MigrateImportEvent $event) {
    if ($event->getMigration()->getBaseId() == "your_migration") {
      $this->staticCache = FALSE;
    }
  }

  /**
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   Import Event.
   */
  public function onMigratePreImport(MigrateImportEvent $event) {
    if ($event->getMigration()->getBaseId() == "your_migration") {
      $this->staticCache = TRUE;
    }
  }

And that's it, now we have a flag which we can use to determine if we are running the migration or not, the complete class look like this:

namespace Drupal\your_module\EventSubscriber;

use Drupal\migrate\Event\MigrateImportEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\migrate\Event\MigrateEvents;

/**
 * Event subscriber to avoid sending emails/tweets/facebook posts on migrations.
 */
class MigrationEvents implements EventSubscriberInterface {

  /**
   * The drupal_static cache.
   *
   * @var array
   */
  protected $staticCache;

  /**
   * CommentEventSubscriber constructor.
   */
  public function __construct() {
    $this->staticCache = &drupal_static("your_migration");
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      MigrateEvents::PRE_IMPORT => 'onMigratePreImport',
      MigrateEvents::POST_IMPORT => 'onMigratePostImport',
    ];
  }

   /**
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   Import Event.
   */
  public function onMigratePostImport(MigrateImportEvent $event) {
    if ($event->getMigration()->getBaseId() == "your_migration") {
      $this->staticCache = FALSE;
    }
  }

  /**
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   Import Event.
   */
  public function onMigratePreImport(MigrateImportEvent $event) {
    if ($event->getMigration()->getBaseId() == "your_migration") {
      $this->staticCache = TRUE;
    }
  }
}

And finally, we now can use this variable to determine if we should send that email when creating a new entity, for instance:

/**
 * Implements hook_node_insert().
 */
function yourmodule_node_insert($entity) {
  // If the migration is running, just return without doing anything.
  if (drupal_static('your_migration', FALSE)) {
    return;
  }
  // All your code for sending emails/tweets is here.
  // . . .
}

And that's it.

Here we used drupal_static to preserve the value through the execution of the migration. If you want to read more about it, check here

Citations supporting specific points in Micky's talk

"Silicon Valley is solving the problems that 20-something's with money face" Should tech startups tackle bigger problems? Yes. #cyberposium  — Emily‏ @EmVVeis on 1 Nov 2014

On startups solving problems of wealthy, white, younger men:

Other:

What else?

What are we missing?  What would you add or change?  Send us a note or tell us in the comments below!

In the previous post we talked about migration groups provided by the Migrate Plus module. Today, we are going to compare them to migration tags. Along the way, we are going to dive deeper into how they work and provide tips to avoid problems when working with them. Let’s get started.

Example migration group definition containing migration tags.

What is the difference between migration tags and migration groups?

In the article on declaring migration dependencies we briefly touched on the topic of tags. Here is a summary of migration tags:

  • They are a feature provided by the core Migrate API.
  • Multiple tags can be assigned to a single migration.
  • They are defined in the migration definition file alone and do not require creating a separate file.
  • Both Migrate Tools and Migrate Run provide a flag to execute operations by tag.
  • They do not allow you to share configuration among migrations tagged with the same value.

Here is a summary of migration groups:

  • You need to install the Migrate Plus module to take advantage of them.
  • Only one group can be assigned to any migration.
  • You need to create a separate file to declare group. This affects the readability of migrations as their configuration will be spread over two files.
  • Only the Migrate Tools provides a flag to execute operations by group.
  • They offer the possibility to share configuration among members of the same group.
  • Any shared configuration could be overridden in the individual migration definition files.

What do migration tags and groups have in common?

The ability to put together multiple migrations under a single name. This name can be used to import or rollback all the associated migrations in one operation. This is true for the migrate:import and migrate:rollback Drush commands provided by Migrate Plus. What you have to do is use the --group or --tag flags, respectively. The following snipped shows an example of importing and rolling back the migrations by group and tag:

$ drush migrate:import --tag='UD Config Group (JSON Source)'
$ drush migrate:rollback --tag='UD Config Group (JSON Source)'

$ drush migrate:import --group='udm_config_group_json_source'
$ drush migrate:rollback --group='udm_config_group_json_source'

Note: You might get errors indicating that the "--tag" or "--group" options do not accept a value. See this issue if you experience that problem.

Neither migration tags nor groups replace migration dependencies. If there are explicit migration dependencies among the members of a tag or group, the Migrate API will determine the order in which the migrations need to be executed. But if no dependencies are explicitly set, there is no guarantee the migrations will be executed in any particular order. Keep this in mind if you have separate migrations for entities that you later use to populate entity reference fields. Also note that migration dependencies are only executed automatically for import operations. Dependent migrations will not be rolled back automatically if the main migration is rolled back individually.

Can groups only be used for migrations defined as configuration entities?

Technically speaking, no. It is possible to use groups for migrations defined as code. Notwithstanding, migration groups can only be created as configuration entities. You would have to rebuild caches and sync configuration for changes in the migrations and groups to take effect, respectively. This is error prone and can lead to hard to debug issues.

Also, things might get confusing when executing migrations. The user interface provided by Migrate Plus works exclusively with migrations defined as configuration entities. The Drush commands provided by the same module work for both types of migrations: code and configuration. The default and null values for the migration_group key are handled a bit different between the user interface and the Drush commands. Moreover, the ability to execute operations per group using Drush commands is provided only by the Migrate Tools module. The Migrate Run module lacks this functionality.

Managing migrations as code or configuration should be a decision to take at the start of the project. If you want to use migration groups, or some of the other benefits provided by migrations defined as configuration, stick to them since the very beginning. It is possible to change at any point and the transition is straightforward. But it should be avoided if possible. In any case, try not to mix both workflows in a single project.

Tip: It is recommended to read this article to learn more about the difference between managing migrations as code or configuration.

Setting migration tags inside migration groups

As seen in this article, it is possible to use set migration tags as part of the shared configuration of a group. If you do this, it is not recommended to override the migration_tags key in individual migrations. The end result might not be what you expect. Consider the following snippets as example:

# Migration group configuration entity definition.
# File: migrate_plus.migration_group.udm_config_group_json_source.yml
uuid: 78925705-a799-4749-99c9-a1725fb54def
id: udm_config_group_json_source
label: 'UD Config Group (JSON source)'
description: 'A container for migrations about individuals and their favorite books. Learn more at https://understanddrupal.com/migrations.'
source_type: 'JSON resource'
  migration_tags:
    - UD Config Group (JSON Source)
    - UD Example
# Migration configuration entity definition.
# File: migrate_plus.migration.udm_config_group_json_source_node.yml
uuid: def749e5-3ad7-480f-ba4d-9c7e17e3d789
id: udm_config_group_json_source_node
label: 'UD configuration host node migration for migration group example (JSON source)'
migration_tags:
  - UD Lorem Ipsum
migration_group: udm_config_group_json_source
source: ...
process: ...
destination: ...
migration_dependencies: ...

The group configuration declares two tags: UD Config Group (JSON Source) and UD Example. The migration configuration overrides the tags to a single value UD Lorem Ipsum. What would you expect the final value for the migration_tags key be? Is it a combination of the three tags? Is it only the one key defined in the migration configuration?

The answer in this case is not very intuitive. The final migration will have two tags: UD Lorem Ipsum and UD Example. This has to do with how Migrate Plus merges the configuration from the group into the individual migrations. It uses the array_replace_recursive() PHP function which performs the merge operation based on array keys. In this example, UD Config Group (JSON Source) and UD Lorem Ipsum have the same index in the migration_tags array. Therefore, only one value is preserved in the final result.

The examples uses the migration_tags key as it is the subject of this article, but the same applies to any nested structure. Some configurations are more critical to a migration than a tag or group. Debugging a problem like this can be tricky. But the same applies to any configuration that has a nested structure. If the end result might be ambiguous, it is preferred to avoid the situation in the first place. In general, nested structures should only be set in either the group or the migration definition file, but not both. Additionally, all the recommendations for writing migrations presented in this article also apply here.

What did you learn in today’s blog post? Did you know the difference between migration tags and groups? Share your answers in the comments. Also, I would be grateful if you shared this blog post with others.

Next: Executing Drupal migrations from the user interface with Migrate Tools

This blog post series, cross-posted at UnderstandDrupal.com as well as here on Agaric.coop, is made possible thanks to these generous sponsors. Contact Understand Drupal if your organization would like to support this documentation project, whether it is the migration series or other topics.

Overview

This training is for people who want to get a solid foundation in Drupal site building. No Drupal experience is required!

With hands-on, guided exercises from start to finish, attendees will have the opportunity to get comfortable with Drupal's administration interface, and build a simple, fully functional website.

You will learn how different concepts relate to each other: nodes, content types, fields, views, users, blocks, taxonomy terms, and menus. By the end of the training, you will be able to identify the different building blocks of a Drupal site and know where to look when modifications are needed.

Request a Private Training