💶 User facing application for the Wikimedia Deutschland fundraising
Clone or download
Latest commit af5d87d Dec 11, 2018
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
app Merge pull request #1404 from wmde/restore-old-amount-options Dec 11, 2018
build Fix campaign configuration Oct 16, 2018
cli Fix line break issues in mail template Oct 11, 2018
deployment Fix deployment (#1363) Oct 12, 2018
doc Add instructions to generate new icons Sep 24, 2018
skins Increase amount options Dec 11, 2018
src Move amount options from config to choice factory Dec 11, 2018
tests Change text snippets on donation confirmation page Nov 21, 2018
web Separate dev-dependency from production code Oct 8, 2018
.dockerignore Build dependencies with Docker Mar 20, 2018
.gitignore Create xDebug-ready Docker environment Jul 9, 2018
.scrutinizer.yml Hide Bootstrap and Route from Scrutinizer Oct 11, 2018
.travis.yml Use configuration name from environment. Oct 8, 2018
COPYING.txt Add license file Aug 5, 2016
Makefile Merge pull request #1362 from wmde/watch-env Oct 11, 2018
README.md Merge pull request #1362 from wmde/watch-env Oct 11, 2018
cli-config.php Separate dev-dependency from production code Oct 8, 2018
composer.json Add Graylog as optional production logger Oct 8, 2018
composer.lock Update dependencies to see translations in dev Nov 29, 2018
console Move config validation to Cli namespace Aug 18, 2016
docker-compose.debug.yml Adapt Scrutinizer settings Aug 1, 2018
docker-compose.yml Document APP_ENV environment variable usage. Oct 8, 2018
npm_skins.js make sure skin exit codes propagate to project level Nov 29, 2017
package-lock.json Add npm task to autogenerate README TOC Apr 25, 2018
package.json Add npm task to autogenerate README TOC Apr 25, 2018
phpcs.xml Add Controllers & RouteHandlers to PHPCS sniff Oct 5, 2018
phpmd.xml Add clean code PHPMD rule Apr 16, 2018
phpunit.xml.dist Re-enable NyanCat Sep 27, 2018

README.md

Build Status Code Coverage Scrutinizer Code Quality

User facing application for the Wikimedia Deutschland fundraising.

Installation

For development you need to have Docker and docker-compose installed. You need at least Docker Version >= 17.09.0 and docker-compose version >= 1.17.0. If your OS does not come with the right version, please use the official installation instructions for Docker and docker-compose. You don't need to install other dependencies (PHP, Node.js, MySQL) on your machine.

Get a clone of our git repository and then run:

make setup

This will

  • Install PHP and Node.js dependencies
  • Copy a basic configuration file. See section Configuration for more details on the configuration.
  • (Re-)Create the database structure and generate the Doctrine Proxy classes
  • Build the assets & JavaScript

Running the application

docker-compose up

The application can now be reached at http://localhost:8082/index.php, debug info will be shown in your CLI.

Configuration

The web and CLI entry points of the application check for the APP_ENV environment variable. If it not set, the application assumes the value development. Each environment must have a corresponding configuration file in app/config, following the name pattern of config.ENVIRONMENTNAME.json. See the section "Running in different environments" below to see how to set APP_ENV.

You can add local modifications by adding a file that follows the name pattern of config.ENVIRONMENTNAME.local.json.

The application merges the values from the configuration files with the default values from the file app/config/config.dist.json.

Create local test configuration to speed up tests

To speed up the tests when running them locally, use SQLite instead of the default MySQL. This can be done by adding the file app/config/config.test.local.json with the following content:

{
    "db": {
        "driver": "pdo_sqlite",
        "memory": true
    }
}

Payments

For a fully working instance with all payment types and working templates you need to fill out the following configuration data:

"operator-email"
"operator-displayname-organization"
"operator-displayname-suborganization"
"paypal-donation"
"paypal-membership"
"creditcard"

Content

The application needs a copy of the content repository at https://github.com/wmde/fundraising-frontend-content to work properly. In development the content repository is a composer dev-dependency. If you want to put the content repository in another place, you need to configure the i18n-base-path to point to it. The following example shows the configuration when the content repository is at the same level as the application directory:

"i18n-base-path": "../fundraising-frontend-content/i18n"

A/B test campaigns.

For more information om how to set up the campaigns see "How to Create an A/B Test.

The campaign definitions are in the app/config directory. You can tell the application which files to use by editing the campaigns value in app/config/config.ENVIRONMENTNAME.json. The campaign configuration files will be merged on top of each other.

Running in different environments

By default, the configuration environment is dev and the configuration file is config.dev.json. If you want to change that, you have to pass the environment variable to make, docker and docker-compose commands.

make ci APP_ENV=prod

For docker-compose you can either put create a file called .env in the application directory and, with the contents of

APP_ENV=prod     

Alternatively, or if you want to override the defaults in the .env file, you set the variable in your shell like this:

export APP_ENV=prod

If you run a single docker container, you can pass the variable with the -e flag:

docker run -e APP_ENV=prod php some_script.php

Valid environment names are

  • dev - development environment, mostly for local development
  • test - unit testing environment
  • uat - user acceptance testing
  • prod - production

Note:* PHPUnit tests are always run in the test environment configuration, regardless of APP_ENV!

Running the tests

Full CI run

make ci

If you want to run all the CI tasks in parallel, without ticking progress bars from commands that support it, run the following command instead:

make -j --output-sync ci DOCKER_FLAGS="" 

For tests only

make test
docker run -it --rm --user $(id -u):$(id -g) -v $(pwd):/app -w /app node:8 npm run test

For style checks only

make cs
docker run -it --rm --user $(id -u):$(id -g) -v $(pwd):/app -w /app node:8 npm run cs

For one context only

make phpunit TEST_DIR=contexts/PaymentContext

phpstan

Static code analysis is performed via phpstan during runs of make ci.

In the absence of dev-dependencies (i.e. to simulate the vendor/ code on production) it can be done via

docker build -t wmde/fundraising-frontend-phpstan build/phpstan
docker run -v $PWD:/app --rm wmde/fundraising-frontend-phpstan analyse -c phpstan.neon --level 1 --no-progress cli/ contexts/ src/

These tasks are also performed during the travis runs.

Emails

All emails sent by the application can be inspected via mailhog at http://localhost:8025/

Database

Database migrations

Out of the box, the database should be in a usable state for local development. For production changes to the database, doctrine migration scripts may be used. Migration scripts are stored in the migrations directory of the FundraisingStore repository.

The scripts from the FundraisingStore repository can be executed through FundraisingFrontend by running make migration commands.

To execute a specific script, run the following command and add the version number of the migration script you want to use. As an example, executing migrations/Version20180612000000.php would look like this:

make migration-execute MIGRATION_VERSION=20180612000000

You can also revert a script (if implemented) through an equivalent migration-revert command:

make migration-revert MIGRATION_VERSION=20180612000000

Note that Doctrine creates its own doctrine_migration_versions table where it stores the status of individual migrations. If you run into issues and want to reset the state of a migrations it's best to check that table directly or use the versions command from doctrine-migrations which supports --add and --delete paramters:

vendor/wmde/fundraising-store/vendor/doctrine/migrations/bin/doctrine-migrations migrations:version

All of the previous make commands are only available in a dockerized environment. If you intend to use these commands on servers, you can check the Makefile for the underlying commands.

Accessing the database from a Docker image

The database container of the Docker development environment is not exposed to the outside. If you want to connect to the default fundraising frontend database using the MySQL command line client, you need first to find out the Docker network name where the database is running in. With the command

docker network ls

you can list all networks. There will be one network name ending in fundraising_proxy (the prefix is probably the directory name where you checked out this repository).

Next up is finding out the full name of the database container with the command

docker ps

The database container will be the one ending in _database_1. The prefix is probably the directory name where you checked out this repository.

Copy the full network name and container name and use them instead of the placeholders __CONTAINER_NAME__ and __NETWORK_NAME__ in the following command to run the MySQL command line client:

docker run -it --link __CONTAINER_NAME__:mysql --net __NETWORK_NAME__ --rm mysql:5.6 \
    sh -c 'exec mysql -h database -P 3306 -u fundraising -p"INSECURE PASSWORD" fundraising'

To use PHPMyAdmin, use the following command to run it on port 8099:

docker run -it --link __CONTAINER_NAME__:db --net __NETWORK_NAME__ -p 8099:80 phpmyadmin/phpmyadmin

Accessing the database from your host machine

If you want to expose the port of the database on your guest host (localhost), for example for using a GUI client, you need to create an "override" file for docker-compose.yml. Example file, called docker-compose.db.yml:

version: '3'

services:
    database:
        ports:
            - "3306:3306"

You then start the environment with the following command:

docker-compose -f docker-compose.yml -f docker-compose.db.yml up

You will be prompted for a password which you can grab from config/config.prod.json.

Frontend development

For a full JS CI run

make ci

If JavaScript or CSS files where changed, you will need to (re)run

make js

If you want to debug problems in the Redux data flow, use the command

make js REDUX_LOG=on

Actions and their resulting state will be logged.

Automatic recompilation of assets during development

If you are working on the JavaScript files of the cat17 skin and need automatic recompilation when a files changes, run the command

make watch-js  

To debug problems in the Redux data flow, add the parameter REDUX_LOG=on to the command line above

To do the same for the 10h16 skin, run the following Docker command corresponding to the skin:

docker run --rm -it -u $(id -u):$(id -g) -v $(pwd):/app -v $(pwd)/web/skins/10h16:/app/skins/10h16/web -w /app/skins/10h16 -e NO_UPDATE_NOTIFIER=1 node:8 npm run watch 

If you want to debug problems in the Redux data flow, add the parameter -e REDUX_LOG=on to the command line above

Skins

If skin assets where changed, you will need to run

make ui

Updating the dependencies

To update all the PHP dependencies, run

make update-php

For updating an individual package, use the command line

docker run --rm -it -v $(pwd):/app -v ~/.composer:/composer -u $(id -u):$(id -g) composer update --ignore-platform-reqs PACKAGE_NAME

and replace the PACKAGE_NAME placeholder with the name of your package.

To update the skins, run

make update-js 

Deployment

For an in-depth documentation how deployment on a server is done, see the deployment documentation.

Profiling

This is not working at the moment.

(When accessing the API via web/index.dev.php, profiling information will be generated and in app/cache/profiler. You can access the profiler UI via index.dev.php/_profiler.)

Project structure

This app and its used Bounded Contexts follow the architecture rules outlined in Clean Architecture + Bounded Contexts.

Architecture diagram

Used Bounded Contexts:

Production code layout

  • src/: framework agnostic code not belonging to any Bounded Context
    • Factories/: application factories used by the framework, including top level factory FFFactory
    • Presentation/: presentation code, including the Presenters/
    • Validation/: validation code
  • vendor/wmde/$ContextName/src/ framework agnostic code belonging to a specific Bounded Context
    • Domain/: domain model and domain services
    • UseCases/: one directory per use case
    • DataAccess/: implementations of services that binds to database, network, etc
    • Infrastructure/: implementations of services binding to cross cutting concerns, ie logging
  • web/: web accessible code
    • index.php: production entry point
  • app/: contains configuration and all framework (Silex) dependent code
    • bootstrap.php: framework application bootstrap (used by System tests)
    • routes.php: defines the routes and their handlers
    • RouteHandlers/: route handlers that get benefit from having their own class are placed here
    • config/: configuration files
      • config.dist.json: default configuration
      • config.test.json: configuration used by integration and system tests (gets merged into default config)
      • config.test.local.json: instance specific (gitignored) test config (gets merged into config.test.json)
      • config.development.json: instance specific (gitignored) production configuration (gets merged into default config)
    • js/lib: Javascript modules, will be compiled into one file for the frontend.
    • js/test: Unit tests for the JavaScript modules
  • var/: Ephemeral application data
    • log/: Log files (in debug mode, every request creates a log file)
    • cache/: Cache directory for Twig templates

Test code layout

The test directory structure (and namespace structure) mirrors the production code. Tests for code in src/ can be found in tests/.

Tests are categorized by their type. To run only tests of a given type, you can use one of the testsuites defined in phpunit.xml.dist.

  • Unit/: small isolated tests (one class or a small number of related classes)
  • Integration/: tests combining several units
  • EdgeToEdge/: edge-to-edge tests (fake HTTP requests to the framework)
  • System/: tests involving outside systems (ie, beyond our PHP app and database)
  • Fixtures/: test doubles (stubs, spies and mocks)

If you need access to the application in your non-unit tests, for instance to interact with persistence, you should use TestEnvironment defined in tests/TestEnvironment.php.

Test type restrictions

Network Framework (Silex) Top level factory Database and disk
Unit No No No No
Integration No No Discouraged Yes
EdgeToEdge No Yes Yes Yes
System Yes Yes Yes Yes

Other directories

  • deployment/: Ansible scripts and configuration for deploying the application
  • build/: Configuration and Dockerfiles for the development environment and Travis CI

See also