Planet Drupal

Syndicate content - aggregated feeds in category Planet Drupal
Updated: 30 min 31 sec ago

Forum One: Drupal 8 Code Sprint at the Jersey Shore

Thu, 07/24/2014 - 20:52
pOn the heels of our own a href= 8 code sprint in DC/a, I spent the last weekend with the New Jersey Drupal group who organized a Drupal 8 a href= sprint in Asbury Park, NJ/a – and although I was never a href=,_N.J.greeted by The Boss/a, I was pleased to participate thanks to the generosity of the event organizers./p h2Issue-Focused/h2 pI worked on a title=Issue href= target=_blankthe MenuLink NG part 1/a issue extensively with a title=Peter Wolanin, href= Wolanin/a and a title=YesCT, href= This issue is part of the a title=Issue href= target=_blank[Meta] New plan, Phase 2/a issue which proposed performance improvement and UI improvement in Drupal 8. This issue originally had a 600KB patch, but to make it more reviewable/committable the issue was split into five child issues./p pThree of us spent a solid two days and more than 30 hours addressing every single point that had been raised by reviewers – and which had been holding up the process of adding this to Core./p div id=attachment_3382 style=width: 710px class=wp-caption aligncenterimg class=wp-image-3382 size-large src= alt=code-sprint-1 width=700 height=525 /p class=wp-caption-textImage courtesy of Blink Reaction/p/div h2About this Issue (a high level overview)/h2 pA site builder or developer can create menu links in Drupal via configuration by changing the weight, position, creating links in menu, or in code. All these different types of menu links need to be rendered together in menus, so that they present the same in the API to developers. The developer experience on this issue needs to be easy, as almost everything depends on menu items./p pWhile we toiled on this issue, other sprinters worked on a title=Issue href= target=_blankDrupalCon Austin#8217;s Consensus Banana/a, testing the migration path from Drupal 6 to Drupal 7, along with some other issues./p div style=text-align: center;img class=alignnone wp-image-3451 size-full src= alt=The DrupalCon Austin Consensus Banana! width=599 height=376 //div h2Results and Commits/h2 pThe sprint was a very productive one, and resulted in a href=””Menu part 1/a and a href=””Menu part 2/a being committed to Core, which was a beta-blocker issue. As of this sprint there were seven beta-blocker issues, but solving the Menu issue helps to put us one step closer to the Drupal 8 Beta release!/p pFor those interested, here are the commits for a href= 1/a and a href= 2/a. And for those needing a chuckle, Alex #8220;The Situation#8221; Pott – who thankfully preferred DCC (Drupal Core Commits) over GTL (Gym, Tan, Laundry) – drew this a href= looking lama/a to celebrate his commit img src= alt=:) class=wp-smiley / /p div id=attachment_3384 style=width: 710px class=wp-caption aligncenterimg class=wp-image-3384 size-large src= alt=Image courtesy of Blink Reaction width=700 height=525 /p class=wp-caption-textImage courtesy of Blink Reaction/p/div pIt was very rewarding to work for a weekend with this group of talented developers, and I think we all left the shore content in the knowledge that we#8217;d made strides toward bringing Drupal 8 that much closer to completion./p pCheck out these other a href= taken by Peter Wolanin/a and a href= NJ at the event »/a/p

Dries Buytaert: The business behind Open Source

Thu, 07/24/2014 - 16:38
div class=field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-abovediv class=field-labelTopic:nbsp;/divdiv class=field-itemsdiv class=field-item evena href=/tag/drupal typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=Drupal/a/divdiv class=field-item odda href=/tag/acquia typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=Acquia/a/divdiv class=field-item evena href=/tag/business typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=Business/a/divdiv class=field-item odda href=/tag/the-future typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=The future/a/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:encodedpA few days ago, I sat down with a href= Hardy/a of a href=http://nytimes.comThe New York Times/a to talk Open Source. We spoke mostly about the a href=http://drupal.orgDrupal ecosystem/a and how a href=http://acquia.comAcquia/a makes money. As someone who spent almost his entire career in Open Source, I'm a firm believer in the fact that you can a href= a high-growth, high-margin business and help the community flourish/a. It's not an either-or proposition, and Acquia and Drupal are proof of that./p pRather than an a href= alternate reality/a as Quentin outlines, I believe Open Source is both a better way to build software, and a good foundation for an ecosystem of for-profit companies. Open Source software itself is very successful, and is capable of running some of the most complex enterprise systems. But failure to commercialize Open Source doesn't necessarily make it bad. /p pI mentioned to Quentin that I thought Open Source was a href=; a proprietary software company can't afford to experiment with creating 10 different implementations of an online photo album, only to pick the best one. In Open Source we can, and do. We often have competing implementations and eventually the best implementation(s) will win. One could say that Open Source is a more wasteful way of software development. In a pure capitalist read of a href= the Origin of Species/a, there is only one winner, but business and Darwin's theory itself is far more complex. Beyond only the strongest survive, Darwin tells a story of interconnectedness, or the way an ecosystem can dictate how an entire species chooses to adapt. /p pWhile it's true that the Open Source business model has produced few large businesses (aRed Hat being one notable example/a), we're also evolving the different Open Source business models. In the case of Acquia, we're selling a number of as-a-service products for Drupal, which is vastly different than just selling support like the first generation of Open Source companies did. /p pAs a private company, a href=http://acquia.comAcquia/a doesn't disclose financial information, but I can say that we've been very busy operating a high-growth business. Acquia is North America's fastest growing private company on the Deloitte Fast 500 list. Our Q1 2014 bookings increased 55 percent year-over-year, and the majority of that is recurring subscription revenue. We've experienced 21 consecutive quarters of revenue growth, with no signs of slowing down. Acquia's business model has been both disruptive and transformative in our industry. Other Open Source companies like a href=http://hortonworks.comHortonworks/a, a href=http://cloudera.comCloudera/a and a href=http://mongodb.comMongoDB/a seem to be building thriving businesses too./p pSociety is undergoing tremendous change right now -- the sharing and collaboration practices of the internet are extending to transportation (a href=http://uber.comUber/a), hotels (a href=http://airbnb.comAirbnb/a), financing (a href=http://kickstarter.comKickstarter/a, a href=http://lendingclub.comLendingClub/a) and music services (a href=http://spotify.comSpotify/a). The a href= of the collaborative economy/a, of which the Open Source community is a part of, should be a powerful message for the business community. It are the established, proprietary vendors whose business models are at risk, and not the other way around./p pHundreds of other companies, including several venture backed startups, have been born out of the Drupal community. Like Acquia, they have grown their businesses while supporting the ecosystem from which they came. That is more than a feel-good story, it's just good business./p /div/div/div

drunken monkey: Updating the Search API to D8 – Part 3: Creating your own service

Thu, 07/24/2014 - 14:28
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item even property=content:encodedpEven though there was somewhat of a delay since a href=/blog/search-api-d8-update-part-2my last post in this series/a, it seems no-one else has really covered any of the advanced use cases of Drupal 8 in tutorials yet. So, here is the next installment in my series. I initially wanted to cover creating a new plugin type, but since that already requires creating a new servive, I thought I'd cover that smaller part first and then move on to plugin types in the next / I realize that now already a lot more people have started on their Drupal 8 modules, but perhaps this will make this series all the more useful./p h2Services in Drupal 8/h2 pFirst, a short overview of what a service even is. Basically it is a component (represented as a class) providing a certain, limited range of functionality. The database is a service, the entity manager (which is what you now use for loading entities) is a service, translation, configuration – everything handled by services. Getting the current user – also a service now, ridding us of the highly unclean global / In general, a lot of what was previously a file in codeincludes//code containing some functions with a common prefix is now a service (or split into multiple services)./p pThe upsides of this is that the implementation and logic is cleanly bundled and properly encapsulated, that all these components can easily be switched out by contrib or later core updates, and that these systems can also be very well tested with unit tests. Even more, since services can be used with dependency injection, it also makes it much easier to test all other classes that use any of these services (if they can use dependency injection and do it properly)./p p(For reference, here is the a href= documentation on services/a.)/p h3Dependency injection/h3 pThis has been covered already in a lot of other blog posts, probably since it is both a rather central concept in Drupal 8, and a bit complicated when you first encounter it. However, before using it, I should still at least skim over the topic. Feel free to skip to the next heading if you feel you already know what dependency injection is and how it roughly works in Drupal 8./p pDependency injection is a programming technique where a class with external dependencies (e.g., a mechanism for translating) explicitly defines these dependencies (in some form) and makes the class which constructs it responsible for supplying those dependencies. That way, the class itself can be self-contained and doesn't need to know about where it can get those dependencies, or use any global functions or anything to achieve that./p pConsider for example the following class:/p div class=codeblock precodespan style=color: #000000span style=color: #0000BBlt;?phpbr //spanspan style=color: #007700class /spanspan style=color: #0000BBExampleClass /spanspan style=color: #007700{br /br /  public function /spanspan style=color: #0000BBgetDefinition/spanspan style=color: #007700() {br /    return array(br /      /spanspan style=color: #DD0000'label' /spanspan style=color: #007700=gt; /spanspan style=color: #0000BBt/spanspan style=color: #007700(/spanspan style=color: #DD0000'example class'/spanspan style=color: #007700),br /      /spanspan style=color: #DD0000'type' /spanspan style=color: #007700=gt; /spanspan style=color: #DD0000'foo'/spanspan style=color: #007700,br /    );br /  }br /br /}br //spanspan style=color: #0000BB?gt;/span/span/code/pre/div pFor translating the definition label, this explicitly uses the global codet()/code function. Now, what's bad about this I, hear you ask, it worked well enough in Drupal 7, right?br / The problem is that it becomes almost impossible to properly unit-test that method without bootstrapping Drupal to the point where the codet()/code function becomes available and functional. It's also more or less impossible to switch out Drupal's translation mechanism without hacking core, since there is no way to redirect the call to codet()/code./p pBut if translation is done by a class with a defined interface (in other words, a service), it 's possible to do this much cleaner:/p div class=codeblock precodespan style=color: #000000span style=color: #0000BBlt;?phpbr //spanspan style=color: #007700class /spanspan style=color: #0000BBExampleClass /spanspan style=color: #007700{br /br /  public function /spanspan style=color: #0000BB__construct/spanspan style=color: #007700(/spanspan style=color: #0000BBTranslationServiceInterface $translation/spanspan style=color: #007700) {br /    /spanspan style=color: #0000BB$this/spanspan style=color: #007700-gt;/spanspan style=color: #0000BBtranslation /spanspan style=color: #007700= /spanspan style=color: #0000BB$translation/spanspan style=color: #007700;br /  }br /br /  public function /spanspan style=color: #0000BBgetDefinition/spanspan style=color: #007700() {br /    return array(br /      /spanspan style=color: #DD0000'label' /spanspan style=color: #007700=gt; /spanspan style=color: #0000BB$this/spanspan style=color: #007700-gt;/spanspan style=color: #0000BBtranslation/spanspan style=color: #007700-gt;/spanspan style=color: #0000BBtranslate/spanspan style=color: #007700(/spanspan style=color: #DD0000'example class'/spanspan style=color: #007700),br /      /spanspan style=color: #DD0000'type' /spanspan style=color: #007700=gt; /spanspan style=color: #DD0000'foo'/spanspan style=color: #007700,br /    );br /  }br /br /}br //spanspan style=color: #0000BB?gt;/span/span/code/pre/div pThen our example class just has to make it easily possible for code that wants to instantiate it to know how to pass its dependencies to it. In Drupal, there are two ways to do this, depending on what you are creating:/p ulliServices, which themselves use dependency injection to get their dependencies (as you will see in a minute) have a definition in a YAML file that exactly states which services need to be passed to the service's constructor./li liAlmost anything else (I think) uses a static codecreate()/code method which just receives a container of all available services and is then responsible for passing the correct ones to the constructor./li /ulpIn either case, the idea is that subclasses/replacements of codeExampleClass/code can easily use other dependencies without any changes being necessary to code elsewhere instantiating the class./p h2Creating a custom service/h2 pSo, when would you want to create your own service in a module? Generally, the code.module/code file should more or less only contain hook implementations now, any general helper functions for the module should live in classes (so they can be easily grouped by functionality, and the code can be lazy-loaded when needed). The decision to make that class into a service then depends on the following questions:/p ulliIs there any possibility someone would want to swap out the implementation of the class?/li liDo you want to unit-test the class?/li liRelatedly, do you want dependency injection in the class?/li /ulpI'm not completely sure myself about how to make these decisions, though. We're still thinking about what should and shouldn't be a service in the Search API, currently there is (apart from the ones for plugins) only one service there:/p h3The Server task manager service/h3 pThe server tasks system, which already existed in D7, basically just ensures that when any operations on a server (e.g., removing or adding an index, deleting items, …) fails for some reason (e.g., Solr is temporarily unreachable) it is regularly retried to always ensure a consistent server state. While in D7 the system consisted of just a few functions, in D8 it was decided to encapsulate the functionality in a dedicated service, the Server task manager./p h3Defining an interface and a class for the service/h3 pThe first thing you need, so the service can be properly swapped out later, is an interface specifying exactly what the service should be able to do. This completely depends on your use case for the service, nothing to keep in mind here (and also no special namespace or anything). In our case, for server tasks:/p div class=codeblock precodespan style=color: #000000span style=color: #0000BBlt;?phpbr //spanspan style=color: #007700namespace /spanspan style=color: #0000BBDrupal/spanspan style=color: #007700\/spanspan style=color: #0000BBsearch_api/spanspan style=color: #007700\/spanspan style=color: #0000BBTask/spanspan style=color: #007700;br /br /interface /spanspan style=color: #0000BBServerTaskManagerInterface /spanspan style=color: #007700{br /br /  public function /spanspan style=color: #0000BBexecute/spanspan style=color: #007700(/spanspan style=color: #0000BBServerInterface $server /spanspan style=color: #007700= /spanspan style=color: #0000BBNULL/spanspan style=color: #007700);br /br /  public function /spanspan style=color: #0000BBadd/spanspan style=color: #007700(/spanspan style=color: #0000BBServerInterface $server/spanspan style=color: #007700, /spanspan style=color: #0000BB$type/spanspan style=color: #007700, /spanspan style=color: #0000BBIndexInterface $index /spanspan style=color: #007700= /spanspan style=color: #0000BBNULL/spanspan style=color: #007700, /spanspan style=color: #0000BB$data /spanspan style=color: #007700= /spanspan style=color: #0000BBNULL/spanspan style=color: #007700);br /br /  public function /spanspan style=color: #0000BBdelete/spanspan style=color: #007700(array /spanspan style=color: #0000BB$ids /spanspan style=color: #007700= /spanspan style=color: #0000BBNULL/spanspan style=color: #007700, /spanspan style=color: #0000BBServerInterface $server /spanspan style=color: #007700= /spanspan style=color: #0000BBNULL/spanspan style=color: #007700, /spanspan style=color: #0000BB$index /spanspan style=color: #007700= /spanspan style=color: #0000BBNULL/spanspan style=color: #007700);br /br /}br //spanspan style=color: #0000BB?gt;/span/span/code/pre/div p(Of course, proper PhpDocs are essential here, I just skipped them for brevity's sake.)/p pThen, just create a class implementing the interface. Again, namespace and everything else is completely up to you. In the Search API, we opted to put interface and class (they usually should be in the same namespace) into the namespace code\Drupal\search_api\Task/code. See a href= for their complete / For this post, the only relevant part of the class code is the constructor (the rest just implements the interface's methods):/p div class=codeblock precodespan style=color: #000000span style=color: #0000BBlt;?phpbr //spanspan style=color: #007700class /spanspan style=color: #0000BBServerTaskManager /spanspan style=color: #007700implements /spanspan style=color: #0000BBServerTaskManagerInterface /spanspan style=color: #007700{br /br /  public function /spanspan style=color: #0000BB__construct/spanspan style=color: #007700(/spanspan style=color: #0000BBConnection $database/spanspan style=color: #007700, /spanspan style=color: #0000BBEntityManagerInterface $entity_manager/spanspan style=color: #007700) {br /    /spanspan style=color: #0000BB$this/spanspan style=color: #007700-gt;/spanspan style=color: #0000BBdatabase /spanspan style=color: #007700= /spanspan style=color: #0000BB$database/spanspan style=color: #007700;br /    /spanspan style=color: #0000BB$this/spanspan style=color: #007700-gt;/spanspan style=color: #0000BBentity_manager /spanspan style=color: #007700= /spanspan style=color: #0000BB$entity_manager/spanspan style=color: #007700;br /  }br /br /}br //spanspan style=color: #0000BB?gt;/span/span/code/pre/div pAs you can see, we require the database connection and the entity manager as dependencies, and just included them in the constructor. We then save them to properties to be able to use them later in the other methods./p pNow we just need to tell Drupal about our service and its dependencies./p h3The codeservices.yml/code file/h3 pAs mentioned earlier, services need a YAML definition to work, where they also specify their dependencies. For this, each module can have a file listing services it wants to publish./p pIn our case, looks like this (with the plugin services removed):/p div class=codeblockcodeservices:br /  search_api.server_task_manager:br /    class: Drupal\search_api\Task\ServerTaskManagerbr /    arguments: ['@database', '@entity.manager']/code/div pAs you see, it's pretty simple: we assign some ID for the service (codesearch_api.server_task_manager/code – properly namespaced by having the module name as the first part), specify which class the service uses by default (which, like the other definition keys, a href= then be altered/a by other modules) and specify the arguments for its constructor (i.e., its dependencies). codedatabase/code and codeentity.manager/code in this example are just IDs of other services defined elsewhere (in Drupal core's, in this case)./p pThere are more definition keys available here, and also more features that services support, but that's more or less the gist of it. Once you have its definition in the file, you are ready to use your new service./p h3Using a service/h3 pYou already know one way of using a service: you can specify it as an argument for another service (or any other dependency injection-enabled component). But what if you want to use it in a hook, or any other place where dependency injection is not available (like entities, annoyingly)?/p pYou simply do this:/p div class=codeblock precodespan style=color: #000000span style=color: #0000BBlt;?phpbr //spanspan style=color: #FF8000/** @var \Drupal\search_api\Task\ServerTaskManagerInterface $server_task_manager */br //spanspan style=color: #0000BB$server_task_manager /spanspan style=color: #007700= \/spanspan style=color: #0000BBDrupal/spanspan style=color: #007700::/spanspan style=color: #0000BBservice/spanspan style=color: #007700(/spanspan style=color: #DD0000'search_api.server_task_manager'/spanspan style=color: #007700);br //spanspan style=color: #0000BB$server_task_manager/spanspan style=color: #007700-gt;/spanspan style=color: #0000BBexecute/spanspan style=color: #007700();br //spanspan style=color: #0000BB?gt;/span/span/code/pre/div pThat's it, now all our code needing server tasks functionality benefits from dependency injection and all the other Drupal 8 service goodness./p /div/div/div

Pedro Rocha: OOP in Drupal 7: Cool module in practice

Thu, 07/24/2014 - 10:08
Hey, do you wanna know how to: reduce the amount of code needed to create modules turns the code more readable make it easier to find bugs make it easier to change business logic make it easier to improve code Sounds good, right? If you only wanna know about code, jump to here, or read about the historical background of the module ;)

NEWMEDIA: Avoiding the API Integration Blues on a Drupal Project

Thu, 07/24/2014 - 05:31
span class=field field-node--title field-name-title field-type-text field-label-hidden data-edit-field-id=node/142/title/en/rssAvoiding the quot;API Integration Bluesquot; on a Drupal Project/spandiv class=field field-node--field-intro field-name-field-intro field-type-text-long field-label-hidden data-edit-field-id=node/142/field_intro/en/rssdiv class=field-itemsdiv class=field-itemAs Drupal continues to mature as a platform and gain adoption in the enterprise space, integration with one or more 3rd party systems is becoming common for medium to large scale projects. Unfortunately, it can be easy to underestimate the time and effort required to make these integrations work seamlessly. Here are lessons we#039;ve learned.../div/div/divdiv class=field field-node--body field-name-body field-type-text-with-summary field-label-hidden data-edit-field-id=node/142/body/en/rssdiv class=field-itemsdiv class=field-itempa href=, a href=, a href=, a href=, and on and onmdash;It#39;s easy to get spoiled by a href=;s extensive library of contributed modules/a that allow for quick, easy, and robust integration with 3rd party systems. Furthermore, if a particular integration does not emyet/em exist, the extendability of Drupal is straightforward enough that it emcould/em be done given the usual caveats (i.e. an appropriate amount of time, resources, and effort). However, these caveats should not be taken lightly. Our own experiences have unearthed many of the same pain points again and again, which almost always result in waste. By applying this gained wisdom to all subsequent projects involving integrations, we#39;ve been much more successful in identifying and addressing these issues head on. We hope that in sharing what we#39;ve learned that you can avoid some of the more common traps./p h3API and Integration Gotchas/h3 h4Vaporware/h4 pShocking as it may seem, there are situations where a client will assume an API exists when there isn#39;t one to be found. Example: anbsp;client may be paying for an expensive enterprise software license that can connect to other programs within the same ecosystem, but there may not be annbsp;endpoint that can be accessed by Drupal. They key here is to ensure you have documentation up front along with a working example of a read and/or write operation written in php or through a web services call. Doing this as early as possible within the project will help prevent a nasty surprise when it#39;s too late to change course or stop the project altogether./p h4Hidden Add-on Fees/h4 pAn alternative to the scenario above is when an endpoint can be made available for an additional one-time or recurringnbsp;fee. This can be quite an expensive surprise. It can also result in a difficult conversation with the client, particularly if it wasn#39;t factored into the budget and now each side must determine who eats the cost. The key to preventing this is to verify (up front) if the API endpoint is included with the client#39;s current license(s) or if it will be extra./p h4Limited Feature Sets/h4 pOne can never assume that an entire feature set is available. Example: an enterprise resource planning (ERP) software solution may provide a significant amount of data and reporting to its end users, but it may only expose particular records (e.g. users, products, and inventory) to an API. The result: a Drupal site#39;s scope document might include functionality that simply cannot be provided. To avoid this issue, you#39;ll want to get your hands on any and all documentation as soon as possible. You#39;ll also want to create an inventory of every feature that requires anbsp;read/write operation so that you cannbsp;verify the documentation covers each and every item./p h4Documentation/h4 pTranscending the quot;Drupal learning cliffquot; was and continues to be a difficult journey for many members of the community despite the abundance of ebooks, videos, and articles on the subject matter. Consider how much more difficult building Drupal sites would be if these resources didn#39;t exist. Now imagine trying to integrate with a systems you#39;ve never heard of using a language you#39;re unfamiliar with and no user guide to point you in the right direction./p pSounds scary, doesn#39;t it?/p pIntegrating with a 3rd party application without documentation is akin to flying blind. Sure you emmight/em eventually get to the appropriate destination, but you will likely spend a significant amount of time using trial and error. Worse yet, you may simply miss certain pieces of functionality altogether./p pThe key here, as always, is to get documentation as soon as you can. Also, pay attention tonbsp;certain red flags, such as the client not having the documentationnbsp;readily available or requiring time for one of their team members to write it up. This is particularly important if the integration is a one-off that is specific to the customer versus an integration with a widely known platform (e.g. Salesforce or PayPal)./p h4Business Logic/h4 pOne of Drupal#39;s strengths is the ability for other modules to hook in to common events. For example, a module could extend the functionality of a user savingnbsp;his or her password to email a notification that a password was changed.When integrating with another system, it#39;s equally important to understand what events may be triggered as a result of reading or writing a record. Otherwise, you may be in for a surprise to find out the external system was firing off emails or trying to charge credit card payments./p pDocumentation is invaluable to prevent these types of gaffs. However, in our experience it has been important to have access to a support resource that can provide warnings up front./p h4Support/h4 pWhat happens when the documentation is wrong or the software doesn#39;t work? If support regarding the API is slow or non-existant, the project may grind to halt until this block is removed. For enterprise level solutions, there is usually some level of support that can be accessed via phone, forums, or support tickets. However, there can sometimes be a sizable fee for this service and your particular questions might not be in scope with respect to what their service provides. In those instances, it might be helpful to contract with a 3rd party vendor or contractor that has performed a similar integration in the past. This can be costly up front while saving a tremendous of time over the course of the project./p h4Domain Knowledge/h4 pAs consultants, one of our primary objectives is to merge our expertise with that of the customer#39;s domain knowledge in order to best achieve their goals. Therefore, it#39;s important that we understand emwhy/em the integration should work the way it does instead of just emhow/em we read and write data back and forth. A great example of this involves integratingnbsp;Drupal Commerce with Quickbooks through thenbsp;Web Connecter application. It#39;s imperative to understand how the client#39;s accounting department configures the Quickbooks application and how it manages the financial records. Otherwise a developer may make an assumption that results in an inefficient or (worse) incorrect functionality./p pSimilar to having a resource available for support on the API itself, it#39;s invaluable to have access to team members on the client side that use the software on a daily basis so that nothing is missed./p h4Stability/h4 pMedium to large sized companies are becoming increasingly reliant on their websites to sustain and grow their businesses. Therefore, uptime is critical. And if the site depends on the uptime of a 3rd party integration to function properly, it may be useful to consider some form of redundancy or fallback solution. It is also important to make sure that support tickets can be filed with a maximum response time specified in anynbsp;service licensing agreement (SLA) with the client./p h4Communication and Coordination/h4 pThe rule of thumb here is simple: more moving parts in a project equals more communication time spent keeping everyone in sync. Additionally, it#39;s usually wise to develop against an API endpoint specifically populated with test data so that it will not impact the client#39;s production data. At some point, the test data will need to be cleared out and production data will need to be imported. This transition could be as simple as swapping a URL or it could involve significant amount of QA time testing and retesting full imports before making the final switch./p pThe best way to address these issues is simply to buffer in more communication time into the budget than a normal Drupal project./p h4SDKs/h4 pOne gotcha that can be particularly difficult to work around is that an API may require you to use their specific software development kit (SDK) instead of a native PHP library. This may require the server to run a different OS (Windows instead of Linux) and web server (IIs instead of Apache). If you#39;re not used to developing on these platforms, development time may be slowed down by a significant percentage. For example: a back-end developer may not be able to use the same IDE they are accustomed to (with all of their optimized configurations and memorized shortcuts). This requirement may be unavoidable in some circumstances, so the best way to deal with these situations is a simple percentage on the budgeted hours./p h4VMs/h4 pWhen possible, it is ideal for developers can work on their own machine locally with a fully replicate instance of the API they are interacting with. Example: Quickbooks connecting through their Web Connector application to read and write records from a Drupal Commerce site. To test this connection, it isnbsp;extremely helpful to have a local virtual machine (VM) with Windows and Quickbooks, which a developer could then use to trigger the process. If a project involves multiple developers, they could each have their own copy to use a sandbox./p pSetting up a local VM definitely adds an upfront cost to create. However, for larger projects this investment can generally be recouped many times over with respect to increased development speed and the ability to start from a consistent target./p h3Final Advice/h3 pBy now, we hope that we#39;ve made the case that it#39;s important to do your due diligence when taking on project involving integrations. And while this entire list of potential pain points may seem overkill, we#39;ve personally experienced the effects of every one of them at some point in our company#39;s history. Ultimately, both you and the client want to avoid the uncomfortable conversation of a project#39;s timeline slipping and going over budget. Therefore, it#39;s critical to have address these issues thoroughly and as early in the project as possible. If uncertainty is especially high, it#39;s usually beneficial to include a line item within the project statement of work to evaluate this piece separately. Finally, if you#39;re able to effectively negotiate the terms of a contract, the budget for the integration shouldn#39;t be set until an evaluation (even a partial one) has been completed./p pThoughts? Story to share? We#39;d love to get your feedback on how to improve upon this article./p /div/div/div

Metal Toad: Drupal Solr Search with Domain Access filtering

Wed, 07/23/2014 - 23:34
pMetal Toad has had the privilege to work over the past two years with DC Comics. What makes this partnership even more exciting, is that the main site also includes sites for Vertigo Comics and Mad Magazine. Most recently Metal Toad was given the task of building the new search feature for all three sites. However, while its an awesome privilege to work with such a well known brand as DC, this does not come without a complex set of issues for the three sites when working with a href= Solr/a search and Drupal./p ul class=links inlineli class=0 first lasta href= rel=tag title=Drupal Solr Search with Domain Access filteringRead more/a/li /ul Headless Drupal - Form API, Drupal 9

Wed, 07/23/2014 - 23:00
h2Defining moment/h2 pA few months ago my DrupalCon Austin session was rejected. I was a bit upset, since presenting plays a big part in my trip to the states, and also surprised, as I mistakenly assumed my presentation repertoire would almost guarantee my session would be accepted. But the committee decided differently./p pThis has been an important moment for me. Two days later I told myself I don#39;t care. I mean, I cared about the empresentation/em, I just stopped caring that it was not selected, since I decided I was going to do it anyway. As an quot;unpluggedquot; BoF./p pa href= Gizra Way/a. I think this is probably the best presentation I#39;ve given so far, and quite ironically my emrejected/em session is second only to Dries#39;s keynote in YouTube./p pYou see - I had a quot;a href= is no spoon/aquot; moment. The second I realized it can be done differently, I was on my own track, perhaps even setting the path for others./p h2Form API, Drupal 9/h2 blockquote pI use Drupal because Form API is so great div class=smallNo one, ever/div/p /blockquote pa href= reading…/a/p

Acquia: Search in Drupal 8 - Thomas Seidl Nick Veenhof

Wed, 07/23/2014 - 17:57
div class=field field-name-body field-type-text-with-summary field-label-hidden div class=field-items div property=content:encoded class=field-item evenpThomas Seidl and Nick Veenhof took a few minutes out of the Drupal 8 Search API code sprint at the Drupal DevDays in Szeged, Hungary to talk with me about the state-of-play and what's coming in terms of search in Drupal: one flexible, pluggable solution for search functionality with the whole community behind it./p /div /div /div span property=dc:title content=Search in Drupal 8 - Thomas Seidl amp; Nick Veenhof class=rdf-meta/span

Clemens Tolboom: Interested in ReST and HAL?

Wed, 07/23/2014 - 16:42
div class=field field-name-field-images field-type-image field-label-hiddendiv class=field-itemsdiv class=field-item evena href=/content/interested-rest-and-halimg src= width=220 height=196 alt= title=HAL 9000 //a/div/div/divdiv class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item evenolli Checkout the issue queue for a href=;status[]=Openamp;version[]=8.xamp;component[]=hal.moduleamp;component[]=rest.moduleamp;issue_tags_op=%3DHAL and ReST/a. /lili Use the quickstart tool: a href= /li/olh2Need HAL?/h2 olli Install a href= Browser/a on your site to see what we got till now. /lili div class=codeblockcodecd drupal-root/code/div/li/ol/div/div/div

Acquia: Migration Tips and Tricks

Wed, 07/23/2014 - 15:18
div class=field field-name-body field-type-text-with-summary field-label-hidden div class=field-items div property=content:encoded class=field-item evenpemCross-posted with permission from a href= target=_blanknerdstein/a/em/p pThe a href= target=_blankMigrate module/a is, hands down, the defacto way to migrate content in Drupal. The only knock against it, is the learning curve. All good things come to those who take the time and learn it./p/div /div /div span property=dc:title content=Migration Tips and Tricks class=rdf-meta/span

Code Karate: Drupal 7 Splashify

Wed, 07/23/2014 - 13:36
div class=field field-name-field-episode-number field-type-number-integer field-label-abovediv class=field-labelEpisode Number:nbsp;/divdiv class=field-itemsdiv class=field-item even158/div/div/divdiv class=field field-name-field-ddod-video field-type-file field-label-hiddendiv class=field-itemsdiv class=field-item evenimg src= alt=Drupal 7 Splashify Module - Daily Dose of Drupal Episode 158 //div/div/divdiv class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item evenpIn this episode we cover the a href= module. This module is used to display splash pages or popups. There are multiple configuration options available to fit your site needs. /p pIn this episode you will learn:/p ulliHow to set up Splashify/li liHow to configure Splashify/li liHow to get Splashify to use the Mobile Detect plugin/li liHow Splashify displays to the end user/li liHow to be awesome/li /ul/div/div/divdiv class=field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-abovediv class=field-labelTags:nbsp;/divdiv class=field-itemsdiv class=field-item evena href=/category/tags/drupalDrupal/a/divdiv class=field-item odda href=/category/tags/drupal/drupal-7Drupal 7/a/divdiv class=field-item evena href=/category/tags/drupal-planetDrupal Planet/a/divdiv class=field-item odda href=/category/tags/uidesignUI/Design/a/divdiv class=field-item evena href=/category/tags/uidesign/javascriptJavascript/a/divdiv class=field-item odda href=/category/tags/uidesign/responsive-designResponsive Design/a/div/div/div

Drupal Association News: Building the Drupal Community in Vietnam: Seeds for Empowerment and Opportunities

Wed, 07/23/2014 - 06:38
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item evenpimg alt=Drupal Vietnam class=left src= /With almost 90 million people, Vietnam has the 13th largest population of any nation in the world. It's home to a young generation that is very active in adopting innovative technologies, and in the last decade, the country has been steadily emerging as an attractive IT outsourcing and staffing location for many Western software companies./p pYet amidst this clear trend, Drupal has emerged very slowly in Vietnam and all of Asia as a leading, enterprise-ready Framework (CMF). However, this is changing as one Drupalista works hard to grow the regional user base./p h2 How it all started/h2 pTom Tran, a German with Hanoian roots, discovered Drupal in 2008. He was overwhelmed by the technological power and flexibility that makes Drupal such a highly competitive platform, and was amazed by the friendliness and vibrancy of the global community. He realized that introducing the framework and the Drupal community to Vietnam would help local people the opportunity to access the following three benefits:/p ulli strongSteady Income:/strong Drupal won’t make you an overnight millionaire, however if you become a Drupal expert and commit to helping clients to achieve their goals, you will never be short of work. Quality Drupal specialists are in huge demand across the world and this demand won’t stop any time soon as Drupal adoption grows./li li strongBetter Lifestyle: /strongYou are free and able to design a work/lifestyle balance on your terms. You can work from home or contribute remotely while traveling, as long as you continue to deliver sustainable value to your client. Many professionals in less developed countries like Vietnam have never imagined this opportunity-- and learning about this lifestyle can be very empowering and inspirational./li li strongCross Cultural Friendships: /strongIn spite of national borders and cultural differences, Tom has established fruitful partnerships between his development team from Vietnam and clients from across the globe. Whether clients are based in California, Berlin, Melbourne or Tokyo, his team has successfully collaborated on many projects and often became good friends beyond just project mates. These relationships can only grow thanks to the open Drupal community spirit and the way it connects peoples from all regions and cultures from around the world./li /ulpTom started by organizing a a href= 7 release party in Hanoi/a in January 2011. Afterwards, he reached out to Drupal enthusiasts in the region and organized informal coffee sessions, which have contributed to the growth of a solid, cohesive community in Vietnam./p h2 Drupal Vietnam College Tour/h2 pWith help from a a href= Cultivation Grant/a, Tom put on workshops every three months at Vietnamese universities and colleges in 2012. By showcasing the big brands and institutions using Drupal, a diverse series of use cases demonstrate that the demand for Drupal is high, and that the Drupal industry is a great place to be. A three hour hands-on session walks students through the basics of sitebuilding with Drupal-- and it's at this point that most students get hooked./p pstrongMarch 2012/strongbr / First ever Drupal Hanoi Conference at VTC Academy, with 120 visitors (a href=;type=1facebook gallery/a)/p pimg alt= src= //p pstrongJune 2012/strongbr / Hello Drupal workshop @ Tech University Danang (a href=;type=3gallery/a)/p pimg alt= src= //p p /p pstrongJuly 2012/strongbr / Drupal Workshop @ FTP-Aptech (a href=;type=1fb gallery/a, a href= aptech news/a)/p pimg alt= src= //p p /p pstrongSeptember 2012/strongbr / Drupal Workshop @ NUCE (a href=, a href=;id=1265Nuce news/a)/p pimg alt= src= //p p /p pstrongNovember 2012/strongbr / Drupal Workshop @ FTP University (a href=;page=1gallery/a)/p pimg alt= src= //p p /p pstrongDecember 2012/strongbr / Drupal Workshop @ Aiti-Aptech (a href=;type=3gallery/a)/p pimg alt= src= //p p /p pstrongDecember 2012/strongbr / Drupal talk amp; sponsorship for 2012 (local images 2x)img alt= src= //p pThe results was an overall increase in members and growing everyday. Stats in 2014:/p ulli 640 Members on a href= li 1300 members on Facebook/Vietnam/li li 550 members on a href= li 80 members on a href= /ulh2 What’s next?/h2 pTom is currently planning to organize the first DrupalCamp in Hanoi / Vietnam in late 2014. Today strongDrupal Vietnam/strong has only roughly 1300 members, (less than LA DUG) but with a growing pool of software engineers graduating each year, this country is set to become a relevant resource of highly skilled developers, provided high quality training is affordable and access to jobs can be facilitated. Things look very bright in Vietnam!/p h2 Supporters/h2 ulli Drupal Association/li li a href= James/a amp; a href= from Acquia/li li a href= Kettunen/a/li li a href= Nadeau/a/li li a href= Wooten/a/li /ulh2 About/h2 pimg alt=Tom Tran class=right src= //p pTom is founder of a href=http://geekpolis.comGeekpolis/a, a software company with a development center based in Hanoi, Vietnam. Geekpolis focuses on high-quality managed Drupal development services for bigger consultancy agencies. Currently the team is comprised of 25 engineers./p h2 To get involved, contact Tom at:/h2 ulli a href= li a href= /ul/div/div/div

Drupal core announcements: Drupal 7.30 release this week to fix regressions in the Drupal 7.29 security release

Wed, 07/23/2014 - 06:06
div class=field field-type-datestamp field-field-start7 div class=field-items div class=field-item odd div class=field-label-inline-first Start:nbsp;/div span class=date-display-start2014-07-23 (All day)/spanspan class=date-display-separator - /spanspan class=date-display-end2014-07-25 (All day) America/New_York/span /div /div /div div class=field field-type-text field-field-event-type div class=field-items div class=field-item odd Sprint /div /div /div div class=field field-type-userreference field-field-organizers div class=field-labelOrganizers:nbsp;/div div class=field-items div class=field-item odd a href=/user/14705 title=View user profile.David_Rothstein/a /div /div /div pThe a href= 7.29 security release/a contained a security fix to the File module which caused some regressions in Drupal's file handling, particularly for files or images attached to taxonomy terms./p pI am planning to release Drupal 7.30 this week to fix as many of these regressions as possible and allow more sites to upgrade past Drupal 7.28. The release could come as early as today (Wednesday July 23)./p pHowever, to do this we need more testing and reviews of the proposed patches to make sure they are solid. Please see a href= Regression: Files or images attached to certain core and non-core entities are lost when the entity is edited and saved/a for more details and for the patches to test, and leave a comment on that issue if you have reviewed or tested them./p pThank you!/p

Mediacurrent: Understanding the Role of the Enterprise in Drupal

Wed, 07/23/2014 - 03:53
img typeof=foaf:Image src= width=200 height=152 / pThere is a a href= topic/a I am seeing being discussed a lot more in the open-source software and a href= community. The point of conversation focuses on what the role should be of enterprise organizations?  Especially, those that are or have already adopted Drupal as their web platform of choice./p

Greater Los Angeles Drupal (GLAD): Drupal Migrate using xml 0 to 35

Tue, 07/22/2014 - 20:55
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item even property=content:encodedpUsing Drupal Migrate is a great way to move you content into Drupal. Unfortunately the documentation for xml import can be obscure. This comes about when those that developed the module try to communicate how they did what they did to someone that did not do the work. Things that seem obvious to them are not to someone else./p pI have spent some time recently importing content using xml. In no way am I an expert that is speeding down the fast lane, something more in the cruising around town at a comfortable 35 mph./p pTo use Drupal Migrate you need to define your own class. A class is php code that is used in Object Oriented Programming that defines your data and defines how you can manipulate your data. Most of the actual migration work is done with the classes provide by the migrate module, you simply have to define the details of your migration./p pConstructor - The constructor modifies the migration modules classes to define your specific data. I was able to follow the SourceList method, this provides one xml (file or feed) that contains the ID number for all the content you want to import, and a second (file or feed) that contains the content. The wine example migrate has this but understanding what it really wants is more difficult to understand./p pBelow is my class file explained:br / =====================br / lt;?php/p p/**br / * @filebr / * Vision Article / *//p p/**br / * Vision Article migration / */br / class VisionArticleMigration extends XMLMigration {br / public function __construct() {br / parent::__construct();br / $this-gt;description = t('XML feed of Ektron Articles.');/p h3---------------br / So far pretty easy. You need to name your class, extend from the proper migration. and give it an extension. /h3p-----------------br //pp // There isn't a consistent way to automatically identify appropriatebr / // fields from an XML feed, so we pass an explicit list of source / $fields = array(br / 'id' =gt; t('ID'),br / 'lang_type' =gt; t('Language'),br / 'type' =gt; t('Type'),br / 'image' =gt; t('Image'),br / 'authors' =gt; t('Authors'),br / 'article_category' =gt; t('Article Category'),br / 'article_series_title' =gt; t('Article Series Title'),br / 'article_part_no' =gt; t('Article Series Part Number'),br / 'article_title' =gt; t('Article Title'),br / 'article_date' =gt; t('Article Date'),br / 'article_display_date' =gt; t('Article Display Date'),br / 'article_dropheader' =gt; t('Article Dropheader'),br / 'article_body' =gt; t('Article Body'),br / 'article_author_name' =gt; t('Article Author Name'),br / 'article_author_url' =gt; t('Article Author Email Address'),br / 'article_authors' =gt; t('Article Additional Authors'),br / 'article_postscript' =gt; t('Article Postscript'),br / 'article_link_text' =gt; t('Article Link text'),br / 'article_link' =gt; t('Article Link'),br / 'article_image' =gt; t('Article Image'),br / 'article_image_folder' =gt; t('Article Image Folder'),br / 'article_image_alt' =gt; t('Article Image Alt'),br / 'article_image_title' =gt; t('Article Image Title'),br / 'article_image_caption' =gt; t('Article Image Caption'),br / 'article_image_credit' =gt; t('Article Image Credit'),br / 'article_sidebar_element' =gt; t('Article Side Bar Content'),br / 'article_sidebar_element_margin' =gt; t('Article Margin between Sidebar Content'),br / 'article_archived_html_content' =gt; t('Article HTML Content from old system'),br / 'article_video_id' =gt; t('Article ID of Associated Video Article'),br / 'metadata_title' =gt; t('Metadata Title'),br / 'metadata_description' =gt; t('Metadata Description'),br / 'metadata_keywords' =gt; t('Metadata Keywords'),br / 'metadata_google_sitemap_priority' =gt; t('Metadata Google Sitemap Priority'),br / 'metadata_google_sitemap_change_frequency' =gt; t('Metadata Google Sitemap Change Freequency'),br / 'metadata_collection_number' =gt; t('Metadata Collection Number'),br / 'title' =gt; t('Title'),br / 'teaser' =gt; t('Teaser'),br / 'alias' =gt; t('Alias from old system'),br / 'taxonomy' =gt; t('Taxonomy'),br / 'created_date' =gt; t('Date Created')br / );/p h3 -------------------br / So what doe this mean?br / You will need a field name below. It has nothing to do with your xml file, you will need a field for each thing you want to import. Such as article_image_alt is the alt text for the image. Later you will define the xpath to load this variable. This will start to come together below, just remember each unique piece of information needs a variable. /h3p---------------------br //pp // The source ID here is the one retrieved from the XML listing URL, andbr / // used to identify the specific item's / $this-gt;map = new MigrateSQLMap($this-gt;machineName,br / array(br / 'ID' =gt; array(br / 'type' =gt; 'int',br / 'unsigned' =gt; TRUE,br / 'not null' =gt; TRUE,br / 'description' =gt; 'Source ID',br / )br / ),br / MigrateDestinationNode::getKeySchema()br / );/p h3 ---------------------br / This has to do with setting up the migration table in the database. This has to do with the input database, the Source ID is the field in the input file that has the pointer to the data record. My source file looks like: /h3p567br / 1054/p pSo we need a table with a field for the id which an integer./p p-----------------------br //pp // Source list / $list_url = 'a href=';br / // Each ID retrieved from the list URL will be plugged into :id in thebr / // item URL to fetch the specific / // @todo: Add langtype for importing translated / $item_url = 'a href=';/p p // We use the MigrateSourceList class for any source where we obtain thebr / // list of IDs to process separately from the data for each item. Thebr / // listing and item are represented by separate classes, so for example webr / // could replace the XML listing with a file directory listing, or the XMLbr / // item with a JSON / $this-gt;source = new MigrateSourceList(new MigrateListXML($list_url),br / new MigrateItemXML($item_url), $fields);/p p $this-gt;destination = new MigrateDestinationNode('vision_article');/p h3 ----------------- /h3pNow we are setting up the magic. We setup a list url that contains the ID's of all the content to import, then another one that uses this ID to fetch the details for this ID. Then you tell Migrate to use the MigrateListXML to find the items to import with MigrateItemXML. Then finally in the MigrateDestinationNode to tell Migrate which content type to use. This means we need a separate migration class for each content type to import. I have been creating each class in it's own inc file and adding this to the files section in the info file./p p-----------------br //pp // TIP: Note that for XML sources, in addition to the source field passed tobr / // addFieldMapping (the name under which it will be saved in the data rowbr / // passed through the migration process) we specify the Xpath used to retrievebr / // the value from the / $this-gt;addFieldMapping('created', 'created_date')br / -gt;xpath('/content/CreateDate');/p h3 ------------------br / Now we map the source field with the destination field. Created is the field name in the content type (vision_article), created_date is from our fields section above. Remember I said we needed a definiation for each part of the content we want to import. The xpath then points to the data in the xml feed. So this says take the content of the /contnet/CreateDate in the xml file and load this into the source variable created_date, then store this in the created field in a new vision_article content item. I say this in this way because if you do like me and cut and paste and forget to change the source varable, the source varable will contain the bottom data from xpath. /h3p------------------br //pp $this-gt;addFieldMapping('field_category', 'article_category')br / -gt;defaultValue(1)br / -gt;xpath('/content/html/root/article/Category');/p h3 ------------------- /h3pYou can set a default value in case the xml does not contain any data/p p----------br //pp $this-gt;addFieldMapping('field_series_title', 'article_series_title')br / -gt;xpath('/content/html/root/article/ArticleSeriesTitle');br / $this-gt;addFieldMapping('field_part_number', 'article_part_no')br / -gt;xpath('/content/html/root/article/ArticlePartNo');br / $this-gt;addFieldMapping('field_h1_title', 'article_title')br / -gt;arguments(array('format' =gt; 'filtered_html'))br / -gt;xpath('/content/html/root/article/Title');br / $this-gt;addFieldMapping('field_display_date', 'article_display_date')br / -gt;xpath('/content/html/root/article/DisplayDate');br / $this-gt;addFieldMapping('field_drophead', 'article_dropheader')br / -gt;arguments(array('format' =gt; 'filtered_html'))br / -gt;xpath('/content/Taxonomy');/p h3 ------------- /h3pAnother field argument, the default content type is plain text, so if your content contains HTML you need to set the correct format here./p p---------------br //pp $this-gt;addFieldMapping('body', 'article_body')br / -gt;arguments(array('format' =gt; 'filtered_html'))br / -gt;xpath('/content/html/root/article/Body');br / $this-gt;addFieldMapping('body:summary', 'teaser')br / -gt;arguments(array('format' =gt; 'filtered_html'))br / -gt;xpath('/content/Teaser');/p h3 ----------- /h3pNote you can set the teaser as a part of the body. One of the drush migrate commands make is easy to discover the additional parts of your content field, drush mfd (Migrate Field Destinations). This will display all the destination fields and their options./p p------------br //pp $this-gt;addFieldMapping('field_author', 'article_author_email')br / -gt;xpath('/content/html/root/article/AuthorURL');br / $this-gt;addFieldMapping('field_author:title', 'article_author_name')br / -gt;xpath('/content/html/root/article/AuthorName');br / $this-gt;addFieldMapping('field_ext_reference_title', 'article_postscript')br / -gt;arguments(array('format' =gt; 'filtered_html'))br / -gt;xpath('/content/html/root/article/Postscript');/p p---------br / see explanation belowbr / --------br / $this-gt;addFieldMapping('field_article_image:file_replace')br / -gt;defaultValue(MigrateFile::FILE_EXISTS_REUSE); //FILE_EXISTS_REUSE is in the MigrateFile classbr / $this-gt;addFieldMapping('field_article_images', 'article_image')br / -gt;xpath('/content/html/root/article/Image/File/img/file_name');br / $this-gt;addFieldMapping('field_article_images:source_dir', 'article_image_folder')br / -gt;xpath('/content/html/root/article/Image/File/img/file_path');br / $this-gt;addFieldMapping('field_article_images:alt', 'article_image_alt')br / -gt;xpath('/content/html/root/article/Image/File/img/@alt');br / $this-gt;addFieldMapping('field_article_images:title', 'article_image_title')br / -gt;xpath('/content/html/root/article/Image/File/img/@alt');/p h3 -------------- /h3pThis section gets tricky. You are importing an Image or other file. The default migration for a file is MigrateFileUrl. You can migrate all your files ahead of time or as I am doing do it inline. The main components for this is the main field, which is the file name, and the source_dir for the path to this image. Drual 7 has a database table for the files is uses with the url to the file. MigrateFile then uploads this file to the public folder and creates an entry into the files_,amaged table to indicate the url. What I did was copy all the images to a public location on S3 storage so I did not want Migrate to create a new file but use the existing file. Thus the file_replace setting to the constant MigrateFile::FILE_EXISTS_REUSE. This tells migrate to use the existing file and make an entry in the file_managed table for this file./p pLater in the PrepareRow method I will show how we separate this and add it to the xml./p p------------br //pp $this-gt;addFieldMapping('field_archive', 'article_archived_html_content')br / -gt;xpath('/content/archive_html');br / $this-gt;addFieldMapping('field_ektron_id', 'id')br / -gt;xpath('/content/ID');br / $this-gt;addFieldMapping('field_ektron_alias', 'alias')br / -gt;xpath('/content/html/Alias');br / $this-gt;addFieldMapping('field_sidebar', 'article_sidebar_element')br / -gt;arguments(array('format' =gt; 'filtered_html'))br / -gt;xpath('/content/html/root/article/SidebarElement/SidebarElementInformation');br / $this-gt;addFieldMapping('field_slider_image:file_replace')br / -gt;defaultValue(MigrateFile::FILE_EXISTS_REUSE); //FILE_EXISTS_REUSE is in the MigrateFile classbr / $this-gt;addFieldMapping('field_slider_image', 'image')br / -gt;xpath('/content/Image/file_name');br / $this-gt;addFieldMapping('field_slider_image:source_dir', 'image_folder')br / -gt;xpath('/content/Image/file_path');br / $this-gt;addFieldMapping('field_slider_image:alt', 'image_alt')br / -gt;xpath('/content/Title');br / $this-gt;addFieldMapping('field_slider_image:title', 'image_title')br / -gt;xpath('/content/Title');br / $this-gt;addFieldMapping('title', 'title')br / -gt;xpath('/content/Title');br / $this-gt;addFieldMapping('title_field', 'title')br / -gt;xpath('/content/Title');/p p // Declare unmapped source / $unmapped_sources = array(br / 'article_author_url',br / 'article_authors',br / 'article_sidebar_element_margin',br / 'article_video_id',br / 'metadata_title',br / 'metadata_description',br / 'metadata_keywords',br / 'metadata_google_sitemap_priority',br / 'metadata_google_sitemap_change_frequency',br / 'metadata_collection_number',/p p );/p h3 ------------- /h3pIf you are not using a source field, best practices state that you declare it in the unmapped sources/p p------------br //pp $this-gt;addUnmigratedSources($unmapped_sources);/p p // Declare unmapped destination / $unmapped_destinations = array(br / 'revision_uid',br / 'changed',br / 'status',br / 'promote',br / 'sticky',br / 'revision',br / 'log',br / 'language',br / 'tnid',br / 'is_new',br / 'body:language',br / );/p h3 ---------------------- /h3pIf you are not using a destination field best practices state that you declare in the unmaped destinations array. Note if you later use this field you need to remove it from the unused array./p p---------------------br //pp $this-gt;addUnmigratedDestinations($unmapped_destinations);/p p if (module_exists('path')) {br / $this-gt;addFieldMapping('path')br / -gt;issueGroup(t('DNM'));br / if (module_exists('pathauto')) {br / $this-gt;addFieldMapping('pathauto')br / -gt;issueGroup(t('DNM'));br / }br / }br / if (module_exists('statistics')) {br / $this-gt;addUnmigratedDestinations(array('totalcount', 'daycount', 'timestamp'));br / }br / }/p p------------/p pThe rest of the constructor is from the example. Did not cause me a problem so did not worry about it./p p------------br / /**br / * {@inheritdoc}br / *//p h3 --------------- /h3pNow we can add our own magic. We can effect the data from the content item before it is saved in to the content item. /p p-----------------br //pp public function prepareRow($row) {br / if (parent::prepareRow($row) === FALSE) {br / return FALSE;br / }br / $ctype = (string)$row-gt;xml-gt;Type;br / //set variable for return codebr / $ret = FALSE;br / //dpm($row);/p h3 ------------ /h3pYou will see these scattered through the prepareRow function. These are the devel command to print to the screen for debuging. They should be commented out but you can see the process I went through to debug my particular prepareRow. Also note this is a great use of the Migrate UI, these print statment only help you in the web interface, if you use Drush you will not see these diagnostic prints./p p---------------br //pp if ($ctype == '12'){/p h3 --------------- /h3pThis is specific to my migrate. The following code is only applicable to a content type of 12. The other content types have a different data structure. If prepareRow returns False the row will be skipped./p p------------------br //pp // Map the article_postscript source field to the new destination / //if((string)$row-gt;xml-gt;root-gt;article-gt;Title == ''){br / // $row-gt;xml-gt;root-gt;article-gt;Title = $row-gt;xml-gt;root-gt;Title;br / //}br / $postscript = $row-gt;xml-gt;html-gt;root-gt;article-gt;Postscript-gt;asXML();br / $postscript = str_replace('','',$postscript);br / $postscript = str_replace('','',$postscript);br / $row-gt;xml-gt;html-gt;root-gt;article-gt;Postscript = $postscript;/p h3 ------------------- /h3pAgain this is something unique to my migrate. The content structure is contained in xml so the HTML is recognized by SimpleXML as xml. So the asXML() function returns a string containing the xml of the node. Now I can save this string to the node and it becomes a string node and is back to straight html. So I need to do this for all the nodes that contain html. Most of the time you will be able to pass the html string as a node and will not have to do this transform./p p-------------------br //pp //converts html nodes to string so they will / $body = $row-gt;xml-gt;html-gt;root-gt;article-gt;Body-gt;asXML();br / $body = str_replace('','',$body);br / $body = str_replace('','',$body);br / $row-gt;xml-gt;html-gt;root-gt;article-gt;Body = $body;br / $title = $row-gt;xml-gt;html-gt;root-gt;article-gt;Title-gt;asXML();br / $title = str_replace('','',$title);br / $title = str_replace('','',$title);br / $row-gt;xml-gt;html-gt;root-gt;article-gt;Title = $title;br / $drophead = $row-gt;xml-gt;html-gt;root-gt;article-gt;Dropheader-gt;asXML();br / $drophead = str_replace('','',$drophead);br / $drophead = str_replace('','',$drophead);br / //If Dropheader is emptybr / $drophead = str_replace('','',$drophead);br / $row-gt;xml-gt;html-gt;root-gt;article-gt;Dropheader = $drophead;br / //Array to allow conversion of Category text to ISbr / $cat_tax = array(br / 'Science and Environment' =gt; 1,br / 'History' =gt; 2,br / 'Social Issues' =gt; 3,br / 'Family and Relationships' =gt; 4,br / 'Life and Health' =gt; 5,br / 'Religion and Spirituality' =gt; 6,br / 'Biography' =gt; 7,br / 'Ethics and Morality'=gt; 8,br / 'Society and Culture' =gt; 9,br / 'Current Events and Politics' =gt; 10,br / 'Philosophy and Ideas' =gt; 11,br / 'Personal Development' =gt; 12,br / 'Reviews' =gt; 13,br / 'From the Publisher' =gt; 14,br / 'Interviews' =gt; 17,br / );br / //Convert additional taxonomies to tagsbr / //$tax_id_in = (string)$row-gt;xml-gt;Taxonomy;br / //$tax_id_array = explode(',',$tax_id_in);br / //$tax_in_array = array();br / //foreach($tax_id_array as $tax){br / // If(is_null($cat_tax[tax]))br / // $tax_in_array[] = $cat_tax[$tax];br / //}br / //$new_tax = implode(',',$tax_in_array);br / //dpm($new_tax);br / //dpm($row);br / //$row-gt;xml-gt;Taxomomy = $new_tax;br / // Change category text to IDbr / $category = (string)$row-gt;xml-gt;html-gt;root-gt;article-gt;Category;br / //Specify unknown category if we do not recognize the categorybr / //This allows the migrate and allow us to fix / $tax_cat = $cat_tax[trim($category)];br / //dpm($category);br / if(is_null($tax_cat)) {$tax_cat = 18;}br / //dpm($tax_cat);br / $row-gt;xml-gt;html-gt;root-gt;article-gt;Category = $tax_cat;/p h3 ------------- /h3pThe category field in the source is a text field. The categories are a entity reference to a taxonomy field, which requires an id rather than text. I manually setup the categories ahead of time so I created an array that has the text as the key and the is as the content. Then you can use this to quickly look up the id for the text in he category field. Then we can replace the text in Category with the id. This works, another way to do this is migrate the categories first then use this migration to translate this for you. This is a feature built into migrate. The explanation of this will come later./p p----------------br //pp //modify the image file / //dpm((string)$row-gt;xml-gt;ID);br / if((string)$row-gt;xml-gt;html-gt;root-gt;article-gt;Image-gt;File-gt;asXML() != ''){br / //dpm((string)$row-gt;xml-gt;html-gt;root-gt;article-gt;Image-gt;File-gt;asXML());br / $src = (string)$row-gt;xml-gt;html-gt;root-gt;article-gt;Image-gt;File-gt;img-gt;attributes()-gt;src;br / $src_new = str_replace('/visionmedia/uploadedImages/','a href=',$src);br / $row-gt;xml-gt;html-gt;root-gt;article-gt;Image-gt;File-gt;img-gt;attributes()-gt;src = $src_new;br / $file_name = basename($src_new);br / $file_path = rtrim(str_replace($file_name,'', $src_new), '/');;br / $row-gt;xml-gt;html-gt;root-gt;article-gt;Image-gt;File-gt;img-gt;addChild('file_name',$file_name);br / $row-gt;xml-gt;html-gt;root-gt;article-gt;Image-gt;File-gt;img-gt;addChild('file_path',$file_path);br / }/p h3 -------------- /h3pThere is alot of stuff here. Remember for the MigrateFile you need to present the file name and source directory. The Image/File node contains an img tag. So we need to get the scr attribute and extract the file name and source directory. So why the if? Migrate will import a null node as null, but this is php code running on the row. If you try to get the src attribute on a null node it will throw an error. So the if statement checks to see if the File node is empty (only contains /File) and skips this tranformation, Migrate will simply import a null or empty field./p pThe src is the relative path to the website, so the first thing we do is change this to full url to the s3 content storage. The path is basically the same except in the uploadedimages the i in the database is uppercase. This was a Windows server so it did not make a difference but the s3 url is case sensitive. We then use base name to extract the file name and use this to remove the file from the path for the file path and create a new child in the xml row to store these. I did not point this out but this is the xpath use in the field mapping above./p p--------------br //pp $email = (string)$row-gt;xml-gt;html-gt;root-gt;article-gt;AuthorURL;br / if (!empty($email)){br / $email = 'mailto:'.$email;br / $row-gt;xml-gt;html-gt;root-gt;article-gt;AuthorURL = $email;br / }/p h3 ------------- /h3pThe author url is the email to the author of the article. We turn this into a mailto link so that it will generate a link to send the author an email./p p---------------br //pp $archive_html = (string)$row-gt;xml-gt;html-gt;asXML();br / $row-gt;xml-gt;addChild('archive_html',$archive_html);br / $sidebar_element = (string)$row-gt;xml-gt;html-gt;root-gt;article-gt;SidebarElement-gt;SidebarElementInformation-gt;asXML();br / $row-gt;xml-gt;html-gt;root-gt;article-gt;SidebarElement-gt;SidebarElementInformation = $sidebar_element;br / $slider_src = (string)$row-gt;xml-gt;Image;br / $slider_src_new = str_replace('/visionmedia/uploadedImages/','a href=',$slider_src);br / $row-gt;xml-gt;Image = $slider_src_new;br / $slider_file_name = basename($slider_src_new);br / $slider_file_path = rtrim(str_replace($slider_file_name,'', $slider_src_new), '/');;br / $row-gt;xml-gt;Image-gt;addChild('file_name',$slider_file_name);br / $row-gt;xml-gt;Image-gt;addChild('file_path',$slider_file_path);br / //dpm($row);/p p---------------/p pThe rest is repitition of the above techniques. Note that we return TRUE if we want to process the row and false if we do not want to process the row./p p-----------------br //pp$ret=TRUE;br / //dpm($src);br / }br / //Need to add processing for other Article Content types especially 0 (HTML content)br / //dpm($row);br / return $ret;br / }/p p}/p h3 ---------- /h3pThis is the class I use for one of the imports. I told you that I would show the use of another migrate in the field mappings. Below is a snippet of code from the issues migration. The issue contains entity reference to vision_articles that were imported from above./p p-------------br //pp $this-gt;addFieldMapping('field_articles', 'article_id')br / -gt;sourceMigration('VisionArticle')br / -gt;xpath('/item/articles/article/ID'); /p h3 -------------- /h3pSo this says use the VisionArticle (I will show you were to find this next), it knows to look up the source ID and relate it to the DestinationID and store this in the field_articles field./p p---------------/p pMigrate has been around for a while. Initially they said that the class would automaticall be registed and you could manually register them if needed. Then they changed to say that they will not manually register and you should register your classes. So you should have as part of your migration module the following that will register your classes. Note the name of the array element is the name used above./p p----------------br //ppfunction vision_migrate_migrate_api() {br / $api = array(br / 'api' =gt; 2,br / // Give the group a human readable / 'groups' =gt; array(br / 'vision' =gt; array(br / 'title' =gt; t('Vision'),br / ),br / ),br / 'migrations' =gt; array(br / 'VisionArticle' =gt; array('class_name' =gt; 'VisionArticleMigration'),br / 'VisionIssue' =gt; array('class_name' =gt; 'VisionIssueMigration'),br / 'VisionVideoArticle' =gt; array('class_name' =gt; 'VisionVideoArticleMigration'),br / 'VisionFrontpage' =gt; array('class_name' =gt; 'VisionFrontpageMigration'),br / ),br / );/p p return $api;br / } /p h3 ---------------- /h3pI hope this makes things a little easier to understand. You will need some basic module building skills, knowing the file names and things like that, but this should help you through the more obscure parts of creating your migration class./p /div/div/divdiv class=field field-name-field-tags field-type-taxonomy-term-reference field-label-inline clearfixdiv class=field-labelTags:nbsp;/divdiv class=field-itemsdiv class=field-item evena href=/tags/planet-drupal typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=Planet Drupal/a/div/div/div

Drupal Association News: Why we moved to a CDN

Tue, 07/22/2014 - 19:54
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item evenpAs of a little after 19:00 UTC on 2 July 2014, is now delivering as many sites as possible via our a href= CDN./p h2 a href= a CDN/a?/h2 pWe are primarily concerned with the network level security that a CDN will provide pThe CDN enables us to restrict access to our origin servers and disallow directly connecting to origin web nodes (which is currently possible). The two big advantages are:/p olli Accelerate cacheable content (static assets, static pages, etc)./li li Allow us to easily manage network access and have a very large network in front of ours to absorb some levels of attacks./li /olpHere are some examples of how the CDN helps ulli We were having issues with a .js file on The network was having routing issues to Europe and people were complaining about stalling on page loads. There was basically nothing we could do but wait for the route to get better. This should never be a problem again with EdgeCast's global network./li li We constantly have reports of because blacklisted because it serves a ton of traffic coming in and out of a small number of IP addresses. This should also not happen again because the traffic is distributed through EdgeCast's network./li li A few months ago we were under consistent attack from a group of IPs that was sub-HTTP and was saturating the origin network's bandwidth. We now have EdgeCast's large network in front of us that can 'take the beating'./li /ulh2 pBy enabling EdgeCast's raw logs, rsync, and caching features, we were able to offload roughly 25 Mbps of traffic from our origin servers to EdgeCast. This change resulted in a drastic drop in origin network traffic, which freed up resources for The use of rsync and the raw log features of EdgeCast enabled us to continue using our current project usage statistics tools. We do this by syncing the access logs from EdgeCast to’s utility server that processes project usage statistics./p h2 img alt=CDN caching results screenshot src= style=width: 494px; height: 192px; //h2 h2 pMinutes after switching to use the CDN, there were multiple reports of faster page load times from Europe and North America./p pA quick check from France / / Pre-CDN results: first page load=4.387s. repeat view=2.155sbr / Post-CDN results: first page load=3.779s, repeat view=1.285s/p h2 Why was the rename required?/h2 pOur CDN uses a combination of a href= IP addresses/a and DNS trickery. Each region (Asia, North America, Europe, etc.) has an Anycast IP address associated with it. For example might resolve to in North America, and in Japan./p pSince,, etc. are Anycast IPs, generally their routes are as short as possible, and the IP will route to whatever POP is closest. This improves network performance globally./p h2 Why can't be a CNAME?/h2 pThe DNS trickery above works by using a CNAME DNS record. must be an A record because the root domain cannot be a CNAME. MX records and any other records are a href= allowed by the RFC on CNAME records/a. To work around this DNS limitation, URLs are now redirected to p /p p /p pstrongRelated issues/strongbr /a href= /a href= /div/div/div

Stanford Web Services Blog: Cherry Picking - Small Git lesson

Tue, 07/22/2014 - 18:56
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item even property=content:encodedp class=summarySmall commits allow for big wins./p p class=summarySomething that I have been using a lot lately is GIT's cherry pick command. I find the command very usefull and it saves me bunches of time. Here is a quick lesson on what it does and an example use case./p h3spanWhat is GIT cherry-pick? a href= rel=nofollowman page/a/span/h3 pspanGit cherry pick allows you to merge a single commit from one branch into another.  To use the cherry pick command follow these steps:/span/p/div/div/div

2bits: Improve Your Drupal Site Performance While Reducing Your Hosting Costs

Tue, 07/22/2014 - 17:00
We were recently apporached by a non-profit site that runs on Drupal. Major Complains Their major complaint was that the quot;content on the site does not show upquot;. The other main complain is that the site is very slow. Diagnosis First ... In order to troubleshoot the disappearing content, we created a copy of the site in our lab, and proceeded to test it, to see if we can replicate the issues. pa href= target=_blankread more/a/p

Drupalize.Me: Drupal 8 Has All the Hotness, but So Can Drupal 7

Tue, 07/22/2014 - 15:30
div class=field field-name-body field-type-text-with-summary field-label-hidden text-content text-secondarydiv class=field-itemsdiv class=field-item evenpDrupal 8 is moving along at a steady pace, but not as quickly as we all had hoped. One great advantage this has is it gives developers time to backport lots of the features Drupal 8 has in core as modules for Drupal 7. My inspiration and blatant rip-off for this blog came from the presentation fellow Lullabot Dave Reid did at Drupalcon Austin about how to Future-Proof Your Drupal 7 Site. Dave’s presentation was more about what you can do to make your Drupal 7 “ready” where this article is more about showing off Drupal 8 “hotness” that we can use in production today./p /div/div/div