Planet Drupal

Syndicate content
Drupal.org - aggregated feeds in category Planet Drupal
Updated: 13 min 18 sec ago

Dcycle: Can the exact same module code run on Drupal 7 and 8?

Tue, 02/28/2017 - 01:00
pAs the maintainer of a href=http://drupal.org/project/realistic_dummy_contentRealistic Dummy Content/a, having procrastinated long and hard before releasing a Drupal 8 version, I decided to leave my (admittedly inelegant) logic intact and abstract away the Drupal 7 code, with the goal of plugging in Drupal 7 or 8 code at runtime./p h2 id=example-original-drupal-7-codeExample original Drupal 7 code/h2 div class=highlighter-rougepre class=highlightcode// Some logic. $updated_file = file_save($drupal_file); // More logic. /code/pre /div h2 id=example-updated-codeExample updated code/h2 pHere is a simplified example of how the updated code might look:/p div class=highlighter-rougepre class=highlightcode// Some logic. $updated_file = Framework::instance()-gt;fileSave($drupal_file); // More logic. abstract class Framework { static function instance() { if (!$this-gt;instance) { if (defined('VERSION')) { $this-gt;instance = new Drupal7(); } else { $this-gt;instance = new Drupal8(); } } return $this-gt;instance; } abstract function fileSave($drupal_file); } class Drupal8 extends Framework { public function fileSave($drupal_file) { $drupal_file-gt;save(); return $drupal_file; } } class Drupal7 extends Framework { public function fileSave($drupal_file) { return file_save($drupal_file); } } /code/pre /div pOnce I have defined fileSave(), I can simply replace every instance of file_save() in my legacy code with Framework::instance()-gt;fileSave()./p pIn theory, I can then identify all Drupal 7 code my module and abstract it away./p h2 id=automated-testingAutomated testing/h2 pAs long as I emsurgically/em replace Drupal 7 code such as code class=highlighter-rougefile_save()/code with “universal” code such code class=highlighter-rougeFramework::instance()-gt;fileSave()/code, emwithout doing anything else, without giving in the impulse of “improving” the code/em, I can theoretically only test code class=highlighter-rougeFramework::instance()-gt;fileSave()/code itself on Drupal 7 and Drupal 8, and as long as both versions are the same, my underlying code should work. My approach to automated tests is: if it works and you’re not changing it, there is no need to test it./p pStill, I want to make sure my framework-specific code works as expected. To set up my testing environment, I have used Docker-compose to set up three containers: Drupal 7, Drupal 8; and MySQL. I then have a script which builds the sites, installs my module on each, then run a code class=highlighter-rougeselftest()/code function which can test the abstracted function such as code class=highlighter-rougefileSave()/code and make sure they work./p pThis can then be a href=https://circleci.com/gh/dcycle/realistic_dummy_contentrun on a continuous integration platform such as Circle CI/a which generates a cool badge:/p pa href=https://circleci.com/gh/dcycle/realistic_dummy_contentimg src=https://circleci.com/gh/dcycle/realistic_dummy_content.svg?style=svg alt=CircleCI //a/p h2 id=extending-to-backdropExtending to Backdrop/h2 pOnce your module is structured in this way, it is relatively easy to add new related frameworks, and I’m much more comfortable releasing a Drupal 9 update in 2021 (or whenever it’s ready)./p pI have included experimental Backdrop code in Realistic Dummy Content to prove the point. a href=https://backdropcms.orgBackdrop/a is a fork of Drupal 7./p div class=highlighter-rougepre class=highlightcodeabstract class Framework { static function instance() { if (!$this-gt;instance) { if (defined('BACKDROP_BOOTSTRAP_SESSION')) { $this-gt;instance = new Backdrop(); } elseif (defined('VERSION')) { $this-gt;instance = new Drupal7(); } else { $this-gt;instance = new Drupal8(); } } return $this-gt;instance; } } // Most of Backdrop's API is identical to D7, so we can only override // what differs, such as fileSave(). class Backdrop extends Drupal7 { public function fileSave($drupal_file) { file_save($drupal_file); // Unlike Drupal 7, Backdrop returns a result code, not the file itself, // in file_save(). We are expecting the file object. return $drupal_file; } } /code/pre /div h2 id=disadvantages-of-this-approachDisadvantages of this approach/h2 pHaving just released a href=http://drupal.org/project/realistic_dummy_contentRealisic Dummy Content/a 7.x-2.0-beta1 and 8.x-2.0-beta1 (which are identical), I can safely say that this approach was a lot more time-consuming than I initially thought./p pstrongDrupal 7 class autoloading/strong is incompatible with Drupal 8 autoloading. In Drupal 7, classes cannot (to my knowledge) use namespaces, and must be added to the code class=highlighter-rouge.info/code file, like this:/p div class=highlighter-rougepre class=highlightcodefiles[] = includes/MyClass.php /code/pre /div pOnce that is done, you can define MyClass in code class=highlighter-rougeincludes/MyClass.php/code, then use code class=highlighter-rougeMyClass/code anywhere you want in your code./p pDrupal 8 uses a href=https://www.drupal.org/docs/develop/coding-standards/psr-4-namespaces-and-autoloading-in-drupal-8PSR-4 autoloading with namespaces/a, so I decided to create my own autoloader to use the same system in Drupal 7, something like:/p div class=highlighter-rougepre class=highlightcodespl_autoload_register(function ($class_name) { if (defined('VERSION')) { // We are in Drupal 7. $parts = explode('\\', $class_name); // Remove Drupal from the beginning of the class name. array_shift($parts); $module = array_shift($parts); $path = 'src/' . implode('/', $parts); if ($module == 'MY_MODULE_NAME') { module_load_include('php', $module, $path); } } }); /code/pre /div pstrongHooks/strong have different signatures in Drupal 7 and 8; in my case I was lucky and the only hook I need for Drupal 7 and 8 is code class=highlighter-rougehook_entity_presave()/code which has a similar signature and can be abstracted./p pstrongDeeply-nested associative arrays/strong are a staple of Drupal 7, so a lot of legacy code expects this type of data. Shoehorning Drupal 8 to output something like Drupal 7’s code class=highlighter-rougefield_info_fields()/code, for example, was a painful experience:/p div class=highlighter-rougepre class=highlightcodepublic function fieldInfoFields() { $return = array(); $field_map = \Drupal::entityManager()-gt;getFieldMap(); foreach ($field_map as $entity_type =gt; $fields) { foreach ($fields as $field =gt; $field_info) { $return[$field]['entity_types'][$entity_type] = $entity_type; $return[$field]['field_name'] = $field; $return[$field]['type'] = $field_info['type']; $return[$field]['bundles'][$entity_type] = $field_info['bundles']; } } return $return; } /code/pre /div pFinally, making Drupal 8 work like Drupal 7 makes it hard to use Drupal 8’s advanced features such as Plugins. However, once your module is “universal”, adding Drupal 8-specific functionality might be an option./p h2 id=using-this-approach-for-website-upgradesUsing this approach for website upgrades/h2 pThis approach might remove a lot of the risk associated with complex site upgrades. Let’s say I have a Drupal 7 site with a few custom modules: each module can be made “universal” in this way. If automated tests are added for all subsequent development, migrating the functionality to Drupal 8 might be less painful./p h2 id=a-fun-proof-of-concept-or-real-valueA fun proof of concept, or real value?/h2 pI’ve been toying with this approach for some time, and had a good time (yes, that’s my definition of a good time!) implementing it, but it’s not for everyone or every project. If your usecase includes preserving legacy functionality without leveraging Drupal 8’s modern features, while reducing risk, it can have value though. The jury is still out on whether maintaining a single universal branch will really be more efficient than maintaining two separate branches for Realistic Dummy Content, and whether the approach can reduce risk during site upgrades of legacy custom code, which I plan to try on my next upgrade project./p pAs the maintainer of a href=http://drupal.org/project/realistic_dummy_contentRealistic Dummy Content/a, having procrastinated long and hard before releasing a Drupal 8 version, I decided to leave my (admittedly inelegant) logic intact and abstract away the Drupal 7 code, with the goal of plugging in Drupal 7 or 8 code at runtime./p

CU Boulder - Webcentral: Adding Simpletests To A Drupal 7 Module

Mon, 02/27/2017 - 21:28
div class=field field-name-field-image field-type-image field-label-hidden img class=image-medium src=http://www.colorado.edu/webcentral/sites/default/files/styles/medium/public/article-image/screen_shot_2017-02-07_at_2.44.23_pm.png?itok=vDfx4tbo width=600 height=301 alt=Simpletest Overview Page / /div div class=field field-name-field-image field-type-image field-label-hidden img class=image-medium src=http://www.colorado.edu/webcentral/sites/default/files/styles/medium/public/article-image/screen_shot_2017-02-16_at_10.37.57_am.png?itok=b5fev5H_ width=600 height=295 alt=Simpletest verbose message / /div div class=field field-name-field-image field-type-image field-label-hidden img class=image-medium src=http://www.colorado.edu/webcentral/sites/default/files/styles/medium/public/article-image/screen_shot_2017-02-16_at_10.33.41_am.png?itok=AUQ2l9c- width=600 height=133 alt=Test Failure / /div div class=field field-name-field-image field-type-image field-label-hidden img class=image-medium src=http://www.colorado.edu/webcentral/sites/default/files/styles/medium/public/article-image/screen_shot_2017-02-16_at_11.37.26_am.png?itok=EbjXyrvR width=600 height=282 alt=Test Results Passed / /div div class=field field-name-field-image field-type-image field-label-hidden img class=image-medium src=http://www.colorado.edu/webcentral/sites/default/files/styles/medium/public/article-image/screen_shot_2017-02-16_at_2.38.00_pm.png?itok=K_GRiUs5 width=600 height=366 alt=Adding Automated Testing / /div div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item evenpI recently inherited a module that didn't have any testing structure setup. I don't boast 100% test coverage on any of my projects and traditionally have done a poor job adding tests, but I thought I could do better with this project. While in Drupal 8 the focus is more on unit tests, in Drupal 7 Simpletestsnbsp;are the standard.nbsp;/p pThe Simpletest module was born out the Simpletest PHP library. When I went to a href=http://www.simpletest.org/the Simpletest website/a you see first in Google search results, the latest release is from 2012, and so I thought the project might be dead. However, the project now a href=https://github.com/simpletest/simpletestlives on Github/a and has development activity as recent as December 2016.nbsp;/p pThe Simpletest module was created back in the days of Drupal 6. Drupal didn't have a huge emphasis on testing back then and so part of the initial module included tests that could be run against Drupal core. As development on the Simpletest module evolved, it was moved into Drupal 7 core development and now you can see it as one of the modules included in a stock Drupal 7 install./p pIt can be confusing to see a core Testing module and then a contrib Simpletest module coexist, but for Drupal 7, you only need to use the core module. To follow along with this post, you'll need to turn on the Testing module in order to see and run your tests.nbsp;/p h2Testing Info Setup/h2 pTo begin setting up your module to run Simpletests, you first have to create a your_module.test file. It is best practice to place this file in a tests folder. You will need to add the location of this file to your module's info file in order for Drupal to find it.nbsp;/p pre code class=hljs name = Google CSE description = Use Google Custom Search to search your site and/or any other sites. core = 7.x files[] = tests/google_cse.test /code /pre pThe second part of getting Drupal to recognize your tests is the aforementioned test file. In it, you will create a class that extends the DrupalWebTestCase class and provides some basic requirednbsp;functions./p pre code class=hljs hljs-php class GoogleCSETestCase extends DrupalWebTestCase { /** * Tell Drupal about the module's tests. * * @return array * An array of information to display on Testing UI page. */ public static function getInfo() { // Note: getInfo() strings are not translated with t(). return array( 'name' =gt; 'Google CSE Tests', 'description' =gt; 'Ensure that the Google Custom Search Engine is integrated with Search API.', 'group' =gt; 'Search', ); } /code /pre pOnce you have created that file and cleared the Drupal cache, then you should see your tests in their group on admin/config/development/testing. If you don't know what group to put your tests in you can make your own; however, if you leave the group key out, your tests will appear at the top of the testing page in a blank group./p img src=https://www.colorado.edu/webcentral/sites/default/files/styles/large/public/article-image/screen_shot_2017-02-07_at_2.44.23_pm.png?itok=zvI8IQlu width=1200 height=603 alt=Simpletest Overview Page class=image-large / h2First Test Setup/h2 pNow that you can run your tests through the Drupal UI, you need to actually write a test to run. I'm not doing the whole red, green, refactor mantra since I know so little about testing, in general, and adding that level of strictness on top would just get in the way. Plus, since I'll be fixing a bug, the test will be red at first anyway even though thenbsp;code is already written for the functionality.nbsp;/p pre code /** * Perform steps to setup Drupal installation for test runs. */ public function setUp() { // Load the dependencies for the Google CSE module. $modules = array( 'google_cse', 'search', 'block', ); parent::setUp($modules); nbsp; // Eventually move more setup functions to separate testing module. // module_enable(array(google_cse_testing)); } /code /pre pEvery class extending DrupalWebTestCase has to implement a setup function. Typically, you'll pass a few modules backnbsp;to the parent class that are dependencies for your module. I knew that I would need the Search module enabled as a dependency, but you also have to enable any modules not enabled by the testing profile. I had never installed a site using that profile so it was a bit tricky knowing what I needed to enable until I looked at a vanilla site installed using the testing profile. It is a rather bare bones environment and more modules were turned off than I expected. For instance, you don't even get the Toolbar module enabled and have no content types pre-installed to work with. So, if you're scratching your head while writing a test, do yourself a favor and actually walk through your steps as the test runner would follow them; don't assume the standard profile is the same environment./p pIf you have anything else you'd like to do in the setup function, make sure you do it after passing modules back to the parent function. In the parent function, the actual installation of Drupal happens so any variable setting you do will get overwritten. Eventually, I will write a module specifically for testing that will handle any additional setup tasks, but for right now, I just want to get a test up and running.nbsp;/p h2Testing a Configuration Change/h2 pFor my first test, I had a display bug related to anbsp;specific set of configuration a user might enter. To test a fix for this, I wanted to change the configuration as a user would through the UI and then assert that thenbsp;HTML output changed as expected.nbsp;/p pre code /** * Tests all SiteSearch configuration options. */ public function testSiteSearchSettingsConfig() { // Need to have user for this test. $this-gt;setupGoogleCSEUser(); // Need to have Google CSE as default search. $this-gt;setupGoogleCSEAsDefaultSearch(); // Need to setup page with Google CSE search block until redirect issue is fixed. // @todo Figure out why going to /search/google ended up in a redirect loop. $this-gt;setupGoogleCSESearchPage(); /code /pre pI began my test with some setup tasks. These tasks could be performed in the setup function, but I wanted to abstract them and put them in individual tests since I might not need to perform these setup tasks for every test I write.nbsp;/p pYou'll see that I made a to-do related to a redirect loop I was seeing. While running Simpletests,nbsp;you will see feedback from assertions and other functions you use to prove your test is functioning as you expect. I kept seeing a 302 response while trying to browse to a path that always returned a 200 when I tried to go to it manually. Debugging that issue was maddening as I had little information to go on.nbsp;/p img src=https://www.colorado.edu/webcentral/sites/default/files/styles/large/public/article-image/screen_shot_2017-02-16_at_10.33.41_am.png?itok=G7dJSOf2 width=1200 height=267 alt=Test Failure class=image-large / pbr / From that test report, I can see the failed assertions, and I also get a nice verbose message to inspect relating to the test failures. You can choose whether or not to include verbose logging in your test runs, but for developing tests I have no reason why you would turn that setting off.nbsp;/p img src=https://www.colorado.edu/webcentral/sites/default/files/styles/medium/public/article-image/screen_shot_2017-02-16_at_10.37.57_am.png?itok=b5fev5H_ width=600 height=295 alt=Simpletest verbose message class=image-medium / pbr / ...and that's what I get from the verbose message. Great. A redirect loop can't really return much more than a blank page, and you'll notice the test report mentioned the number of bytesnbsp;loaded for each page request, which turned out to be zero bytes for this particular request. I tried to replicate the redirect loop while browsing a site installed with the testing profile, but I couldn't reproduce the redirect loop. I was losing my mind trying to figure this out so I cheated and set up the page I was trying to test a different way.nbsp;/p h2The Assertions/h2 pMy test included simulating how a user would navigate through a site and change configurations. I used two assertion functions to test that routine, a function to get a response, and a function to post to an endpoint.nbsp;/p pre code // Post to config form to save SiteSearch settings. $edit = array(); $edit['google_cse_sitesearch'] = example.com/user User Search \n example.com/node Node Search; $edit['google_cse_sitesearch_form'] = 'radios'; $this-gt;drupalPost('admin/config/search/settings', $edit, t('Save configuration')); // Go to Google CSE search page. $this-gt;drupalGet('node/1'); // Assert that all SiteSearch options are there. $this-gt;assertText('Search the web', Default SiteSearch radio button found.); $this-gt;assertText('User Search', First SiteSearch radio button found.); $this-gt;assertText('Node Search', Second SiteSearch radio button found.); // Post different config options for more checks. $edit = array(); $edit['google_cse_sitesearch_form'] = 'select'; $edit['google_cse_sitesearch_option'] = 'Search Your Site'; $edit['google_cse_sitesearch_default'] = 1; $edit['google_cse_sitesearch'] = example.com/user \n example.com/node; $this-gt;drupalPost('admin/config/search/settings', $edit, t('Save configuration')); // Go to Google CSE search page. $this-gt;drupalGet('node/1'); // Assert select options have changed. // Need to use raw option since the select list options are not visible. $this-gt;assertRaw('lt;option value=gt;Search Your Sitelt;/optiongt;', Default SiteSearch select option found.); $this-gt;assertRaw('lt;option value=example.com/user selected=selectedgt;Search amp;quot;example.com/useramp;quot;lt;/optiongt;', First SiteSearch select option found and selected.); $this-gt;assertRaw('lt;option value=example.com/nodegt;Search amp;quot;example.com/nodeamp;quot;lt;/optiongt;', Second SiteSearch select option found.); /code /pre pAs you can see above, I was simulating a change to add radio buttons or a select list to a search form and make sure that change was reflected in the rendering of the search block. To post to a form, you have to tell drupalPost() the path to the form, the form input values, and what to look for as far as a submission button.nbsp;/p pThe form input keys you will need correspond to the values you will see innbsp;$form_state['values']. As for what to post into those keys as values, I ended up looking at what was serialized in the variable table.nbsp;/p pOnce I saved the configuration values, I needed to make sure the change was reflected on a page with a search block. It is best to use assertText() while looking for changes to a page that should be visible. That function worked fine for radio buttons since the options are all displayed on the page; however, for a select list, I didn't know how to test the options that weren't visible so I used assertRaw() to test the hidden select options.nbsp;/p img src=https://www.colorado.edu/webcentral/sites/default/files/styles/medium/public/article-image/screen_shot_2017-02-16_at_11.37.26_am.png?itok=EbjXyrvR width=600 height=282 alt=Test Results Passed class=image-medium / pbr / After a little fiddling around and trial and error with my first Simpletest setup, I got to enjoy an all green test run and submit a patch with greater confidence that it actually did what it was supposed to do. Furthermore, any additional patch added to the module will test whether or not that code change breaks the configuration test I wrote and allow the maintainers to spot problems before they merge in any code.nbsp;/p h2Adding Testing To A Contrib Module/h2 pBut what if the module you're contributing to doesn't have automated testing set up? Well, if you don't maintain the module, then your out of luck. A maintainer has to enable automated testing and choose when those tests are run. Since I just took over maintainership of the module I wrote this test for, I got a crash course into how that process is done./p pYou'll first need to enable automated testing for each branch contained in your module. Under the Automated Testing tab, you'll see that you can add different testing profiles per branch. This makes sense as different versions of Drupal can require different versions of PHP and whatever database you are using, MYSQL vs. PostgreSQL vs. somenbsp;other database backend./p img src=https://www.colorado.edu/webcentral/sites/default/files/styles/medium/public/article-image/screen_shot_2017-02-16_at_2.38.00_pm.png?itok=K_GRiUs5 width=600 height=366 alt=Adding Automated Testing class=image-medium / pbr / You can also choose which branch of Drupal you'd like to test against. Don't fret over what to pick here as you can add multiple test runs for each branch. This feature comes in handy with Drupal 8 since you can test your code on the minor release that is in development as well as the stable current minor release./p pAs for when to run the tests, I always choose Run on commitnbsp;and for issues since that gives me the option of not allowing patches to be merged in without running the test suite on them first. Once you add some testing, there will be a select list next to the patch upload field that gives you options on what test profile you want to test against. You can also choose not to test it against a testing profile, but I'm not sure exactly why you would want to do that if you've actually bothered to write tests and set up automated testing.nbsp;/p pOne final note is to make sure that the issue you've uploaded a patch to has the right branch selected in the issue description. If you've tagged it for a release, say 7.x-2.4, rather than a development branch, say 7.x-2.x, then the test bot can get confused as to what branch of your code to checkout via Composer. I got burned by this at first and hadnbsp;to do some investigating to figure that out./p pAn additional area to check is the release node for the dev branch you are working on. Somehow that node didn't have a Git branch listed on my release even though that field is required. Huh? The node was made before I took over the module so I'm not sure how that happened, but if there is no Git branch listed, then the test bot can't check out the branch you want to test./p pHopefully, if you've never used Simpletest before reading this blog post, you now feel empowered and knowledgeable enough to start writing your own tests for custom and contrib modules. Happy testing, y'all!/p /div/div/div Developer Blog

OSTraining: How to Use Pathauto in Drupal 8

Mon, 02/27/2017 - 20:10
div class=ost-intro-imageimg src=https://www.ostraining.com/images/drupal8/pathauto-hd.jpg alt=How to Use Pathauto in Drupal 8 width=200 height=134 //div pMany modules have been in flux during the early stages of Drupal 8's development./p pFew modules have changed as much as Pathauto, which the vast majority of Drupal sites use to control their URLs./p pIn this tutorial, I'll show you the current way to use Pathauto with your Drupal 8 site./p

Cheeky Monkey Media: Serious Accolades Prove that We Do More Than 'Monkey' Around

Mon, 02/27/2017 - 18:34
span class=field field--name-title field--type-string field--label-hiddenSerious Accolades Prove that We Do More Than 'Monkey' Around/span div class=field field--name-field-image field--type-image field--label-hidden field__item img src=https://cheekymonkeymedia.ca/sites/default/files/2017-02/Serious%20Accolades%20Prove%20that%20We%20Do%20More%20Than%20%E2%80%9CMonkey%E2%80%9D%20Around%20-%20Blog%20image.png width=1380 height=444 alt=Serious Accolades Prove that We Do More Than 'Monkey' Around by Cheeky Monkey Media title=Serious Accolades Prove that We Do More Than 'Monkey' Around by Cheeky Monkey Media //div span class=field field--name-uid field--type-entity-reference field--label-hiddena title=View user profile. href=https://cheekymonkeymedia.ca/users/rohan class=usernamerohan/a/span span class=field field--name-created field--type-created field--label-hiddenMon, 02/27/2017 - 17:34/span div class=clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__itempAt a href=https://cheekymonkeymedia.ca/servicesCheeky Monkey,/a one of our goals is to have fun at work. After all, it's been said that the average worker spends 5 hours and 41 minutes per day at their desk, so why not make the most of it? That being said, we take our work uemvery/em/u seriously and it shows. Cheeky Monkey was recently named not only as a top web design company in Canada, but also as one of the best web developers from leading technology research firm Clutch. Yeah, we’re pretty excited about that./p/div

Drupal Modules: The One Percent: Drupal Modules: The One Percent — Range (video tutorial)

Mon, 02/27/2017 - 17:03
span class=field field--name-title field--type-string field--label-hiddenDrupal Modules: The One Percent — Range (video tutorial)/span div class=field field--name-field-screenshot field--type-image field--label-hidden field__item img src=http://gogrow.org/sites/default/files/styles/large/public/2017-02/range.png?itok=4SlsKocP width=480 height=242 alt=Project page screenshot typeof=foaf:Image class=image-style-large //div span class=field field--name-uid field--type-entity-reference field--label-hiddenspan lang= about=http://gogrow.org/user/24 typeof=schema:Person property=schema:name datatype= xml:lang=NonProfit/span/span span class=field field--name-created field--type-created field--label-hiddenMon, 02/27/2017 - 10:03/span div class=field field--name-field-episode field--type-integer field--label-inline div class=field__labelEpisode/div div class=field__item21/div /div div class=clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__itempHere is where we bring awareness to Drupal modules running on less than 1% of reporting sites. Today we'll look at Range, a module which allows you to declare a range of numeric values./p/div

Acquia Developer Center Blog: Ektron to Drupal Conversion: Content Migration

Mon, 02/27/2017 - 16:12
div class=field field-name-field-blog-image field-type-image field-label-hiddendiv class=field-itemsdiv class=field-item evenimg typeof=foaf:Image class=img-responsive src=https://dev.acquia.com/sites/default/files/styles/blog__190_x110_/public/blog/graphic-for-webinar.png?itok=yxJ5AZ2o width=140 height=85 alt=graphic for webinar //div/div/divdiv class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item even property=content:encodedpIn January of 2015, Accel-KKR, a private equity firm, combined Ektron and the Swedish company Episerver into a single company and CMS platform. This has caused many organizations to choose to migrate off the Ektron platform and onto a CMS like Drupal. Two factors are driving this trend: the high cost of an Episerver license upgrade, and the fact that the open source landscape has evolved significantly over the prior decade, to the point where many enterprise organizations (from private and public corporations to government entities) have embraced Drupal and the open source community./p/div/div/divdiv class=field field-name-field-blog-tags field-type-taxonomy-term-reference field-label-inline clearfixdiv class=field-labelTags:nbsp;/divdiv class=field-itemsdiv class=field-item evena href=/tags/acquia-drupal-planet typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=acquia drupal planet/a/div/div/div

Nuvole: Introducing Config Filter

Mon, 02/27/2017 - 15:12
div class=field field-name-field-blog-subtitle field-type-text-long field-label-hiddendiv class=field-itemsdiv class=field-item evenA new structure and new possibilities for Config Split/div/div/divdiv class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item evenpOur solution for advanced configuration management workflows has just become more powerful! The core of what makes Configuration Split work so nicely with drush and the Drupal UI has been split off in a new module: a href=https://www.drupal.org/project/config_filterConfig Filter/a! Config Filter exposes a codeConfigFilter/code plugin and swaps the sync storage applying all the active ConfigFilters to it. This means it is no longer necessary to manually swap the service as we recommended to do in the past and it works also when installing a site, as the swapping happens only when the module is installed. As of drush 8.1.10 this works with the default config import and export commands./p h3Update Config Split/h3 pFor current users of the a href=https://www.drupal.org/project/config_splitConfig Split/a module it means that they should remove the custom service swapping as part of the update and then apply the database updates which will install Config Filter (you already downloaded it with composer update, right?)./p h3New command-line options and new workflows/h3 pWith the re-factoring we also changed the options of the drush and console commands. We added a new option for specifying a split and then export to and import from only that split directory; this supersedes the previous options to specify separate export destinations and import sources - they are not needed for the simple work flow we advocate for, and the behaviour can easily be achieved by modifying codesettings.php/code as needed./p pWith the addition of the single split export, a new workflow becomes possible: export only the production split, before importing the whole configuration which will have it merged back in./p h3Improved Graylists/h3 pIn addition to the new architecture the graylist feature has been improved so that dependencies can be graylisted as well and optionally only items that differ from the sync storage are split off. More details and more documentation will come in future./p h3Roadmap/h3 pThe ultimate goal is to improve the export API in Drupal 8 core so that more advanced workflows are possible. Config Filter is our proposal for a solution in contrib, but we feel that this functionality should belong to Core./p pOn the way to Core, here are some more immediate steps:/p ulliClean up after the big refactoring, adding automated tests for some special cases./li liImprove the documentation./li liIntegrate with a href=https://www.drupal.org/project/config_readonlyConfig Readonly/a to allow locking the site except for the configuration defined in splits./li liFor those that want to do configuration management without seatbelts, integrate a href=https://www.drupal.org/project/config_ignoreConfig Ignore/a with Config Filter so that it can work smoothly next to Config Split./li li...and eventually propose Config Filter for inclusion in Core!/li /ulh3More information and acknowledgments/h3 pThe re-factoring started during the Drupal Mountain Camp in Davos and I would like to thank the organizing committee for the great event. On Friday I gave a presentation about my favorite topic in Drupal: a href=https://drupalmountaincamp.ch/sessions/configuration-management-without-problemsConfiguration Management/a, attached here are the a href=http://nuvole.org/sites/default/files/ConfigurationManagement_no-problems_davos17.pdfslides/a based on the Nuvole presentation at DrupalCon Dublin 2016./p pFor any further information see the module pages for a href=https://www.drupal.org/project/config_splitConfig Split/a and a href=https://www.drupal.org/project/config_filterConfig Filter/a and their a href=https://www.drupal.org/project/issues/config_filter?categories=Allissue/a a href=https://www.drupal.org/project/issues/config_split?categories=Allqueues/a./p /div/div/divdiv class=field field-name-field-blog-tags field-type-taxonomy-term-reference field-label-inline clearfixdiv class=field-labelTags:nbsp;/divdiv class=field-itemsdiv class=field-item evenDrupal 8/divdiv class=field-item oddDrupal Planet/divdiv class=field-item evenCode Driven Development/div/div/divdiv class=field field-name-field-blog-attachments field-type-file field-label-abovediv class=field-labelAttachments:nbsp;/divdiv class=field-itemsdiv class=field-item evenspan class=fileimg class=file-icon alt= title=application/pdf src=/modules/file/icons/application-pdf.png / a href=http://nuvole.org/sites/default/files/ConfigurationManagement_no-problems_davos17.pdf type=application/pdf; length=1202397ConfigurationManagement_no-problems_davos17.pdf/a/span/div/div/div

DrupalEasy: Florida DrupalCamp 2017 Recap; Bigger in All Dimensions

Mon, 02/27/2017 - 14:05
pimg alt=People in auditorium data-entity-type=file data-entity-uuid=9371b277-ad28-4570-a98a-146ede741007 src=https://www.drupaleasy.com/sites/drupaleasy.com/files/inline-images/32138221524_e6d6fda10a_z_kurt.jpg //p pLast weekend the Florida Drupal community hosted its ninth annual Florida DrupalCamp (FLDC) at a href=http://www.ftccollege.edu/Florida Technical College/a in Orlando.  It was a great success. At this point, we (the organizers) have a pretty good idea how to put on this event. (Since a good number of us have been involved in all nine iterations, (and all still seem to like each other!) some aspects of the camp organizing process are on veritable auto-pilot./p pIf you're a camp organizer, you know what goes into securing sponsors and a location, spreading the word, finding presenters, arranging for swag and catering, etc… For this year's event, we wanted to step things up a bit by focusing on three things: more learning, more fun, and more networking. Based on feedback and our own experiences, we feel like we achieved all three goals with some changes from previous years' camp recipes./p h2More Learning/h2 pIn the past, FLDC has been a 2-day event; Saturday has been the main event - a day full of sessions, while Sunday has been a community day with sprints, Coding for a Cause, BoFs, and a generally less-defined schedule. /p pThis year we decided we stepped it up to a full-on three-day event; full-day training workshops on Friday, sessions on Saturday and Sunday, as well as a professionally mentored code sprint on Sunday. /p pimg alt=Adam Bergstein session data-entity-type=file data-entity-uuid=b282fd21-63b0-4d26-9038-7e3d733c8e80 src=https://www.drupaleasy.com/sites/drupaleasy.com/files/inline-images/C49ezYVWEAI84sa_cathy.jpg //p pWith the generosity of five trainers, we were able to provide full-day workshops to almost 80 people on Friday. Many, many, many thanks to our trainers:/p ulliIntroduction to Drupal 8 Theme Development - a href=https://www.drupal.org/u/pixeliteSuzanne Dergacheva/a, a href=https://evolvingweb.ca/Evolving Web/a.  /li liIntroduction to Drupal 8 - a href=https://www.drupal.org/u/ultimikeMichael Anello/a, a href=https://www.drupaleasy.comDrupalEasy/a.  /li liIntroduction to DrupalVM - a href=https://www.drupal.org/u/bhosmerBen Hosmer/a.  /li liDocker for Development with Drupal - a href=https://www.drupal.org/u/lhridleyLisa Ridley/a, a href=https://www.prometsource.com/Promet Source/a.  /li liBeginning ReactJS - a href=https://www.linkedin.com/in/john-tucker-23b09458/John Tucker/a.  /li /ulpimg alt=Code sprint data-entity-type=file data-entity-uuid=e8f1b53f-9b57-4a85-839b-d45ee6d5499b src=https://www.drupaleasy.com/sites/drupaleasy.com/files/inline-images/C5DT-JVXUAM4BFW_herchel.jpg //p pThe other change to facilitate more learning is to provide experienced sprint mentors for our Sunday sprint. With a nudge or two (maybe three) from a href=https://www.drupal.org/u/xjmxjm/a, we decided to have a a href=http://xjmdrupal.org/blog/triage-majors-at-campsMajor Issue Triage Sprint/a at this year's camp. We brought in a href=https://www.drupal.org/u/yesct)YesCT/a and a href=https://www.drupal.org/u/nerdsteinnerdstein/a to mentor the sprinters to great success. During the Sunday sprint, we were able to make progress on well over 20 Drupal core major issues./p pFinally, we decided to bring in a href=https://www.drupal.org/u/kthullKevin Thull/a (a href=https://twitter.com/kevinjthull@kevinjthull/a) to handle all the session recording, processing, and uploading for the event. Kevin's a href=http://www.bluedropshop.com/blog/drupal-camp-session-recordings-year-reviewwork with recording other Drupal events/a is top-notch. Having all of our sessions recorded will allow those who weren't able to attend (or those who did attend but couldn't make a particular session) to be able to benefit from our speakers. All of the sessions are currently posted on our a href=https://www.fldrupal.camp/schedule/satwebsite schedule/a, as well as on our a href=https://www.youtube.com/channel/UCNUknlPg9wDNfo4nMVQK3aQ/videosYoutube channel/a./p h2More Networking/h2 pTraditionally, we have always had a full-day beginner track on the main day of the camp. This had the effect of keeping the vast majority of the beginners in the same room all day - limiting their networking opportunities. By having a full-day introductory workshop on Friday, beginners became fully-involved in camp activities the rest of the weekend. The feedback we received from this change is overwhelmingly positive./p pThe other big-ish change aimed at more networking was to increase the amount of time between each session to a full 30 minutes. This had the side-effect of us having fewer sessions on Saturday, but was mitigated by adding a half-day of sessions on Sunday. Again, the response we received from this change was overwhelmingly positive. It provided a less rushed day for all attendees, gave presenters a little more leeway if they went a few minutes over their allotted window, and provided ample time for the hallway track. In addition, our sponsors strongloved/strong this change, as it gave attendees more time to stop and chat with sponsors in our exhibition area. /p pDuring the closing session, we announced that any leftover funds from the event can (and should!) be used by Florida local meetup organizers to promote and grow their local meetups. In the past, we've informally made these funds available, but we're going all-in this year. If you're a Florida Drupal meetup organizer, we have $$$ for you for a href=https://www.meetup.com/meetup.com/a memberships, food for your meetups, or just about anything else that will help you grow your local community. Look for more details on https://groups.drupal.org/florida soon.  /p h2More Fun/h2 pWhile Drupal events tend to be very positive events for all attendees, we made the conscious decision to ensure that we maximized the enjoyment of our attendees while we kept the Drupal knowledge flowing. It was also very important to us that we make a positive first impression on those new to Drupal and attending one of their first Drupal events. We wanted folks to be able to leave the event with positive feelings for the Florida Drupal community. /p pimg alt=Networking at the after party. data-entity-type=file data-entity-uuid=84bd7eb8-c8b9-41f8-bad4-a983ec3fda64 src=https://www.drupaleasy.com/sites/drupaleasy.com/files/inline-images/C4_kE15WAAETBaj_anello.jpg //p pTo this end, we increased the fun factor in several ways. First off, we further official-ized our Friday night dinner gathering. Over the past few years, organizers and a few others have always gathered at a href=http://alafaya.bubbalous.com/Bubbalou's/a a local BBQ restaurant just down the street from the camp venue after prepping the venue for the event. This year, with the full-day trainings on Friday, we invited everyone to meet up at the restaurant for a pay-on-your-own dinner. This turned into a wonderful, casual evening for well over 75 people. The restaurant has a large indoor/outdoor picnic table eating area, perfect for networking. /p pimg alt=Suzanne Dergacheva with Skywalker data-entity-type=file data-entity-uuid=a1f4c1e1-52de-45b5-a726-bea298239b4b src=https://www.drupaleasy.com/sites/drupaleasy.com/files/inline-images/C49Cea3UEAAEb86_suzanne.jpg //p pOn Saturday, we set the tone early and put smiles on people's faces from the very start. We worked with the folks from a href=http://www.gatorland.com/Gatorland/a to have a professional animal handler and a friendly alligator named Skywalker on-hand to greet guests when they arrived. Many attendees went for a cuddle with Skywalker even before getting coffee. /p pimg alt=Druplicon chocolates data-entity-type=file data-entity-uuid=26e6f585-e9c7-42e2-9a0a-f36763c67935 src=https://www.drupaleasy.com/sites/drupaleasy.com/files/inline-images/C4-RduyWQAMoyDR_george.jpg //p pAdditionally, we wanted to provide unique swag to our attendees. A former attendee of previous Florida DrupalCamps, Kathryn Neel, is now running custom chocolate business, a href=http://sapphochocolatesllc.com.45-33-30-249.ionnovative.com/Sappho Chocolates/a. We worked with her company to create Druplicon chocolates for all attendees. As part of the process, we funded the development of the custom molds for the Druplicon chocolates, so if any other Drupal event organizers want to order chocolates for their event, the molds are there for your use!/p pFinally, for the last Saturday session, we went with a single session of lightning talks. This ended up being one of the highlights of the weekend, as we had a some strongamazing/strong 5 minutes talks. With most of the camp attendees in the room, it left everyone with smiles on their faces and provided a great transition to the closing session and after party. /p h2Sponsor Happiness/h2 pMost camp organizers always have trepidation about camp finances right up to the actual event. Sponsor needs have evolved as the Drupal community has evolved, and camp organizers have to evolve as well. Today's Drupal event sponsors are more focused on getting a return-on-investment from their sponsorship dollars than ever before, so it is up to event organizers to do everything they can to make that happen. /p pBy providing more time for attendees to visit sponsor tables as well as the opportunity for Platinum and Gold sponsors to receive an opt-in version of our attendee list, as well as all of the other standard sponsor benefits, the feedback from our sponsors has been very positive. Additionally, we gave Platinum and Gold sponsors the opportunity to place text ads in our emails to attendees leading up to the camp./p pimg alt=Achieve Agency logo data-entity-type=file data-entity-uuid=e3ffd3cf-fc9c-47a1-a8d9-91cdada2dafd src=https://www.drupaleasy.com/sites/drupaleasy.com/files/inline-images/Achieve_FullLogo_FullColor.png //p pOur Platinum sponsor, a href=http://www.achieveagency.com/Achieve Agency/a is a newly-formed Florida digital agency based in West Palm Beach. a href=https://www.drupal.org/u/studdmanJohn Studdard/a, their COO (and formerly of Big Couch Media), has been a long-time FLDC supporter and attendee, and wanted to use FLDC as a vehicle to announce Achieve Agency to the community. As event organizers, we couldn't be happier that our top-level sponsor is a Florida-based organization. /p h2Featured Speakers/h2 pimg alt=Megan Sanicki at FLDC17. data-entity-type=file data-entity-uuid=c720a5a8-f68f-444d-86ab-2470ac853f7c src=https://www.drupaleasy.com/sites/drupaleasy.com/files/inline-images/C49dsUpXUAEkO48_cathy.jpg //p pKeeping with our tradition of not having a single keynote speaker (mainly due to the fact that our venue's auditorium can't accommodate all attendees, we invited three featured speakers to this year's event. We were lucky to get our top three choices - check out their (recorded) sessions below:/p ullia href=https://www.drupal.org/u/megansanickiMegan Sanicki/a, Executive Director of the a href=https://www.drupal.org/associationDrupal Association/a - a href=https://www.fldrupal.camp/sessions/approved/florida-drupalcamp-2017/beginner-track/featured-session-keeping-drupal-communityKeeping the Drupal Community Alive and Thriving/a.  /li lia href=https://www.drupal.org/u/helenasueHelena McCabe/a - accessibility expert, a href=https://www.lullabot.comLullabot/a - a href=https://www.fldrupal.camp/sessions/approved/florida-drupalcamp-2017/design-theming-front-end-development/featured-sessionIn Their Own Words: Accessibility Stories/a and a href=https://www.fldrupal.camp/sessions/approved/florida-drupalcamp-2017/design-theming-front-end-development/accessibility-auditAccessibility Audit and Case Study/a.  /li lia href=https://www.drupal.org/u/pixeliteSuzanne Dergacheva/a - co-founder and front-end developer, a href=https://evolvingweb.ca/Evolving Web/a - a href=https://www.fldrupal.camp/sessions/approved/florida-drupalcamp-2017/site-building/featured-session-creating-landing-pages-andCreating Landing Pages and Layouts for Drupal 8/a.  /li /ulh2Room for Improvement/h2 pAs always, our post-camp organizer retrospective highlights a few areas we need to address for next year's event./p ulliHave a printer on-hand for printing emergencies.  /li liFind a volunteer to arrange for food donations for left-overs.  /li liFigure out a magical solution for badges that will make everyone happy.  /li liFind a new official hotel: We had a fair number of complaints.  /li liFigure out a way to improve the slow service at the after-party.  /li /ulh2Quick hits/h2 ulliCamp attendance was a bit more than last year. Overall, we had 251 registered attendees. A bit more than 100 participated on Friday, almost 200 participated on Saturday, and about 100 participated on Sunday.  /li liCamp budget was about $18,000, the majority went to catering, but we also had significant costs for featured speakers and sprint leads travel and swag.  /li liWe had a total of 17 fiscal sponsors which provided about two-thirds of our income.  /li liThe registration fee for attendees was $35 ($25 early-bird), with an optional $25 individual sponsorship. We had 41 individual sponsors.  /li liOur camp organizing volunteers are way better than yours.  /li liWe invested a bit this year in large signage that we can re-use in future years.  /li liAnother change this year - volunteers got in for free (sorry this took so long).  /li liWe had attendees from 9 countries and 19 states.  /li /ulh2Summary/h2 pWhat more can we say? Florida DrupalCamp 2017 was a huge success. Our volunteers are the best, our sponsors are the best, and the Florida community is the best!/p pBe on the lookout for an announcement about the dates for Florida DrupalCamp 2018 by a href=http://eepurl.com/bUXSmPjoining our mailing list/a and following us on a href=https://twitter.com/fldrupalcampTwitter/a!/pdiv class=feedflare a href=http://feeds.feedburner.com/~ff/DrupalEasy?a=tklxZnxXBxM:A2d0cgjonJs:yIl2AUoC8zAimg src=http://feeds.feedburner.com/~ff/DrupalEasy?d=yIl2AUoC8zA border=0/img/a a href=http://feeds.feedburner.com/~ff/DrupalEasy?a=tklxZnxXBxM:A2d0cgjonJs:qj6IDK7rITsimg src=http://feeds.feedburner.com/~ff/DrupalEasy?d=qj6IDK7rITs border=0/img/a /divimg src=http://feeds.feedburner.com/~r/DrupalEasy/~4/tklxZnxXBxM height=1 width=1 alt=/

Web Omelette: Query for entities using dates in Drupal 8

Mon, 02/27/2017 - 09:38
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item evenpDates have always been a tricky thing to manage in Drupal. Even in PHP. PHP 5.2 introduced the codeDateTimeInterface/code which makes handling dates, date ranges, intervals, comparisons etc much easier. However, we always still have the complication of data storage, formatting and different timezones management./p pIn this article we are going to look at how we can run some entity queries in Drupal 8 using the Date field in our conditions. The requirement for returning entities which have a date field with a value between certain hours is definitely not an edge case, and although seems like an easy task, it can be tricky./p pimg src=https://www.webomelette.com/sites/default/files/field/image/clock-650753_1920.jpg alt=Query for entities using dates in Drupal 8 title=Query for entities using dates in Drupal 8 //p pImagine a simple date field on the Node entity which stores date and time. By default in Drupal 8, the storage for this date is in the format codeY-m-d\TH:i:s/code and the timezone is UTC. However, the site timezone is rarely UTC and we very well may have users choosing their own timezones. So we need to construct our node queries carefully if we want reliable results./p pRunning a codedb_query()/code type of query for returning nodes with the date in a certain range would be a pain at best and impossible at worst. Luckily though, we can, and should always in Drupal 8 try to rely on the codeentity.query/code service when looking for entities./p pSo let's see a couple of examples./p pFirst, an easy one: how do we query for all the nodes which have the codefield_date/code value in the future./p pre class=brush: php$now = new DrupalDateTime('now'); $query = \Drupal::entityQuery('node'); $query-gt;condition('field_date', $now-gt;format(DATETIME_DATETIME_STORAGE_FORMAT), 'gt;='); $results = $query-gt;execute(); /prepA few things to notice. First, we are using the Drupal wrapper of code\DateTime/code and constructing an object to represent our current time. Then we create our entity query and for the date field condition we pass the storage format so that it can be compared to what is being stored. And the regular operators here allow us to find the right entities./p pThere is one problem with this though. When creating the codeDrupalDateTime/code, the site default timezone is used. So if our timezone is not UTC, the query will suffer because we are essentially comparing apples with oranges. And the further away from UTC we are, the more apples start to become compared to cars and airplanes./p pTo fix this, we need to set the timezone to UTC before running the query./p pre class=brush: php$now = new DrupalDateTime('now'); $now-gt;setTimezone(new \DateTimeZone(DATETIME_STORAGE_TIMEZONE)); /prepAnd emthen/em use code$now/code in the query. The subtle difference to understand is that we are creating code$now/code totally relative to where we are (the site timezone) because we are interested in finding nodes in the future from us, not from from another timezone. However, we then convert it so that we can have them compared properly in the query./p pA more complex example could be a range of times. Let's say we want all the nodes with the time of today between 16:00 and 18:00 (a 2 hour span)./p pI prefer to work directly with code\DateTime/code and then wrap it into the Drupal wrapper just because i can have all the native methods highlighted by my IDE. So we can do something like this:/p pre class=brush: php$timezone = drupal_get_user_timezone(); $start = new \DateTime('now', new \DateTimezone($timezone)); $start-gt;setTime(16,0); $start-gt;setTimezone(new \DateTimeZone(DATETIME_STORAGE_TIMEZONE)); $start = DrupalDateTime::createFromDateTime($start); $end = new \DateTime('now', new \DateTimezone($timezone)); $end-gt;setTime(18, 0); $end-gt;setTimezone(new \DateTimeZone(DATETIME_STORAGE_TIMEZONE)); $end = DrupalDateTime::createFromDateTime($end); $query = \Drupal::entityQuery('node'); $query -gt;condition('field_date', $start-gt;format(DATETIME_DATETIME_STORAGE_FORMAT), 'gt;=') -gt;condition('field_date', $end-gt;format(DATETIME_DATETIME_STORAGE_FORMAT), 'lt;='); $results = $query-gt;execute(); /prepSo first, we get the user timezone. codedrupal_get_user_timezone()/code returns for us the string representation of the timezone the current user has selected, or if they haven't, the site default timezone. Based on that, we create our native date object that represents the current point in time but set the actual time to 16:00. After that we set the storage timezone and create our Drupal wrapper so that we can format it for the query./p pFor the end date we do the same thing but we set a different time. Then we expectedly write our query conditions and ask for the entities which have a date between those 2 times./p pThe order of setting the time and timezone on the date object is important. We want to set the time before we set the timezone because the times we are looking for are relative to the current user, not to the storage timezone./p pSo that is pretty much it. Now you can query for entities and play with date fields without issues (hopefully)./p /div/div/div

fluffy.pro. Drupal Developer's blog: Panels: custom style plugin

Sat, 02/25/2017 - 22:15
div dir=ltr style=text-align: left; trbidi=onPanels style plugins are made for wrapping panel panes and panel regions into extra markup. 99% of your needs are covered by a a href=https://www.drupal.org/project/panels_extra_styles target=_blankquot;Panels Extra Stylesquot;/a module. Please look at that module if you need extra styles for panels. But if you need some specific style you can easily implement it.br/diva href=http://www.fluffy.pro/2017/02/panels-custom-style-plugin.html#moreRead more »/a

The Jibe: Creating your own Slideshow and Content tabs with Drupal 8 Theme Libraries and Slick at the Pacific Northwest Drupal Summit

Sat, 02/25/2017 - 21:22
span property=schema:nameCreating your own Slideshow and Content tabs with Drupal 8 Theme Libraries and Slick at the Pacific Northwest Drupal Summit/span span rel=schema:authorspan lang= about=https://thejibe.com/user/2 typeof=schema:Person property=schema:name datatype= xml:lang=Leah Wagner/span/span span property=schema:dateCreated content=2017-02-25T20:22:02+00:00February 25, 2017 12:22pm/span

Chris Hall on Drupal 8: Bursting the Drupal Bubble

Sat, 02/25/2017 - 20:16
spanBursting the Drupal Bubble/span spanspanchrishu/span/span spanSat, 02/25/2017 - 19:16/span divh2Introduction/h2 pI have been working with Drupal for over six years now, for much of that period exclusively working with Drupal as an employee or in a freelance/contract role./p pPrior to the start of Drupal 8, the nearest thing I manged to a href=http://www.garfieldtech.com/blog/off-the-island-2013getting off of the island /a was periods of doing something completely different (Expression Engine, Django, a custom PHP framework, attending a Silverstripe conference), usually because of an existing or already started/inherited project connected with the Drupally people I was working with./p pThese sabbaticals were reasonably short, however often instructive and enjoyable, in some cases (not all) the feeling was 'could have been better done in Drupal', they were a complete break from Drupal./p pI have just finished ten months of working on a Symfony based project and things are very different. /p h2Bursting the Drupal Bubble/h2 pFor almost a year, I have not been doing Drupal, but also so busy and involved learning more about Symfony, Angular 2 and other technologies that I have not had time or capacity to attend Drupal events, meetups etc. /p pAlthough working with a group of people that had all used Drupal a lot before (amongst other things), Drupal was very rarely mentioned, not one person said 'this could have been done better in Drupal' in fact the only time that really came up at all was in reference to other client systems that were integrating with what we were building./p pI needed to burst the bubble, forget about Drupal and whilst working on something different spend my time thinking about that./p pThe bubble I am referring to is thinking about everything in the context of Drupal, even the proudly invented elsewhere bits in Drupal 8. This kind of thinking can perhaps have the same bad effects as the echo chambers on social networks where everyone you are connected to has essentially the same or similar references and experiences./p pThere is a possibility that the next contract I do will not be Drupal either./p h2Drupal is still there/h2 pUsing Symfony and anything using Symfony components (Laravel may be next) still increases knowledge and skills related to Drupal (before 8 anything elsewhere just meant Drupal relevant knowledge was fading over time). Having used the Symfony console a lot and written commands for it, I will be pouncing on the a href=https://drupalconsole.com/Drupal Console/a when I do my next piece of Drupal work for example (which is more than I can say for Drush)./p pI am clearer about what I think Drupal strengths are though. I current have two personal projects I want to start/finish, one is a match for Drupal one for Symfony./p h2Conclusion/h2 pMileage may differ for other people, I found I had to put Drupal to one side for a while, it is all very well getting off the Island but that is not quite so effective if you remain in an Island culture ghetto somewhere on the mainland and don't fully integrate for a while. Some people will have no need to ever get off at all, we all have different stories to tell./p pHowever if you do come across some work that would be better done in something else, will you even know? If you do know will you have the courage to burst the bubble?/p/div section id=comment-sectionh2Add new comment/h2 drupal-render-placeholder callback=comment.lazy_builders:renderForm arguments=0=node1=392=comment3=comment token=830f3ce1/drupal-render-placeholder/section

3C Web Services: Introducing the Commerce Abandoned Carts module

Sat, 02/25/2017 - 19:18
Users abandoned their shopping carts before completing the checkout process results potential lost sales. This module allows you to automate the sending of emails to users who have abandoned their carts, thereby allowing you to remind them of the incomplete checkout and/or provide additional information to them.

DrupalCon News: Announcing 161 sessions of diverse speakers, new perspectives, and top-notch topics for DrupalCon programming

Sat, 02/25/2017 - 00:00
div class=field field--name-body field--type-text-with-summary field--label-hiddendiv class=field__itemsdiv class=field__item evenpOne of the most exciting aspects of preparing for a DrupalCon is selecting its sessions. It’s always incredibly impressive and humbling to see the great ideas that our community comes up with—and they’re all so great that making the official selections is definitely not an easy process!/p pThis time, the a href=https://events.drupal.org/baltimore2017/teamTrack Chairs/a had over 600 sessions to evaluate, and only 139 hours worth of time to fit. With the addition of the 25-minute talk option, we were able to accept 161 sessions to fill our programming time./p/div/div/div

Drupal Association blog: Meet the Drupal Association At-Large Board Member Candidates

Fri, 02/24/2017 - 22:59
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item evenp id=docs-internal-guid-70a7cf53-7215-ad8c-2c0f-6d992e9a4de0Did you know you have a say in who is on the Drupal Association Board? Each year, the Drupal community votes in a member who serves two years on the board. It’s your chance to decide which community voice you want to represent you in discussions that set the strategic direction for the Drupal Association. a href=https://assoc.drupal.org/drupal-association-board-elections rel=nofollowGo here for more details./a/p pVoting takes place from March 6 - March 18. Anyone who has a Drupal.org profile page and has logged in to their account in the last year is eligible to vote. This year, there are many candidates from around the world. Now it’s time for you to meet them./p h2Meet the candidates/h2 p id=docs-internal-guid-70a7cf53-7215-c94e-ed79-1ea13a746b92We just concluded the phase where a href=https://assoc.drupal.org/election/18/candidates rel=nofollow13 candidates nominated themselves/a for the board seat. From now through March 4, 2017 we encourage you to check out each person’s candidate profile, where they explain which board discussion topics they are most passionate about and what perspectives they will bring to the board./p pThis year, we asked candidates to include a short video - a statement of candidacy - that summarizes why you should vote for them. Be sure to check them out. Videos are found in the candidate’s profile as well as here:/p pimg alt=Screenshot of candidates profile page with arrow to highlight video link height=370 src=/files/candidates_2017.png width=500 //p h2 id=docs-internal-guid-70a7cf53-721c-c12e-e2bf-241bbe78be0aWhat To Consider/h2 pWhen reviewing the candidates, it is helpful to know what the board is focusing on over the next year or two, so you can decide who can best represent you./p pHere are the key topics the board will focus on./p ulli pStrengthening Drupal Association’s sustainability. The board discusses how the Association can improve its financial health while expanding its mission work./p /li li pUnderstanding what the Project needs to move forward and determine how the Association can help meet those needs through Drupal.org and DrupalCon./p /li li pGrowing Drupal adoption through our own channels and partner channels./p /li li pDeveloping the strategic direction for DrupalCon and Drupal.org./p /li /ulpThere are certain duties that a candidate must be able to perform as a board member. The three legal obligations are a href=http://www.bridgespan.org/Publications-and-Tools/Nonprofit-Boards/Nonprofit-Boards-101/Legal-Responsibilities-Nonprofit-Boards.aspx#.U-GZiYBdWPc rel=nofollowduty of care, duty of loyalty, and duty of obedience/a. In addition to these legal obligations, there is a lot of practical work that the board undertakes. These generally fall under the a href=http://www.bridgespan.org/Publications-and-Tools/Nonprofit-Boards/Nonprofit-Boards-101/Fiduciary-Responsibilities-Board-Members.aspx#.U-GZ7YBdWPc rel=nofollowfiduciary responsibilities/a and include:/p ulli pOverseeing Financial Performance/p /li li pSetting Strategy/p /li li pSetting and Reviewing Legal Policies/p /li li pFundraising/p /li li pManaging the Executive Director/p /li /ulp id=docs-internal-guid-70a7cf53-7216-446a-4347-206c11d5668cHopefully providing this context gives you a helpful way to assess the candidates as you decide how to vote from March 6 - March 18./p pemWe encourage you to ask the candidates questions. Use comments to leave a question on their /ema href=https://assoc.drupal.org/election/18/candidates rel=nofollowemcandidate profile page/em/aem. /em/p/div/div/div

Acquia Lightning Blog: Extending Lightning - Part II

Fri, 02/24/2017 - 18:48
span class=field field--name-title field--type-string field--label-hiddenExtending Lightning - Part II/span span class=field field--name-uid field--type-entity-reference field--label-hiddenspan lang= about=http://lightning.acquia.com/user/1 typeof=schema:Person property=schema:name datatype= xml:lang=Adam Balsam/span/span span class=field field--name-created field--type-created field--label-hiddenFri, 02/24/2017 - 12:48/span div class=clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__itemh3History/h3 pOne of the problems with Drupal distributions is that they, by nature, contain an installation profile — and Drupal sites can only have one profile. That means that consumers of a distribution give up the ability to easily customize the out of the box experience./p pThis was fine when profiles were first conceived. The original goal was to provide “ready-made downloadable packages with their own focus and vision”. The out of the box experience was customized by the profile, and then the app was built on top of that starting point. But customizing the out of the box experience is no longer reserved for those of us that create distributions for others to use as a starting point. It’s become a critical part of testing and continuous integration. Everyone involved in a project, including the CI server, needs a way to reliably and quickly build the application from a single command. Predictably, developers have looked to the installation profile to handle this./p pThis practice has become so ubiquitous, that I recently saw a senior architect refer to it as “emthe normal Drupal paradigm of each project having their own install profile/em”. Clearly, if distributions want to be a part of the modern Drupal landscape, they need to solve the problem of profiles./p h3Old Approach/h3 pIn July 2016, Lightning introduced a href=https://github.com/acquia/lightning/blob/63ce3b2b23138a25a280d34c2a240b83ed288fba/lightning.extend.ymllightning.extend.yml/a which enabled site builders to:/p olliInstall additional modules after Lightning had finished its installation/li liExclude certain Lightning components/li liRedirect users to a custom URL upon completion/li /olpThis worked quite well. It gave site builders the ability to fully customize the out of the box experience via contrib modules, custom code, and configuration. It even allowed them to present users with a custom “Installation Done” page if they chose — giving the illusion of a custom install profile./p pBut it didn’t allow developers to take full control over the install process and screens. It didn’t allow them to organize their code they way they would like. And it didn’t follow the “emnormal Drupal paradigm”/em of having an installation profile for each project./p h3New Approach/h3 pAfter much debate, the Lightning team has decided to embrace the a href=https://www.drupal.org/node/1356276concept of “inheriting” profiles/a. AKA sub-profiles. (/throws confetti)/p pThis is not a new idea and we owe a huge thanks to those that have contributed to the current patch and kept the issue alive for over five years. Nor is it a done deal. It still needs to get committed which, at this point, means Drupal 8.4.x./p pOn a technical level, this means that — similar to sub-themes — you can place the following in your own installation profile’s *.info.yml file and immediately start building a distribution (or simply a profile) on top of Lightning:/p pre strongbase profile: name: /stronglightning/pre pTo encourage developers to use this method, we will also be including a DrupalConsole command that interactively helps you construct a sub-profile and a script which will convert your old lightning.extend.yml file to the equivalent sub-profile./p article class=embedded-entityarticle class=media media-image view-mode-defaultdiv class=field field--name-image field--type-image field--label-hidden field__item img src=http://lightning.acquia.com/sites/default/files/lightning-subprofile-command.gif width=570 height=366 alt= typeof=foaf:Image //div /article/articlepThis change will require some rearchitecting of Lightning itself. Mainly to remove the custom extension selection logic we had implements and replace it with standard dependencies./p pThis is all currently planned for the 2.0.5 release of lightning which is due out in mid March. Stay tuned for updates./p/div

Jeff Geerling's Blog: Thoughts on the Acquia Certified Front end Specialist - Drupal 8 Exam

Fri, 02/24/2017 - 17:58
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item even property=content:encodedpAnother day, another Acquia Developer Certification exam review (see the previous one: a href=/blog/2017/thoughts-on-acquia-certified-back-end-specialist-drupal-8-examCertified Back end Specialist - Drupal 8/a, I recently took the a href=https://www.acquia.com/customer-success/learning-services/acquia-certified-front-end-specialist-d8-exam-blueprintFront End Specialist – Drupal 8 Exam/a, so I'll post some brief thoughts on the exam below./p pimg src=//www.jeffgeerling.com/sites/jeffgeerling.com/files/images/acquia-front-end-specialist-drupal-8-exam-badge.png width=175 height=175 alt=Acquia Certified Front End Specialist - Drupal 8 Exam Badge class=insert-image //p/div/div/div

Drupal core announcements: 8.3.0 release candidate phase begins week of February 27; no Drupal 8.2.x or 7.x patch release planned

Fri, 02/24/2017 - 17:08
h3Drupal 8.3.0 release candidate phase/h3 pThe release candidate phase for the 8.3.0 minor release begins the week of February 27. Starting that week, the 8.3.x branch will be subject to a href=https://www.drupal.org/core/d8-allowed-changes#rcrelease candidate restrictions/a, with only critical fixes and certain other limited changes allowed./p p8.3.x includes new experimental modules for workflows, layout discovery and field layouts; raises stability of the BigPipe module to stable and the Migrate module to beta; and includes several REST, content moderation, authoring experience, performance, and testing improvements among other things. You can read a detailed list of improvements in the announcements of a href=/project/drupal/releases/8.3.0-alpha1alpha1/a and a href=/project/drupal/releases/8.3.0-beta1beta1/a./p pMinor versions may include changes to user interfaces, translatable strings, themes, internal APIs like render arrays and controllers, etc. (See the a href=https://www.drupal.org/core/d8-bc-policyDrupal 8 backwards compatibility and internal API policy/a for details.) Developers and site owners should test the release candidate to prepare for these changes./p p8.4.x will remain open for new development during the 8.3.x release candidate phase./p pDrupal 8.3.0 will be released on April 5th, 2017./p h3No Drupal 8.2.x or 7.x releases planned/h3 pMarch 1 is also a monthly core patch (bug fix) release window for Drupal 8 and 7, but no patch release is planned. This is also the final bug fix release window for 8.2.x (meaning 8.2.x will not receive further development or support aside from its final security release window on March 15). Sites should plan to update to Drupal 8.3.0 on April 5./p pFor more information on Drupal core release windows, see the documentation on a href=http://drupal.org/documentation/version-info#whenrelease timing/a and a href=http://drupal.org/node/1173280security releases/a, as well as the a href=https://www.drupal.org/core/release-cycle-overviewDrupal core release cycle overview/a./p

CiviCRM Blog: The quest for performance improvements - 6th sprint

Fri, 02/24/2017 - 14:59
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item even property=content:encoded pIn this blog I want to explain the round up we have done around the refactoring of the acl_contact_cache. In the previous sprints we discovered that a lot of the performance was slowed down by the way the acl_contact_cache was used (or rather not used at all). See also the previous blog post: a href=https://civicrm.org/blog/jaapjansma/the-quest-for-performance-improvements-5th-sprinthttps://civicrm.org/blog/jaapjansma/the-quest-for-performance-improvements-5th-sprint/a/p pAt the socialist party they have 350.000 contacts and around 300 users who can access civicrm. Most of the users are only allowed to see only the members in their local chapter./p pIn the previous blog we explained the proof of concept. We now have implemented this proof of concept and the average performance increase was 60%./p pWe created a table which holds which user has access to which contacts. We then fill this table once in a few hours. See also issue a href=https://issues.civicrm.org/jira/browse/CRM-19934CRM-19934/a for the technical implementation of this proof of concept./p h3 Performance increase in the search query/h3 pIn the next examples we are logged in as a local member who can only see members in the chapter Amersfoort. We then search for persons with the name 'Jan'. And we measure how long the query for searching takes./p pThe query for presenting the list with letters in the search result looks like/p pre SELECT count(DISTINCT contact_a.id) as rowCount FROM civicrm_contact contact_a LEFT JOIN civicrm_value_geostelsel geostelsel ON contact_a.id = geostelsel.entity_id LEFT JOIN civicrm_membership membership_access ON contact_a.id = membership_access.contact_id WHERE ((((contact_a.sort_name LIKE '%jan%')))) AND (contact_a.id = 803832 OR (((( ( geostelsel.`afdeling` = 806816 OR geostelsel.`regio` = 806816 OR geostelsel.`provincie` = 806816 ) AND ( membership_access.membership_type_id IN (1, 2, 3) AND ( membership_access.status_id IN (1, 2, 3) OR (membership_access.status_id = '7' AND (membership_access.end_date gt;= NOW() - INTERVAL 3 MONTH)) ) ) ) OR contact_a.id = 806816 )) AND (contact_a.is_deleted = 0) )) ORDER BY UPPER(LEFT(contact_a.sort_name, 1)) asc; /pre pAs you can see that is quite a complicated query and includes details about which members the user is allowed to see.  Only executing this query takes around 0.435 seconds and the reason is that mysql has to check each record in civicrm_contact (which in this case is around 350.000 and growing)/p pAfter refactoring the acl cache functionality in CiviCRM Core the query looks different:/p pre SELECT DISTINCT UPPER(LEFT(contact_a.sort_name, 1)) as sort_name  FROM civicrm_contact contact_a INNER JOIN `civicrm_acl_contacts` `civicrm_acl_contacts` ON `civicrm_acl_contacts`.`contact_id` = `contact_a`.`id`  WHERE  (((( contact_a.sort_name LIKE '%jan%' ))))  AND  `civicrm_acl_contacts`.`operation_type` = '2' AND `civicrm_acl_contacts`.`user_id` = '803832' AND `civicrm_acl_contacts`.`domain_id` = '1' AND (contact_a.is_deleted = 0)    ORDER BY UPPER(LEFT(contact_a.sort_name, 1)) asc/pre pThe query now takes around 0,022 seconds to run (20 times faster)./p h3 Explanation/h3 pHow does this new functionality works:/p p1. Every time an ACL restriction is needed in a query civicrm core only does an inner join on the civicrm_acl_contacts table and that is all/p p2. The inner join is generated in the service 'acl_contact_cache'  that service also checks whether the the civicrm_acl_contacts table need to be updated or not./p p3. When an update of civicrm_acl_contacts table is needed depends on the settings under administer --gt; System Settings --gt; Misc --gt; ACL Contact Cache Validity (in minutes)/p pstrongSo how does this look like in code?/strong/p pBelow an example of how you could use the acl_contact_cache service to inject acl logic into your query:/p pre // First get the service from the Civi Container $aclContactCache = \Civi::service('acl_contact_cache'); // The $aclContactCache is a class based on \Civi\ACL\ContactCacheInterface // Now get the aclWhere and aclFrom part for our query $aclWhere = $aclContactCache-gt;getAclWhereClause(CRM_Core_Permission::VIEW, 'contact_a'); $aclFrom = $aclContactCache-gt;getAclJoin(CRM_Core_Permission::VIEW, 'contact_a'); // Now build our query $sql = SELECT contact_a.* FROM civicrm_contact contact_a .$aclFrom. WHERE 1 AND .$aclWhere; // That is it now execute our query and handle the output... /pre pThe reason we use a service in the Civi Container class is that it is now also quite easy to override this part of core in your own extension./p pThe \Civi\ACL\ContactCache class has all the logic to for building the ACL queries. Meaning that this class contains the logic to interact with the ACL settings in CiviCRM, with the permissioned relationship etc.. All those settings are taken into account when filling civicrm_acl_contacts table which is per user and per operation once in the three hours./p p /p /div/div/divdiv class=field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-hiddendiv class=field-itemsdiv class=field-item evena href=/blog/tags/drupal typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=Drupal/a/div/div/div

InternetDevels: What type of Drupal developer do you need for your project?

Fri, 02/24/2017 - 09:16
div class=field field--name-field-preview-image field--type-image field--label-hiddendiv class=field__itemsdiv class=field__item evenimg src=http://st2.internetdevels.net/sites/default/files/public/blog_preview/3_main_types_of_drupal_developers.png width=937 height=622 alt=What type of Drupal developer do you need for your project? //div/div/divdiv class=field field--name-body field--type-text-with-summary field--label-hiddendiv class=field__itemsdiv class=field__item evenpIf you want to create a web resource, or to implement certain improvements on an existing one, then you must find specialists who will make your ideas come true. It’s quite a challenging task. We offered our a href=http://internetdevels.com/blog/10-tips-for-hiring-a-top-web-developer target=_blank10 tips for hiring a top web developer/a by mentioning qualities that must be possessed. However, in addition, there are different types of web developers, with different skills, duties and types of work. The objectives and the scale of your project require appropriate experts./p a href=http://internetdevels.com/blog/types-of-drupal-developersRead more/a/div/div/div