Falcon

Why

Falcon is an open source project for charities.

Quick start

Follow instructions in Installation section.

Installation

Install Docker

You need to install Docker and Docker-compose. See https://docs.docker.com/install/ for details.

Make local environment

Open command line terminal, navigate to project root and run make install. If you want to adjust local environment settings then first run make stop and review the .env and .docker/docker-compose.override.yml files. After that run make install.

Then you can stop your work by running make stop and continue by running make up. To remove all the containers you can run make down.

Update local environment

If there were some changes in the upstream that render your local environment settings out of date - you need to update the .env and docker/docker-compose.override.yml files. There are 2 ways to do it - just remove them and run any make command or review them manually and compare with the sources:

  • .env file comes from .env.default
  • .docker/docker-compose.override.yml comes from .docker/docker-compose.override.default.yml.
Access the site

Go to http://frontend.docker.localhost to see the frontend and http://admin.docker.localhost to access the backend.

Configuration management

General approach

All configuration is stored in code. Any configuration change done directly on production environment will be reset on next deploy.

To allow clients to change configuration we should use the Config Pages module approach.

Testing

Overview

Falcon uses Codeception framework to test its functions, modules, features and API endpoints. Tests are integrated in development workflow using Circle CI.

Every time when someone opens a new pull request on Github, Circle CI executes the following tasks:

  • Checkout code from the corresponding git branch.
  • Spin up docker containers.
  • Install Falcon and all its features.
  • Run tests.

If you are interested in details of Falcon CI setup, you can find latest Circle CI configuration file here: https://github.com/systemseed/falcon/blob/master/.circleci/config.yml

Running tests on local

First, run make tests:prepare to initialize testing framework. Now, you can run all Codeception tests using make tests:run command. You can run a specific test suite by passing its name as a second parameter:

# Run API test suite only
make tests:run api
# Run unit test suite only
make tests:run unit

You can pass any extra options to codecept bin if you need:

# Run API tests from group "failed".
make tests:run api -- -g failed

Tests structure

There are two Codeception test suites in /tests folder: API and Unit. Both have connection to Drupal 8 API and to the database which allows developers to implement sophisticated and granular tests.

API tests

This type of tests is suitable for testing of API (REST) endpoints. You can find examples of API tests here: https://github.com/systemseed/falcon/tree/master/tests/api

Read more: https://codeception.com/docs/modules/REST#Actions

Unit tests

Suitable for classic unit tests and integration tests with runtime access to Drupal code and database.

You can find examples of unit tests here: https://github.com/systemseed/falcon/tree/master/tests/unit

Read more: https://codeception.com/docs/05-UnitTests

Writing tests

Each new feature, or API endpoint, or pure PHP function should be covered by tests.

When adding a new test to the Falcon distribution developer should decide if it will cover basic distribution installation or not. If it covers basic installation distribution it should be added to basic tests group. If not than it should be added to additional group. For example:

/**
 * @group basic
 */
public function testBasic()

If you wrote a test for additional group than you should add module this test covers into ADDITIONAL_MODULES variable in env.default file. It’s recommended to store tests in subfolders with the same name as Falcon module or feature to test. For example, if you want to test function falcon_development_install you need to put your test into tests/unit/falcon_development/ folder.

Before you start writing tests we recommend to run the following command:

# Optional. Creates ".codecept" folder with Codeception sources in project root.
make tests:autocomplete

It will enable autocomplete of available test methods in most of popular IDEs. Now you can start writing tests and run them using make tests:run.

To access codecept cli directly run:

make tests:cli

It will allow you to run codecept commands to generate new tests or run a specific test if you need. See list of available commands here: https://codeception.com/docs/reference/Commands

Contributing

Coding Standards

Falcon follows Drupal 8 Coding standards.

To check code on your local environment, run the following commands:

  1. make code:check - checks all PHP & Javascript code against Drupal and DrupalPractice coding standards.
  2. make code:fix - attempts to automatically fix some of found issues in PHP & Javascript code.

Documentation

We’d love to have you helping with Falcon documentation.

All documentation is stored in the main Falcon repo in docs folder. We use reStructuredText format and readthedocs.org hosting for our documentation.

Getting started

You can start contributing using GitHub edit feature. All you need to do is to clone the repo, edit one of .rst files and submit PR as usual.

Haven’t used reStructuredText before? Don’t worry! Check out a couple of examples to get started.

Building on local

If you’d like to build Falcon docs on your local please uncomment sphinxdocs service in docker-compose.override.yml and run make up. Now all your changes in docs folder are tracked and automatically built in docs/_build/html folder.

Falcon Development

Naming conventions

Custom modules should be placed into the modules/custom directory and prefixed with falcon_ string, for instance falcon_example.

Packaged features should be placed into modules/features directory and prefixed with falcon_feature_ string, for instance falcon_feature_example.

Adding a new module

When adding a new module to the Falcon distribution developer should decide if it is needed on every site consuming the distribution. If this is the case then it should be enabled using hook_update_N() in the falcon_deploy module and also added as a dependency into falcon.info.yml file so it gets installed on new installations. If the module is not required on every site then it should either be a dependency for some other modules/features or enabled by the team managing specific client site.

Falcon Dashboard

Falcon provides a lightweight administration dashboard for users who don’t need full access to all Drupal administration tools.

The dashboard is available at /dashboard and integrated with Admin Toolbar.

Permissions
  • Users need “Use the administration toolbar” permission to access Dashboard from the toolbar.
  • Users need “Use default admin toolbar” permission to access Administration menu from the toolbar.

There are two ways to place new categories and items on the dashboard:

  1. Export config menu items into features using Config menu link module. Preferred option for Falcon features.
  2. Add normal menu items (content level) and flush cache.

Creating releases

Requirements
  • New release should be based on master branch.
  • New release tag should look like “1.0.0”.

Given a version number MAJOR.MINOR.PATCH, increment the:

  • MAJOR version when you make incompatible API changes.
  • MINOR version when you add functionality in a backwards-compatible manner.
  • PATCH version when you make backwards-compatible bug fixes.

You can read documentation for more info about version standardization.

Create new release
  1. Make sure you switched to the master branch and have the latest version of it.
  2. Create a new tag git tag -a 1.1.0 -m "Version 1.1.0"
  3. Push a new tag to github.com git push origin 1.1.0
  4. Go to Releases page on github and Draft a new release
  5. Choose tag version, add Release title (e.g. “1.1.0 (March 7, 2019)”), mention main changes since last release in Description (e.g. 1.1.0) and publish the release.

You can read official Github instruction for more info how to create releases.

Client-site Development

General approach

Falcon is using Features module to package configurations. Please see Features handbook for detailed information on Features.

When feature is installed for the first time its configuration files are getting imported into site configuration - once it is done then this configuration is owned by the site.

It is recommended to use the Config Distro module to manage configuration updates coming from Falcon distribution.

How to install Falcon feature?

Go to /admin/modules and install it.

How to update Falcon feature?

After updating the codebase to the new version of Falcon go to /admin/config/development/configuration/distro and import feature updates.

TODO: check if it can be done automatically in hook_update_N() or using drush command config-distro-update.

How to remove Falcon feature?

Go to /admin/modules/uninstall and uninstall it. Then go to /admin/config/development/features, review the configurations supplied with the uninstalled feature and remove the configurations you don’t need anymore.

TODO: Is there (or can we provide) a way to automate this through hook_update or some drush command? There should be some automated upgrade path from old configs to new configs list. Maybe through hook_update or something like that.

Information Architecture

This section contains Information Architecture for the Falcon project. It helps to understand the relationships between entities alongside with their key fields and design choices.

Donations

Appeal

Appeal is a revisionable node, which represents content for Appeal Landing Page, alongside with settings for the donation form and Thank You Landing Page / Email. Here’s the list of key fields divided into groups on the edit form:

General Appeal Information:
 
  • Title [title] - required textfield determines the Appeal’s title. Uses default Drupal’s node title field.
  • Related Countries [related_countries] - optional entity reference field to Country entity (TODO: Add a link to the entity structure when exists in the doc).
  • Related Key Programme Areas [related_key_areas] - optional entity reference field to Key Programme Area entity (TODO: Add a link to the entity structure when exists in the doc).
  • Path [path] - Fieldable mirror of default Drupal’s URL field built in for decoupled filtering by path via JSON API. Hidden from users on the edit form.
  • Published [status] - Appeal publishing state. Uses default Drupal’s node publish flag.
Appeal Landing Page:
 
  • Body blocks [blocks] - Optional unlimited list of paragraphs. Each paragraph determines visible content block on the appeal landing page. Each appeal comes with several default paragraphs by default for easier and faster appeal creation.
Donation Form:

This section defines behavior of donation form on the appeal’s landing page.

  • Allowed donation types [donation_type] - Required select field with 2 pre-defined options: “Single Donation” and “Recurring Donation”. Allows to select either one or two options.
  • Min donation amount [donation_min_amount] - Required integer field with default value set to 0. Determines minimal amount which a user should be able to donate to the given appeal.
  • Suggested amounts [donation_suggested_amounts] - Optional integer mutiple field with up to 3 values. Each of the values defines the suggested amount to donate on the form next to the donation amount input textfield.
Source Codes:

Note: This section is relevant only when `Falcon ThankQ` integration is enabled.

This section uses Inline Entity Form to embed Source Code entity inline as a multiple unlimited field. Each Source code entity has the following set of fields:

  • ThankQ Source Code [source_code] - Required text field which defines source code fetched from ThankQ CRM.
  • Label - Required text field which defines human readable label on the frontend which matches the Source Code.
  • Active on - Optional date range field, which defines when the current source code may be shown on the donation form.
Thank You Landing Page:
 

This section defines content which will be shown on the Thank You page after successful donation.

  • Title [thankyou_page_title] - Required text field. Defines page title for the Thank You page.
  • Body blocks [thankyou_page_blocks] - Optional paragraphs list. Defines content blocks for the Thank You landing page.
Thank You Email:
 

This section defines content of email which will be send when donation is completed by a donor.

  • Email subject [thankyou_email_subject] - Required text field which allows to use Drupal tokens. This field defines title of thank you email.
  • Email body [thankyou_email_body] - Required rich text field which allows to use Drupal tokens. This field defines content of thank you email.
Commercial part of Donations

This section describes IA of Commerce system which supports Donations in Falcon.

Commercial part of Donations is based on Drupal Commerce module. All default commerce entities generated by this module get deleted upon installation of Falcon Commerce module.

Store:

There is a single General Store available for all commerce operations on the backend.

Order types:

Donations has its own Order type called Donation. Here’s list of fields:

  • Order items [order_items] - Default Commerce reference to the list of order items.
  • UID [uid] - Default Commerce reference to the user account of a donor who has donated. The user account is generated upon donation automatically.
  • Mail [mail] - Default Commerce email field which stores Donor’s email.
  • Billing address [billing_profile] - Default Commerce entity reference to the customer’s profile. Note that the Customer Profile is of a new bundle for the donations feature.
  • State [state] - Default Commerce state field defined by Order Workflow. Note that Order Workflow is custom for the donations feature.
  • Appeal [appeal] - Required Entity Reference to the Appeal which was used to submit the order.
  • Source code [source_code] - Optional text field which defines the source code of a donor who submitted the donation. It is done as text field and not the reference field as we need to capture the source code that was there when the user submitted the form (as source codes are editable and can be changed by editors/managers).
Order workflow:

NOTE: Drupal Commerce doesn’t allow order workflows without draft state and without place transition.

The system defines only 1 workflow called Donation with the following states:

  • Draft
  • Completed
  • Canceled
Order Item type:
 

There is single order item type Donation [donation].

Every Order Item defines the following fields:

  • Purchaised Entity - Default Commmerce field with reference to the donation product.
  • Quantity - Default Commerce field. In relation of Donations feature it always equals 1.
  • Unit price - Default Commerce field which allows to override donation price. This field is used in Donations feature to override the Donations product price by the real donation amount.
  • Donation type - Defines type of donation, either Single Donation [single_donation] or Recurring Donation [recurring_donation].
Product type:

The donation feature implementation defines only 1 product type called Donation with a single product also called Donation with a 0 price. This product is created automatically on Falcon installation and is used for adding to the Order Item with overriding of its price upon order creation. The single donation product has hard-coded product SKU donation which makes the interaction with it easier.

Product variation type:
 

The donation feature implementation defines only 1 product type variation called Donation with a single product also called Donation with a 0 price. This product is created automatically on Falcon installation and is used for adding to the Order Item with overriding of its price upon order creation. The single donation product has hard-coded product SKU donation which makes the interaction with it easier.

Payment gateways:
 

Default Drupal Commerce’s payment gateways.

Customer Profile:
 

Donations implementation in Falcon extends the default Customer Profile type called Customer. This profile type allows for multiple profiles of the same type for the same user. It has the following fields:

  • Address [address] - Default Commerce’s address field. TODO: need clarification on what fields are required here as address is complex field.
  • Phone number [phone] - Phone number field.
  • Allow Contact by Phone [contact_phone] - Optional boolean field which defines if this donor can be contacted via phone by charity’s staff.
  • Allow Contact by SMS [contact_sms] - Optional boolean field which defines if this donor can be contacted via SMS by charity’s staff.
  • Allow Contact by Email [contact_email] - Optional boolean field which defines if this donor can be contacted via Email by charity’s staff.
  • Allow Contact by Post [contact_post] - Optional boolean field which defines if this donor can be contacted via physical post by charity’s staff.

Users

This section defines structure of user accounts & profiles within the system.

  • Email - default Drupal’s user email address.
  • Account name - default Drupal’s user account name field.
  • First Name - optional text field with donor’s First Name.
  • Last Name - optional text field with donor’s Last Name.
  • Status - default Drupal’s status field. All donors get their own user account, but status is set to 0 to restrict from authentication.

Roles & Permissions

This section contains definition of user roles and their level of permissions within the system.

Administrator:Full administrative access to all sections of the site, including modules & other development aspects. This role is defined for developers.
Manager:Full access over site’s content, users and all features without access to development sections. This role is defined for people with highest level of access within the site.
Content manager:
 Full access to all content of the site, apart from appeals. This role is defined for content editors of a company.
Appeals manager:
 Create, edit & delete access to appeals. This role is defined for staff members, who work only with specific donation campaigns and do not need to have access to other content.
Donations manager:
 View access to donations submitted by donors. This role is defined for staff members, who should be able to overview submitted donation amounts and donors’ data.

Content API

Falcon supports multiple ways to expose content via API:

You are free to use any of the options above to meet your project goals.

JSON:API

JSON:API is recommended option for API exposure in Falcon. With JSON:API & JSON:API Extras (both installed in Falcon), you most likely will be able to cover most your API-related tasks.

However, please be aware of well-known JSON:API limitations:

  • In case of more complex content structures (nested Media, Paragraphs, etc) JSON:API queries may become hard to maintain.
  • There is no way to make cross-bundle requests. Follow this issue to stay up to date.
  • JSON:API doesn’t support aliases and redirects out of the box. You will need help of Decoupled Router of similar modules.

Usage:

/jsonapi/node/my-bundle

Read more about JSON:API in the official documentation.

RESTful Web Services

With RESTful Web Services module you can enable built-in endpoints for various content types. Default REST endpoints have a couple of drawbacks:

  • No way to include related entities.
  • No way to expose listings.

Usage:

Go to /admin/config/services/rest page and enable “Content” resource. Make a request:

/node/1?_format=json
or
/node-alias?_format=xml

Custom resource:

With REST module you can create your own REST endpoints.

Read more about RESTful Web Services in the official documentation.

REST Views

You can create a view with REST export display to expose dynamic lists of content via API. Known drawbacks of this approach:

  • You have to reconfigure your view if business logic of the app has been changed.
  • You have to create similar views for different listings on your site.

Falcon will be return the response with pagination data, but if you want to use page or item_per_page in your request you should configure exposed options in you pager options.

In Falcon, we have enhanced pagination support for REST Views (via patch).

Example request:

/view-url?_format=json&page=3

Read more about JSON:API in the official documentation.

Rest Entity Recursive

Rest Entity Recursive provides new “json_recursive” REST format which exposes all fields and referenced entities by default. You may want to use this module if you need to fetch almost everything in one request.

Usage: Enable core REST resource or create REST View display with format json_recursive enabled. Make a request:

/request-url?_format=json_recursive

You can use query parameter max_depth if you want to limit depth of loaded references. Default is max_depth = 10.

Find examples how to customize and fine-tune the output in submodules:

  • rest_media_recursive
  • rest_paragraphs_recursive

Read more about Rest Entity Recursive on Drupal.org project page.

Payments / Checkout API

Falcon uses Commerce Decoupled Checkout module as an endpoint for all Commerce order creation and payments. The REST endpoint is /commerce/order/create.

You can find the link about the expected payload and additional payment related endpoints in the module’s documentation.

Below you will find more examples how those endpoints are used on Falcon for various use cases and payment gateways.

Additionally, you can look at tests inside of ./tests/api/commerce_decoupled_checkout folder for real payment examples.

Supported Payment Gateways

Out of the box Falcon comes with support of the following payment methods:

  • Paypal (disabled by default)
  • Credit Cards through Stripe (disabled by default)
  • Credit Cards through Realex / Global Payments (disabled by default)
  • Direct Debits (enabled by default)
  • Example payment (disabled by default)

In fact, thanks to Commerce Decoupled Checkout any other Drupal module which provides payment gateway for Drupal Commerce is supported as well.

Donations API example

Here’s the example REST Payload to submit a new donation with Example Payment method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
   {
     "order": {
       "type": "donation"
       "field_appeal": 1 // Appeal ID. Mandatory.
       "order_items": [
         {
           "type": "donation",
           "field_donation_type": "single_donation", // Donation type. Can be "single_donation" or "recurring_donation".
           "purchased_entity": {
             "sku": "donation"
           },
           "unit_price": {
             "number": 15,
             "currency_code": "EUR",
           }
         }
       ],
     },
     "profile": {
       "field_phone": "88001234567",
       "field_contact_email": 1,
       "field_contact_phone": 0,
       "field_contact_post": 0,
       "field_contact_sms": 0,
       "address": {
         "given_name": "John",
         "family_name": "Snow",
         "country_code": "US",
         "address_line1": "1098 Alta Ave",
         "locality": "Mountain View",
         "administrative_area": "CA",
         "postal_code": "94043"
       }
     },
     "user": {
       "mail" : "test@systemseed.com",
     },
     "payment": {
       "gateway": "example_test", // Machine name of the payment gateway added by admin.
       "type": "credit_card",
       "details": {
         "type": "visa",
         "number": "4111111111111111",
         "expiration": {
         "month": "01",
         "year": "2022"
       },
     },
   }

Paypal Payments

Requires Commerce Paypal Express Checkout module to be enabled & configured (already part of Falcon).

To make Paypal payments, the first step is to send request to standard endpoint /commerce/order/create with order / user info (no payments details yet). This request will return created Order ID - save it into a variable. The further step depends on Single vs Recurring payment.

In case of Single Payment, send this data to /commerce/payment/create/$orderID:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  gateway: "paypal_ec_test",
  type: "paypal_ec",
  details: {
    type: 'single',
    data: {
      transactions: [{
        description: 'Single donation.',
      }],
    },
  }
}

This response will initialize a payment transaction and return created Payment ID - save it as well. Next, the confirmation of the transaction should happen on the client side by a user. See Paypal Checkout for detailed documentation of frontend implementation.

When a user confirms transaction on the frontend, send this payload to /commerce/payment/capture/$orderID/$paymentID. It should finalize the payment transaction.

In case of Recurring Payment, send this data to /commerce/payment/create/$orderID:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
  gateway: "paypal_ec_test",
  type: "paypal_ec",
  details: {
    type: 'single',
    data: {
      billing_plan: {
        name: 'Monthly donation',
        description: 'Monthly donation for my website.',
        type: 'INFINITE',
        payment_definitions: [{
          name: 'Monthly donation',
          type: 'REGULAR',
          frequency: 'MONTH',
          frequency_interval: 1,
          cycles: 0,
        }],
        merchant_preferences: {
          auto_bill_amount: 'NO',
          initial_fail_amount_action: 'CONTINUE',
          max_fail_attempts: 0,
        },
      },
      billing_agreement: {
        name: 'Monthly donation for my website',
        description: 'Description of your donation.',
      },
    },
  }
}

The next step is the same as with one-off payment - let a user verify the transaction on the frontend and then send the received payload to /commerce/payment/capture/$orderID/$paymentID.

The structure & available options for the payment initialization of Paypal payments follow Paypal PHP SDK library. Here is the code which transforms the data from the frontend request into Paypal-acceptable format: Single Payment and Recurring Payment.

Realex (Global Payments)

Requires Commerce Global Payments (Realex) module to be enabled & configured (already part of Falcon).

The request should contain data related to order, user and payment. Send the request to /commerce/order/create. Here’s the example of payload part specific to Global Payments (Realex) payment:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  // All order & user specific data.
  ...
  // Payment details.
  payment: {
    gateway: "globalpayments_creditcard_test", // Machine name of payment gateway added by admin.
    type: "globalpayments_credit_card",
    details: {
      name: "John Snow",
      number: "4263970000005262",
      security_code: "123",
      expiration: {
        month: "02",
        year: "2023",
      }
    }
  }
}

Stripe Payments

Requires Commerce Stripe module to be enabled & configured (already part of Falcon).

To make a payment using Stripe, you need to obtain a Stripe token first. It is up to the frontend application to handle it. For example, React.js has react-stripe-checkout library which handles it for you (token method). Another example for PHP you can find in ./tests/api/commerce_decoupled_checkout/StripeCest.php.

As soon as you got the token, the remaining step is straightforward - just send the request to /commerce/order/create. Here’s the example of payload part specific to Stripe Payments:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
   {
     // All order & user specific data.
     ...
     // Payment details.
     payment: {
       gateway: "stripe_test", // Machine name of payment gateway added by admin.
       type: "credit_card",
       details: {
         stripe_token: "<INSERT_TOKEN_HERE>",
       }
     }
   }

Direct Debit Payments

Direct Debits are enabled by default. The request should contain data related to order, user and payment. Send the request to /commerce/order/create. Here’s the example of payload part specific to Direct Debit payment:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  // All order & user specific data.
  ...
  // Payment details.
  payment: {
    gateway: "direct_debit_test", // Machine name of payment gateway added by admin.
    type: "direct_debit_sepa", // Can be "direct_debit_sepa" or "direct_debit_uk"
    details: {
      account_name: "John Snow",
      swift: "BOFIIE2D",
      iban: "DE89 3704 0044 0532 0130 00",
      debit_date: 2,
      accept_direct_debits: 1,
      one_signatory: 1
  }
}

Payment Test / Live modes

Every payment gateway has live and test payment modes.

Falcon allows to use test payment modes on any non-production environments. For the production environment test payments are restricted. To use test payment mode on production environment you need to set special environment variables: PAYMENT_SECRET_HEADER_NAME and PAYMENT_SECRET_HEADER_VALUE - and then set local storage value in the browser using the supplied name and value.

Example:

PAYMENT_SECRET_HEADER_NAME = X-Payment-Secret
PAYMENT_SECRET_HEADER_VALUE = 76a67787-af11-4870-b384-b8e85c4fe3b8

And then browser local storage should have X-Payment-Secret / 76a67787-af11-4870-b384-b8e85c4fe3b8

Environment

Falcon is using the environment variable called ENVIRONMENT to recognize if it is running in production mode.

Supported values are:

  • production - if the value of ENVIRONMENT is production then Falcon is running in production mode. If it has any other value - then it is running in non-production mode.
  • development - if the value of ENVIRONMENT is development then Falcon is running in development mode.

In order to use this environment variable on the PHP code level you need to set it. Local environment powered by Docker and Makefile sets it for the php service in the .docker/docker-compose.override.yml file taking the value from the .env file. To set this environment variable on the hosting environment you should use the hosting provider tools.

There is a Drupal service to use in any custom code to determine the environment - falcon_common.environment. You can inject it and then use like this: $this->environment->isProduction().

1
2
3
4
services:
  module_name.service_name:
    class: Drupal\module_name\ServiceName
    arguments: ['@falcon_common.environment']
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

namespace Drupal\module_name;

/**
 * Class ServiceName.
 */
class ServiceName implements ServiceNameInterface {

  /**
   * The environment.
   *
   * @var \Drupal\falcon_common\EnvironmentInterface
   */
  protected $environment;

  /**
   * Constructs a new Payment object.
   *
   * @param \Drupal\falcon_common\EnvironmentInterface $environment
   *   The environment.
   */
  public function __construct(RequestStack $request_stack, EnvironmentInterface $environment) {
    $this->request = $request_stack->getCurrentRequest();
    $this->environment = $environment;
  }

  public function methodName() {
    $if (this->environment->isProduction()) {
      // Do smth related to production environment.
    }
  }

}

Content

Basic concepts

  1. Falcon follows Drupal best practices to organise content structure: nodes, fields, taxonomy, etc.
  2. Each content type has at least title (standard Drupal property), image (field_image) and short description (field_description) fields.
  3. Falcon uses Paragraphs to manage visual content (field_blocks).
  4. Falcon doesn’t require to follow these concepts. Instead, it ships with a showcase to demonstrate how these concepts allow building flexible and sophisticated content architectures.

Showcase

Falcon demo content structure is stored in the following features:

  • falcon_feature_content_structure_demo - collection of content types with fields and relationships.
  • falcon_feature_content_blocks - collection of content blocks for the demo content types.
  • Default content is coming soon.
  • Frontend showcase is coming soon.

Content blocks

Content blocks built using Paragraphs module.

Paragraphs Browser

Content blocks are organised in groups using Paragraphs Browser module. Falcon content showcase includes the following groups:

Hero

The blocks at the top of the page, usually a full width image with headings / links.

Section

Containers for other blocks (items).

Items

Can be added to sections blocks only (i.e. child blocks).

Widgets

Rich interactive elements.

Listing

Automated / semi-automated listings, i.e. “Latest content” block.

Paragraph machine name should begin with its group name, i.e. “Latest content” block should be named listing_latest_content.

Reusable content blocks

Reusable content blocks use Paragraphs Library module from Paragraphs package in combination with Entity Browser for better editorial experience.

Media

Falcon Media tools are based on Drupal core and fully compatible with Media Browser. It is recommended to use Media fields instead of legacy Image/File fields when developing sites on Falcon.

Basic media configuration should be stored in Falcon Media feature. It provides setup for images (all popular formats and SVG) and videos (local and external).

Note: Falcon uses Video Embed Field solution for external videos until [#2996029] Add oEmbed support to the media library is solved.

Metatags

Falcon provides metatags. You can create new metatag field into entity type, and you can get metatag_normalized key from jsonApi. Also falcon use consumers_token module that provides a token [consumers:current-name] for consumers name replacement depending on what consumer has requested the token.

Email Configuration

Falcon mailing functionality is placed in falcon_mail module. The module provides a plugin for Drupal mail system with a formatter that can wrap emails into HTML templates and replace dynamic tokens.

You can change formatter on admin/config/system/mailsystem page.

You can configure you email with several params. Example

$to = $order->getEmail();
$langcode = 'en';
$reply = NULL;
$send = TRUE;

$params = [];
$params['from'] = 'your_email@example.com'
$params['subject'] = "Message subject";
$params['body'] = "<div> Html message body </div>";
$params['headers'] = ['Content-Type' => 'text/html'];   # Enable html. You can pass any headers.
$params['render_tokens']['commerce_order'] = $order;    # Array 'render_tokens' contains variables for token replacement.
$params['token_options'] = [                            # Array 'token_options' contains options for token replaceement.
    'langcode' => $langcode,
    'callback' => 'callback_function'
];
$params['replace_tokens'] = TRUE;                       # Enable replacement tokens.
$params['theme_template'] = "<div> #$#BODY#$# </div>"   # The template where will be replaced #$#BODY#$# on $messsage['body'].

\Drupal::service('plugin.manager.mail')->mail('your_module', 'your_mail_key', $to, $langcode, $params, $reply, $send);

The theme_template param can use the #$#BODY#$# variable for wrap an another html to theme_template html. You can also find an example of working in the falcon_donation module.