Newsfeeds

NonAutocomplete Widget

New Drupal Modules - 4 December 2018 - 8:09am

This module provides an entityreference widget that does not show autocomplete suggestions. Note that this does not change any access restrictions on the referenced entities nor change the autocomplete callback (so technically versatile people can use it to get the autocomplete suggestions anyway).

Categories: Drupal

Elfsight PayPal Button

New Drupal Modules - 4 December 2018 - 6:53am
Introduction

Elfsight PayPal Button provides a simple way to allow your customers to make payments via PayPal on your website. It enables you to create buttons for single payments that can include taxes and shipping price; subscriptions with recurring option; and donations with specified or open value. Localization and wide choice of currencies will help make transactions comfortable for you and your clients. Set up a smooth and secure payment procedure for your clients using one of the most reputable payment tools in seconds.

Categories: Drupal

Your Inner Fish That Wants to Play: What Anthropology Has to Say about Games - by Sergei Anankin

Gamasutra.com Blogs - 4 December 2018 - 6:37am
A personal inquiry into anthropological reasons of playing in an attempt to derive some game design suggestions from our inherited desires, needs and behaviors.
Categories: Game Theory & Design

The Design Lessons Designers Fail to Learn From Dark Souls - by Josh Bycer

Gamasutra.com Blogs - 4 December 2018 - 6:31am
The success of Dark Souls has spawned many imitators, and for today's post, we're going to look at the common elements people get wrong when analyzing Souls-Like design.
Categories: Game Theory & Design

Commerce Balance Field

New Drupal Modules - 4 December 2018 - 6:19am

Adds a pseudo-field to the Manage Display tab of the commerce order which will display the order balance of the order.

Categories: Drupal

How Enemy AI works in Dicey Dungeons - by Terry Cavanagh

Gamasutra.com Blogs - 4 December 2018 - 6:09am
A detailed write up how the new Enemy AI works in my game, Dicey Dungeons! I tried to write it in a "popular science" style that's hopefully of interest to everyone, not just programmers.
Categories: Game Theory & Design

The Ultimate RPG Character Backstory Guide Review

Gnome Stew - 4 December 2018 - 5:00am

I really enjoy books about roleplaying games. Not just products that are rulebooks, supplements, or adventures, but products that discuss the process of roleplaying. I enjoy products that discuss how to run games, and how to play them. Even in a single game system, the value added to long-term play by looking at the game from multiple directions is tremendous.

There is no shortage of books that look at roleplaying games from the perspective of game moderators. In fact, some of the other gnomes have been involved in some amazing books on the topics of preparing, managing, and executing various games at the table. What is less common is a book about roleplaying that isn’t designed for a particular system that is aimed squarely at players instead of moderators.

There is an increasing number of games that give players an opportunity to flesh out their player characters in deep and interesting ways. Traveller was one of the earliest RPGs to address detailed backstory with its lifepath system, which some modern games such as Modiphius’ Conan and Star Trek also use. Pathfinder includes Character Background rules in Ultimate Campaign. Shadow of the Demon Lord has some detailed character background tables in the core rules, which are expanded in the Victims of the Demon Lord line of supplements. The Dungeons and Dragons supplement Xanathar’s Guide to Everything also includes a detailed This is Your Life section that can be used to generate a more detailed backstory.

System specific backstory rules can be useful but are often created as a means of narrowing mechanically defined character options. In other words, these backstory elements often explain why a character picks the game elements they have for a character or narrows the options to help eliminate option paralysis. That doesn’t mean that those backstory systems are deficient, it just means that even the depth that is added in those systems may not touch on important backstory elements or motivations that a character might have.

The next natural extension of this would be for a player to have a guide that isn’t tied to a specific game system or setting. A guide aimed at getting a player to get inside their character’s head in a way that isn’t just a means of determining if they should specialize in using a sword or an axe. The Ultimate RPG Character Backstory Guide is a book that aims to add details to a character’s life story that aren’t just a means of justifying what game elements went into mechanically building that character.

The Chronicle of Chronicles

This review is based both on the paperback version of the book, and on the Kindle version.

The book is 272 pages long. It contains no illustrations, but does have solid formatting throughout, with headers, bullet points, lists, and call out boxes. The colors present in the book are black and orange-red. The formatting for the various bullet points and lists remains consistent in the Kindle version of the book. Because so much of the book is comprised of lists and questions, the formatting makes it very easy to follow from one exercise to another.

Introduction and What Can We Accomplish?

The first three pages of the book establish the goal of this work. There are numerous exercises in the book to help a player find the perspective of their character. These exercises are largely written with a game like Dungeons and Dragons in mind, but the What Can We Accomplish section helps to define the power level and experience of a player for which an exercise is written.

Humble Beginnings

As you might expect from the title, these exercises are for low-level characters to help determine how they got into adventuring in the first place, and how they determine party dynamics as they first begin to work with one another. The suggested character range is levels 1-7, but that’s essentially short hand for adventurers that are still relatively new to adventuring.

The following exercises exist in this section:

  • Idioms
  • Save the Cat
  • Holidays
  • What Gets Left Behind
  • Beanstalk
  • Five Lessons
  • Ventur
  • My Associates
  • Across a Crowded Tavern
  • Orphan Details
  • What Can You Do For Me?
  • A Matter of Status
  • What Drives You Forward?
  • Where I’m From
  • Finders Keepers
  • Well Worn
  • Five Things You Packed but Shouldn’t Have
  • Of the Cloth
  • Five Fears
  • What Does It Mean to Be . . . ?
  • Private Mysteries
  • Prophesy Half-Remembered
  • On the Line
  • Red Flags
  • Damn Merlinials
  • Rival
  • The Taming of the Wolverine
  • My Grimoire
  • Familiar, but Not Too Familiar
  • A Touch of Home
  • Vision of the Future
  • Mentor
  • Magic Mirrors
  • Visualizing Intellect

Some of these exercises cover the basics you would expect when discussing a character’s backstory, like the very basics of where they were from, and the people that they knew. Other exercises go a bit deeper, examining how a member of the party would petition another to gain their help for a goal, as well as examining what it means to have interactions with characters that have a different status (higher or lower) than the player character.

Some of the exercises are relatively straightforward, while others are multi-step procedures that build on the answers provided in previous steps.

Veteran Heroes 

These are questions geared towards characters that have been adventuring for a while. The level range provided for a more traditional D&D style game is 8-14, but it’s easy enough to use this for characters that have been working as adventurers for a significant amount of time in non-level-based systems.

The exercises in this section include the following:

  • Five Scars
  • Wed, Bed, or Behead
  • The One that Got Away
  • Never Have I Ever . . .
  • Last Will
  • My Friends
  • I Know You From Somewhere
  • Five Things You Can’t Throw Away
  • These Things Rarely Work Out
  • A Traveler’s Taste
  • I’ve Heard Stories About These
  • Cursed
  • We Clean Up Well
  • Song of Folly
  • Old Haunts
  • Atonement
  • Wanted
  • It’s More Than Personal
  • Movements of a Master
  • Campfire
  • Hero’s Best Friend
  • Unheard Confession
  • A Taste of Death
  • Conquered Fear
  • Getting to Know You
  • A Show of Force
  • Five Times Your Name Was Cursed
  • Mountains and Molehills
  • Life Goes On
  • In the Eye of My Enemy
  • Irrational Taste
  • Fish Story
  • You Have No Idea
  • The Gauntlet
  • Honey Pot
  • Trusty Steed

The exercises in this section are designed to add details that characters may not have thought to stop and add as they began to advance in levels or get more adventures under their belts. Many of them examine how the appearance of a character may have changed, or how they might describe their fighting style or abilities differently now.

Instead of having exercises about how the group deals with sudden adversity, there are exercises that look at how the group would plan for events that they know are coming. Additionally, there are exercises that ask about what supporting characters and areas look like now that the PCs have left their mark.

Some of my personal favorites are “I’ve Heard Stories About These,” which is a generator for coming up with wildly inaccurate things a character might believe about a monster they still haven’t run into at this point in their career, and “Fish Stories,” which is a guide to determining how exaggerated an exploit from your past has become. I couldn’t help but think of the Hero of Canton from Firefly.

Myths and Legends

The final section of exercises is recommended for characters of levels 15-20, or at least those adventurers that have become larger than life in the campaign.

The exercises for this section include:

  • Tower of Terror
  • Monuments
  • Classifying Villains
  • Home Heraldry
  • “It Is My Distinct Please to Announce . . . “
  • God, No
  • Five Commandments
  • Pocket Dimension
  • For the Myth that Has Everything
  • Inventory
  • Art of Facts
  • Terror of Wisdom
  • A Cutlass Carol
  • Private Secrets
  • It Sounds Good on Paper
  • I Knew Them Well
  • Alive Only in Memory
  • Collecting Dust
  • Sign of a Legend
  • Hobby
  • Five Lives
  • You Made It Weird
  • In the Eyes of Mortals
  • Hangover
  • Apprentice
  • Five Enemies
  • Impossible Trial
  • Not Looking to Get Merlined
  • Crisis of Faith
  • Your Kind of King

The exercises in this section deal with campaign elements such as how a character may have made a major change in the setting without contemplating the ramifications, as well as looking forward to how the character’s actions will be viewed in a historical context. There are also exercises that look at how many enemies a character has vanquished and what that means, people and places that are long gone, and how supporting characters in the service of the player character operate or act.

Some of my favorites in the section are “God, No,” which is an exercise that details how the player character would deal with a visit from a deity, and “For the Myth That Has Everything,” which is about trying to determine what you could provide your fellow epic player characters as a gift.

Ultimate Ups The book does a wonderful job of bringing up motivations and off-screen events that neither a player nor a game moderator would commonly think to add to a game. 

The book is a great resource for thought exercises. Just reading through the exercises without doing them is entertaining, but there are some deep character examinations that can evolve by following several of the multi-step procedures.

Wandering Guide

It’s not really a downside, but because there are so many exercises, it may be easy to get lost in them if you really want to specifically narrow down some details about your character. Being written through the lens of games with similar conventions to Dungeons and Dragons means that some exercises will either not be as useful to non-fantasy gamers or may take a little bit of adaptation to be useful. Some of the exercises, by default, give the player a little more world-building authority than a game moderator may be willing to hand out, especially if they are playing in an established setting. While entertaining, some of the exercises exist just to be humorous, and don’t do much to flesh out the backstory or history of a character.

Recommended–If the product fits in your broad area of gaming interests, you are likely to be happy with this purchase.

Anyone that has been a player in an RPG is likely to get some enjoyment from this product, even if it is geared towards fantasy gaming. Even without using it to flesh out a specific character, the various exercises are both entertaining and instructive about the kinds of elements players may want to add to a character. Reading the exercises is also likely to give a game moderator some ideas about what questions they want to answer over the long term in established campaigns.

What are your favorite system agnostic, player-facing products? How often do you read products about roleplaying games that aren’t about a specific system or genre? We would love to hear from you in the comments below!

Categories: Game Theory & Design

ComputerMinds.co.uk: Open links in popups with Foundation

Planet Drupal - 4 December 2018 - 3:16am

Let me take you on a journey. We'll pass by Drupal content renderer services, AJAX commands, javascript libraries and a popular front-end framework. If you've only heard of one or two of those things, come lean on the experience I took diving deep into Drupal. I'm pleased with where my adventure took me to, and maybe what I learned will be useful to you too.

Here's the end result: a contact form, launched from a button link in the site header, with the page beneath obscured by an overlay. The form allows site visitors to get in touch from any page, without leaving what they were looking at.

Drupal has its own API for making links launch dialogs (leveraging jQuery UI Dialogs). But our front-end of the site was built with Foundation, the super-popular theming framework, which provides components of its own that are much better for styling. We often base our bespoke themes on Foundation, and manipulate Drupal to fit.

We had already done some styling of Foundation's Reveal component. In those places, the markup to show in the popup is already in the page, but I didn't really want the form to be in the page until it was needed. Instead, AJAX could fetch it in. So I wondered if I could combine Drupal's AJAX APIs with Foundation's Reveal markup and styling. Come with me down the rabbit hole...

There are quite a few components in making this possible. Here's a diagram:

So it comes down to the following parts, which we'll explore together. Wherever custom code is needed, I've posted it in full later in this article.

  • A link that uses AJAX, with a dialog type set in an attribute.
  • Drupal builds the content of the page that was linked to.
  • Drupal's content view subscriber picks up that response and looks for a content renderer service that matches the dialog type.
  • The content renderer returns an AJAX command PHP class in its response, and attaches a javascript library that will contain a javascript AJAX command (a method).
  • That command returns the content to show in the popup, and that javascript method name.
  • The javascript method launches the popup containing the HTML content.

Let's start at the beginning: the link. Drupal's AJAX API for links is pretty neat. We trigger it with two things:

  1. A use-ajax class, which tells it to open that link via an AJAX call, returning just the main page content (e.g. without headers & footers), to be presented in your existing page.
  2. A data-dialog-type attribute, to instruct how that content should be presented. This can be used for the jQuery UI dialogs (written up elsewhere) or the newer off-canvas sidebar, for example.

I wanted to have a go at creating my own 'dialog type', which would be a Foundation Reveal popup. The HTML fetched by the AJAX call would be shown in it. Let's start with the basic markup I wanted to my link to have:

Enquire

This could either just be part of content, or I could get this into a template using a preprocess function that would build the link. Something like this:

<?php // $url could have come from $node->toUrl(), Url::fromRoute() or similar. // For this example, it's come from a contact form entity. $url->setOption('attributes', [ 'class' => [ 'use-ajax', ], // This attribute tells it to use our kind of dialog 'data-dialog-type' => 'reveal', ]); // The variable 'popup_launcher' is to be used in the template. $variables['popup_launcher'] = \Drupal\Core\Link::fromTextAndUrl(t('Enquire'), $url);

After much reading around and breakpoint debugging to figure it out, I discovered that dialog types are matched up to content rendering services. So I needed to define a new one of those, which I could base closely on Drupal's own DialogRenderer. Here's the definition from my module's mymodule.services.yml file:

services: main_content_renderer.foundation_reveal: class: Drupal\mymodule\Render\MainContent\FoundationReveal arguments: ['@title_resolver'] tags: - { name: render.main_content_renderer, format: drupal_reveal }

Adding the tag named 'render.main_content_renderer' means my class will be picked up by core's MainContentRenderersPass when building the container. Drupal's MainContentViewSubscriber will then consider it as a service that can render responses.

The 'format' part of the tag needs to be the value that our data-dialog-type attribute has, with (somewhat arbitrarily?) 'drupal_' prepended. The arguments will just be whatever the constructor for the class needs. I often write my class first and then go back to adjust the service definition once I know what it needs. But I'll be a good tour guide and show you things in order, rather than shuttling you backwards and forwards!

Onto that FoundationReveal service class now. I started out with a copy of core's own ModalRenderer which is a simple extension to the DialogRenderer class. Ultimately, that renderer is geared around returning an AJAX command (see the AJAX API documentation), which comes down to specifying a command to invoke in the client-side javascript with some parameters.

I would need my own command, and my FoundationReveal renderer would need to specify it to be used. That only two functional differences were needed in comparison to core's DialogRenderer:

  1. Attach a custom library, which would contain the actual javascript command to be invoked:
$main_content['#attached']['library'][] = 'mymodule/dialog.ajax';
  1. Return an AJAX command class, that will specify that javascript command (rather than the OpenDialogCommand command that DialogRenderer uses) - i.e. adding this to the returned $response:
new OpenFoundationRevealCommand('#mymodule-reveal')

We'll learn about that command class later!

So the renderer file, mymodule/src/Render/MainContent/FoundationReveal.php (in that location in order to match the namespace in the service file definition), looks like this - look out for those two tweaks:

<?php namespace Drupal\mymodule\Render\MainContent; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Render\MainContent\DialogRenderer; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\mymodule\Ajax\OpenFoundationRevealCommand; use Symfony\Component\HttpFoundation\Request; /** * Default main content renderer for foundation reveal requests. */ class FoundationReveal extends DialogRenderer { /** * {@inheritdoc} */ public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match) { $response = new AjaxResponse(); // First render the main content, because it might provide a title. $content = drupal_render_root($main_content); // Attach the library necessary for using the OpenFoundationRevealCommand // and set the attachments for this Ajax response. $main_content['#attached']['library'][] = 'core/drupal.dialog.ajax'; $main_content['#attached']['library'][] = 'mymodule/dialog.ajax'; $response->setAttachments($main_content['#attached']); // Determine the title: use the title provided by the main content if any, // otherwise get it from the routing information. $title = isset($main_content['#title']) ? $main_content['#title'] : $this->titleResolver->getTitle($request, $route_match->getRouteObject()); // Determine the dialog options and the target for the OpenDialogCommand. $options = $request->request->get('dialogOptions', []); $response->addCommand(new OpenFoundationRevealCommand('#mymodule-reveal', $title, $content, $options)); return $response; } }

That AJAX command class, OpenFoundationRevealCommand sits in mymodule/src/Ajax/OpenFoundationRevealCommand.php. Its render() method is the key, it returns the command which will map to a javascript function, and the actual HTML under 'data'. Here's the code:

<?php namespace Drupal\mymodule\Ajax; use Drupal\Core\Ajax\OpenDialogCommand; use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Defines an AJAX command to open certain content in a foundation reveal popup. * * @ingroup ajax */ class OpenFoundationRevealCommand extends OpenDialogCommand { use StringTranslationTrait; /** * Implements \Drupal\Core\Ajax\CommandInterface:render(). */ public function render() { return [ 'command' => 'openFoundationReveal', 'selector' => $this->selector, 'settings' => $this->settings, 'data' => $this->getRenderedContent(), 'dialogOptions' => $this->dialogOptions, ]; } /** * {@inheritdoc} */ protected function getRenderedContent() { if (empty($this->dialogOptions['title'])) { $title = ''; } else { $title = '' . $this->dialogOptions['title'] . ''; } $button = 't('Close') . '" type="button">×'; return '' . $title . parent::getRenderedContent() . '' . $button; } }

Now, I've mentioned that the command needs to match a javascript function. That means adding some new javascript to the page, which, in Drupal 8, we do by defining a library. My 'mymodule/dialog.ajax' library was attached in the middle of FoundationReveal above. My library file defines what actual javascript file to include - it is mymodule.libraries.yml and looks like this:

dialog.ajax: version: VERSION js: js/dialog.ajax.js: {} dependencies: - core/drupal.dialog.ajax

Then here's that actual mymodule/js/dialog.ajax.js file. It adds the 'openFoundationReveal' method to the prototype of the globally-accessible Drupal.AjaxCommands. That matches the command name returned by my OpenFoundationRevealCommand::render() method that we saw.

(function ($, Drupal) { Drupal.AjaxCommands.prototype.openFoundationReveal = function (ajax, response, status) { if (!response.selector) { return false; } // An element matching the selector will be added to the page if it does not exist yet. var $dialog = $(response.selector); if (!$dialog.length) { // Foundation expects certain things on a Reveal container. $dialog = $('').appendTo('body'); } if (!ajax.wrapper) { ajax.wrapper = $dialog.attr('id'); } // Get the markup inserted into the page. response.command = 'insert'; response.method = 'html'; ajax.commands.insert(ajax, response, status); // The content is ready, now open the dialog! var popup = new Foundation.Reveal($dialog); popup.open(); }; })(jQuery, Drupal);

There we have it - that last bit of the command opens the Foundation Reveal popup dialog!

I should also add that since I was showing a contact form in the popup, I installed the Contact ajax module. This meant that a site visitor would stay within the popup once they submit the form, which meant for a clean user experience.

Thanks for following along with me!

Categories: Drupal

WeKnow: Improving Drupal and Gatsby Integration - The Drupal Modules

Planet Drupal - 4 December 2018 - 3:15am
Improving Drupal and Gatsby Integration - The Drupal Modules

At weKnow we are not only using Drupal, we also take contributing back very seriously and now is the time for improving the Drupal and Gatsby integration.

As mentioned in my personal blog, Moving weKnow's personal blog sites from Drupal to GatsbyJS, we have been using Gatsby with Drupal for projects as our decouple strategy lately, and after building a few sites with Drupal and Gatsby we found some challenges, which we resolved writing custom code. But now we’ve decided to share our knowledge as contributed modules.

Toast UI Editor

This module provides a markdown WYSIWYG editor integration for Toast UI Editor

jmolivas Tue, 12/04/2018 - 11:15
Categories: Drupal

Web Omelette: Simple Guzzle API mocking for functional testing in Drupal 8

Planet Drupal - 4 December 2018 - 12:05am

In this article I am going to show you a technique I used recently to mock a relatively simple external service for functional tests in Drupal 8.

Imagine the following scenario: you have an API with one or a few endpoints and you write a service that handles the interaction with it. For example, one of the methods of this service takes an ID and calls the API in order to return the resource for that ID (using the Guzzle service available in Drupal 8). You then cast the Guzzle response stream to a string and return whatever from there to use in your application. How can you test your application with this kind of requirements?

The first thing you can do is unit test your service. In doing so, you can pass to it a mock client that can return whatever you set to it. Guzzle even provides a MockHandler that you can use with the client and specify what you want returned. Fair enough. But what about things like Kernel or Functional tests that need to use your client and make requests to this API? How can you handle this?

It’s not a good idea to use the live API endpoint in your tests for a number of reasons. For example, your testing pipeline would depend on an external, unpredictable service which can go down at any moment. Sure, it’s good to catch when this happens but clearly this is not the way to do it. Or you may have a limited amount of requests you can make to the endpoint. All these test runs will burn through your budget. And let’s not forget you need a network connection to run the tests.

So let’s see an interesting way of doing this using the Guzzle middleware architecture. Before diving into that, however, let’s cover a few theoretical aspects of this process.

Guzzle middlewares

A middleware is a piece of functionality that can be added to the pipeline of a process. For example, the process of turning a request into a response. Check out the StackPHP middlewares for a nice intro to this concept.

In Guzzle, middlewares are used inside the Guzzle handler stack that is responsible for turning a Guzzle request into a response. In this pipeline, middlewares are organised as part of the HandlerStack object which wraps the base handler that does the job, and are used to augment this pipeline. For example, let’s say a Guzzle client uses the base Curl handler to make the request. We can add a middleware to the handler stack to make changes to the outgoing request or to the incoming response. I highly recommend you read the Guzzle documentation on handlers and middlewares for more information.

Guzzle in Drupal 8

Guzzle is the default HTTP client used in Drupal 8 and is exposed as a service (http_client). So whenever we need to make external requests, we just inject that service and we are good to go. This service is instantiated by a ClientFactory that uses the default Guzzle handler stack (with some specific options for Drupal). The handler stack that gets injected into the client is configured by Drupal’s own HandlerStackConfigurator which also registers all the middlewares it finds.

Middlewares can be defined in Drupal as tagged services, with the tag http_client_middleware. There is currently only one available to look at as an example, used for the testing framework: TestHttpClientMiddleware.

Our OMDb (Open Movie Database) Mock

Now that we have an idea about how Guzzle processes a request, let’s see how we can use this to mock requests made to an example API: OMDb.

The client

Let’s assume a module called omdb which has this simple service that interacts with the OMDb API:

<?php namespace Drupal\omdb; use Drupal\Core\Site\Settings; use Drupal\Core\Url; use GuzzleHttp\ClientInterface; /** * Client to interact with the OMDb API. */ class OmdbClient { /** * @var \GuzzleHttp\ClientInterface */ protected $client; /** * Constructor. * * @param \GuzzleHttp\ClientInterface $client */ public function __construct(ClientInterface $client) { $this->client = $client; } /** * Get a movie by ID. * * @param \Drupal\omdb\string $id * * @return \stdClass */ public function getMovie(string $id) { $settings = $this->getSettings(); $url = Url::fromUri($settings['url'], ['query' => ['apiKey' => $settings['key'], 'i' => $id]]); $response = $this->client->get($url->toString()); return json_decode($response->getBody()->__toString()); } /** * Returns the OMDb settings. * * @return array */ protected function getSettings() { return Settings::get('omdb'); } }

We inject the http_client (Guzzle) and have a single method that retrieves a single movie from the API by its ID. Please disregard the complete lack of validation and error handling, I tried to keep things simple and to the point. To note, however, is that the API endpoint and key is stored in the settings.php file under the omdb key of $settings. That is if you want to play around with this example.

So assuming that we have defined this service inside omdb.services.yml as omdb.client and cleared the cache, we can now use this like so:

$client = \Drupal::service('omdb.client'); $movie = $client->getMovie('tt0068646');

Where $movie would become a stdClass representation of the movie The Godfather from the OMDb.

The mock

Now, let’s assume that we use this client to request movies all over the place in our application and we need to write some Kernel tests that verify that functionality, including the use of this movie data. One option we have is to switch out our OmdbClient client service completely as part of the test, with another one that has the same interface but returns whatever we want. This is ok, but it’s tightly connected to that test. Meaning that we cannot use it elsewhere, such as in Behat tests for example.

So let’s explore an alternative way by which we use middlewares to take over any requests made towards the API endpoint and return our own custom responses.

The first thing we need to do is create a test module where our middleware will live. This module will, of course, only be enabled during test runs or any time we want to play around with the mocked data. So the module can be called omdb_tests and we can place it inside the tests/module directory of the omdb module.

Next, inside the namespace of the test module we can create our middleware which looks like this:

<?php namespace Drupal\omdb_tests; use Drupal\Core\Site\Settings; use GuzzleHttp\Promise\FulfilledPromise; use GuzzleHttp\Psr7\Response; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** * Guzzle middleware for the OMDb API. */ class OmdbMiddleware { /** * Invoked method that returns a promise. */ public function __invoke() { return function ($handler) { return function (RequestInterface $request, array $options) use ($handler) { $uri = $request->getUri(); $settings = Settings::get('omdb'); // API requests to OMDb. if ($uri->getScheme() . '://' . $uri->getHost() . $uri->getPath() === $settings['url']) { return $this->createPromise($request); } // Otherwise, no intervention. We defer to the handler stack. return $handler($request, $options); }; }; } /** * Creates a promise for the OMDb request. * * @param RequestInterface $request * * @return \GuzzleHttp\Promise\PromiseInterface */ protected function createPromise(RequestInterface $request) { $uri = $request->getUri(); $params = \GuzzleHttp\Psr7\parse_query($uri->getQuery()); $id = $params['i']; $path = drupal_get_path('module', 'omdb_tests') . '/responses/movies'; $json = FALSE; if (file_exists("$path/$id.json")) { $json = file_get_contents("$path/$id.json"); } if ($json === FALSE) { $json = file_get_contents("$path/404.json"); } $response = new Response(200, [], $json); return new FulfilledPromise($response); } }

Before explaining what all this code does, we need to make sure we register this as a tagged service inside our test module:

services: omdb_tests.client_middleware: class: Drupal\omdb_tests\OmdbMiddleware tags: - { name: http_client_middleware }

Guzzle middleware services in Drupal have one single (magic) method called __invoke. This is because the service is treated as a callable. What the middleware needs to do is return a (callable) function which gets as a parameter the next handler from the stack that needs to be called. The returned function then has to return another function that takes the RequestInterface and some options as parameters. At this point, we can modify the request. Lastly, this function needs to make a call to that next handler by passing the RequestInterface and options, which in turn will return a PromiseInterface. Take a look at TestHttpClientMiddleware for an example in which Drupal core tampers with the request headers when Guzzle makes requests during test runs.

So what are we doing here?

We start by defining the first two (callable) functions I mentioned above. In the one which receives the current RequestInterface, we check for the URI of the request to see if it matches the one of our OMDb endpoint. If it doesn’t we simply call the next handler in the stack (which should return a PromiseInterface). If we wanted to alter the response that came back from the next handler(s) in the stack, we could call then() on the PromiseInterface returned by the stack, and pass to it a callback function which receives the ResponseInterface as a parameter. In there we could make the alterations. But alas, we don’t need to do that in our case.

A promise represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its then method, which registers callbacks to receive either a promise's eventual value or the reason why the promise cannot be fulfilled.

Read this for more information on what promises are and how they work.

Now for the good stuff. If the request is made to the OMDb endpoint, we create our own PromiseInterface. And very importantly, we do not call the next handler. Meaning that we break out of the handler stack and skip the other middlewares and the base handler. This way we prevent Guzzle from going to the endpoint and instead have it return our own PromiseInterface.

In this example I decided to store a couple of JSON responses for OMDb movies in files located in the responses/movies folder of the test module. In these JSON files, I store actual JSON responses made by the endpoint for given IDs, as well as a catch-all for whenever a missing ID is being requested. And the createPromise() method is responsible for determining which file to load. Depending on your application, you can choose exactly based on what you would like to build the mocked responses.

The loaded JSON is then added to a new Response object that can be directly added to the FulfilledPromise object we return. This tells Guzzle that the process is done, the promise has been fulfilled, and there is a response to return. And that is pretty much it.

Considerations

This is a very simple implementation. The API has many other ways of querying for data and you could extend this to store also lists of movies based on a title keyword search, for example. Anything that serves the needs of the application. Moreover, you can dispatch an event and allow other modules to provide their own resources in JSON format for various types of requests. There are quite a lot of possibilities.

Finally, this approach is useful for “simple” APIs such as this one. Once you need to implement things like Oauth or need the service to call back to your application, some more complex mocking will be needed such as a dedicated library and/or containerised application that mocks the production one. But for many such cases in which we read data from an endpoint, we can go far with this approach.

Categories: Drupal

Advanced Designers & Dragons: Designers & Dragons Next — Fantasy Flight Games: 2004-Present

RPGNet - 4 December 2018 - 12:00am
A more in-depth look at Fantasy Flight Games over the last decade.
Categories: Game Theory & Design

Code Karate: Drupal 8 Rabbit Hole Module

Planet Drupal - 3 December 2018 - 8:03pm
Episode Number: 221

The Drupal 8 Rabbit Hole Module allows you to control what happens when someone views an entity page. Before you ask why this might be important, let me clarify, it's not a layout tool. It's a simple module that allows you to easily redirect or prevent users from viewing specific types on entities on your site.

Tags: DrupalContribDrupal 8Site BuildingDrupal Planet
Categories: Drupal

I'm not selling my Apple stock

Dries Buytaert - 3 December 2018 - 6:00pm

Apple had a rough year; its stock price has fallen 25% since the beginning of the year. Apple also reported a weaker than expected outlook and shared that it will no longer report individual unit sales, which many consider a bearish signal within a saturated smartphone market.

It's no surprise that this has introduced some skepticism with current Apple shareholders. A friend recently asked me if she should hold or sell her Apple stock. Her financial advisor suggested she should consider selling. Knowing that Apple is the largest position in my own portfolio, she asked what I'm planning to do in light of the recent troubles.

Every time I make an investment decision, I construct a simple narrative based on my own analysis and research of the stock in question. I wrote down my narrative so I could share it with her. I decided to share it on my blog as well to give you a sense of how I develop these narratives. I've shared a few others in the past — documenting my "investment narratives" is useful as it helps me learn from my mistakes and institutes accountability.

As a brief disclaimer, this post should be considered general information, and not a formal investment recommendation. Before making any investment decisions, you should do your own proper due diligence.

Over the last five years, Apple grew earnings per share at 16% annually. This is a combination of about 10% growth in net profit, combined with almost 6% growth as the result of share buybacks.

Management has consistently used cash to buy back five to six percent of the company's outstanding shares every year. At the current valuation and with the current strength of Apple's balance sheet, buybacks are a good use of a portion of their cash. Apple will likely see similar levels of cash generation in the coming years so I expect Apple will continue to buy back five to six percent of its outstanding shares annually. By reducing the number of shares on the market, buybacks lift a company's earnings per share by the same amount.

Next, I predict that Apple will grow net profits by six to seven percent a year. Apple can achieve six to seven percent growth in profits by growing sales and improving its margins. Margins are likely to grow due to the shift in revenue from hardware to software services. This is a multi-year shift so I expect margins to slowly improve over time. I believe that six to seven percent growth in net profits is both reasonable and feasible. It's well below the average 10% growth in net profits that we've seen in recent years.

Add 5-6% growth as the result of share buybacks to 6-7% growth in profit as a result of sales growth and margin expansion, and you have a company growing earnings per share by 12% a year.

If Apple sustains that 12% percent earnings per share growth for five years, earnings per share will grow from $11.88 today to $20.94 by the end of 2023. At the current P/E ratio of 15, one share of Apple would be worth $314 by then. Add about $20 in dividends that you'd collect along the way, and you are likely looking at market beating returns.

The returns could be better as there is an opportunity for P/E expansion. I see at least two drivers for that; (a) the potential for margin improvement as a result of Apple shifting its revenue mix, and (b) Apple's growing cash position (e.g. if you subtract the cash per share from the share price, the P/E increases).

Let's assume that the P/E expands from the current 15 to 18. Now, all of a sudden, you're looking at a per share price of $397 by the end 2023, and an average annual return of 18%. If that plays out, every dollar invested in Apple today, would double in five years — and that excludes the dividend you'd collect along the way!

Needless to say, this isn't an advanced forecasting model. Regardless, my narrative shows that if we make a few very reasonable assumptions, Apple could have a great return the next five years.

While Apple's day of disruption might be behind it, it remains one of the greatest cash machines of all time. Modest growth combined with a large buyback program and a relatively low valuation, can make for a great investment.

I'm not selling my Apple stock and I'd be tempted to buy more if the share price were to drop below $155 a share.

Disclaimer: I'm long AAPL. Before making any investment decisions, you should do your own proper due diligence. Any material in this article should be considered general information, and not a formal investment recommendation.

Categories: Drupal

Media Entity File Redirect

New Drupal Modules - 3 December 2018 - 5:32pm
Overview

This simple module allows you to configure the canonical path for media entities to redirect to the file source associated with them.

All media entities have a canonical path, like /media/[id], which renders the entity using the "full" view mode. For many media entity types, like documents, this default canonical page is usually pointless because the only thing on the page is a link to download the document. This module allows you to sidestep that page entirely and just redirect to the actual file URL.

Categories: Drupal

DrupalCon News: Community Connection - Kelly Tetterton

Planet Drupal - 3 December 2018 - 4:34pm

We’re featuring some of the people in the Drupalverse! This Q&A series highlights some of the individuals you could meet at DrupalCon. Every year, DrupalCon is the largest gathering of people who belong to this community. To celebrate and take note of what DrupalCon means to them, we’re featuring an array of perspectives and some fun facts to help you get to know your community.

Categories: Drupal

Video: Designing UX for board games

Social/Online Games - Gamasutra - 3 December 2018 - 3:22pm

In this GDC 2018 session, Foxtrot Games' Randy Hoyt explores the many details that board game publishers and producers consider when turning solid game prototypes into great product experiences. ...

Categories: Game Theory & Design

DrupalEasy: DrupalEasy Podcast 212 - Commerce Guys: decoupling and roadmap with Bojan Zivanovic and Matt Glaman

Planet Drupal - 3 December 2018 - 3:15pm

Direct .mp3 file download.

DrupalEasy Podcast 212 - Commerce Guys: decoupling and roadmap

Matt Glaman, (mglaman) and Bojan Zivanovic, (bojanz) join Mike live from Disney World to talk about decoupling Drupal Commerce as well as the roadmap for Drupal Commerce as a project. We take a quick side trip into some blog posts Matt recently wrote about running all of Drupal core's automated tests in DDEV-Local.

Interview DrupalEasy News Upcoming events Sponsors
  • Drupal Aid - Drupal support and maintenance services. Get unlimited support, monthly maintenance, and unlimited small jobs starting at $99/mo.
  • WebEnabled.com - devPanel.
Follow us on Twitter Subscribe

Subscribe to our podcast on iTunes, Google Play or Miro. Listen to our podcast on Stitcher.

If you'd like to leave us a voicemail, call 321-396-2340. Please keep in mind that we might play your voicemail during one of our future podcasts. Feel free to call in with suggestions, rants, questions, or corrections. If you'd rather just send us an email, please use our contact page.

Categories: Drupal

Jeff Geerling's Blog: Testing the 'Add user' and 'Edit account' forms in Drupal 8 with Behat

Planet Drupal - 3 December 2018 - 2:20pm

On a recent project, I needed to add some behavioral tests to cover the functionality of the Password Policy module. I seem to be a sucker for pain, because often I choose to test the things it seems there's no documentation on—like testing the functionality of the partially-Javascript-powered password fields on the user account forms.

In this case, I was presented with two challenges:

  • I needed to run one scenario where a user edits his/her own password, and must follow the site's configured password policy.
  • I needed to run another scenario where an admin creates a new user account, and must follow the site's configured password policy for the created user's password.

So I came up with the following scenarios:

Categories: Drupal

Don't Miss: Fostering camaraderie in game communities from the ground up

Social/Online Games - Gamasutra - 3 December 2018 - 11:28am

Smash Sisters founders Emily Sun and Lil Chen share practical learnings from their side events organized for women, by women in the Super Smash Bros. community. ...

Categories: Game Theory & Design

Devs say a problem with the Steam algorithm has severely hurt store page traffic

Social/Online Games - Gamasutra - 3 December 2018 - 11:12am

With no official word from Steam, devs aren†™t sure if it's a bug or an intentional change but many are saying that traffic to the pages for their games on Steam has seen a significant hit since October. ...

Categories: Game Theory & Design

Pages

Subscribe to As If Productions aggregator