Jedisjeux Documentation

Jedisjeux Welcome Page

Jedisjeux is a PHP boardgame website, based on Symfony Framework and Sylius.

Note

This documentation assumes you have a working knowledge of the Symfony Framework. If you’re not familiar with Symfony, please start with reading the Quick Tour from the Symfony documentation.

The Book

Here you will find all the concepts used in the Jedisjeux platform. The Book helps to understand how Jedisjeux works.

The Book

Here you will find all the concepts used in Jedisjeux. The Books helps to understand how Jedisjeux works.

Architecture

The key to understanding principles of Sylius internal organization. Here you will learn about the Resource layer, state machines, events and general non e-commerce concepts adopted in the platform, like E-mails or Fixtures.

Architecture

Before we dive separately into every Jedisjeux concept, you need to have an overview of how our main application is structured. In this chapter we will sketch this architecture and our basic, cornerstone concepts, but also some supportive approaches, that you need to notice.

Architecture Overview

Before we dive separately into every Jedisjeux concept, you need to have an overview of how our main application is structured.

Fullstack Symfony _images/symfonyfs.png

Jedisjeux is based on Symfony, which is a leading PHP framework to create web applications. Using Symfony allows developers to work better and faster by providing them with certainty of developing an application that is fully compatible with the business rules, that is structured, maintainable and upgradable, but also it allows to save time by providing generic re-usable modules.

Learn more about Symfony.

Doctrine _images/doctrine.png

Doctrine is a family of PHP libraries focused on providing data persistence layer. The most important are the object-relational mapper (ORM) and the database abstraction layer (DBAL). One of Doctrine’s key features is the possibility to write database queries in Doctrine Query Language (DQL) - an object-oriented dialect of SQL.

To learn more about Doctrine - see their documentation.

Twig _images/twig.png

Twig is a modern template engine for PHP that is really fast, secure and flexible. Twig is being used by Symfony.

To read more about Twig, go here.

Third Party Libraries

Jedisjeux uses a lot of libraries for various tasks:

  • Sylius for routing, controllers, data fixtures, grids, products, reviews, taxonomy
  • KnpMenu - for backend menus
  • Imagine for images processing, generating thumbnails and cropping
  • Pagerfanta for pagination
  • Winzou State Machine - for the state machines handling
Fixtures

Fixtures are used mainly for testing, but also for having your website in a certain state, having defined data - they ensure that there is a fixed environment in which your application is working.

Note

They way Fixtures are designed in Jedisjeux is well described in the FixturesBundle documentation.

What are the available fixtures in Jedisjeux?

To check what fixtures are defined in Jedisjeux run:

$ php bin/console sylius:fixtures:list
How to load Jedisjeux fixtures?

The recommended way to load the predefined set of Jedisjeux fixtures is here:

$ php bin/console sylius:fixtures:load
What data is loaded by fixtures in Jedisjeux?

All files that serve for loading fixtures of Jedisjeux are placed in the AppBundle/Fixture/* directory.

And the specified data for fixtures is stored in the app/config/app/sylius/sylius_fixtures.yml file.

Grids

A grid is the way objects of a desired entity are displayed on its index view.

Create a Grid

To create a grid, you have to create a yaml file in app/config/app/sylius/grids and to add this file in the sylius_grid.yml.

sylius_grid:
    grids:
        app_backend_address:
            driver:
                name: doctrine/orm
                options:
                    class: "%app.model.address.class%"
            sorting:
                city: asc
            fields:
                street:
                    type: string
                    label: sylius.ui.street
                    sortable: ~
                postcode:
                    type: string
                    label: sylius.ui.postcode
                    sortable: ~
                city:
                    type: string
                    label: sylius.ui.city
                    sortable: ~
            filters:
                search:
                    type: string
                    label: sylius.ui.search
                    options:
                        fields: [street, postcode, city]
            actions:
                main:
                    create:
                        type: create
                item:
                    update:
                        type: update
                    delete:
                        type: delete
Generate the routing

SyliusResourceBundle allows to generate a default CRUD interface including the grid we have just defined. Just put this in your routing configuration! To learn more about routing, go to Routing documentation.

app_backend_address:
    resource: |
        alias: app.address
        section: backend
        except: ['show']
        redirect: index
        grid: app_backend_address
        vars:
            all:
                subheader: app.ui.manage_addresses
                templates:
                    form: backend/address/_form.html.twig
            index:
                icon: map
        templates: :backend/crud
    type: sylius.resource
The Grid Configuration Reference

Here you will find all configuration options of sylius_grid.

sylius_grid:
    grids:
        app_user: # Your grid name
            driver:
                name: doctrine/orm
                options:
                    class: "%app.model.user%"
            sorting:
                name: asc
            limits: [10, 25, 50, 100]
            fields:
                name:
                    type: twig # Type of field
                    label: Name # Label
                    path: . # dot means a whole object
                    sortable: true
                    position: 100
                    options:
                        template: :Grid/Column:_name.html.twig # Only twig column
                        vars:
                            labels: # a template of how does the label look like
                    enabled: true
            filters:
                name:
                    type: string # Type of filter
                    label: app.ui.name
                    enabled: true
                    template: ~
                    position: 100
                    options:
                        fields: { }
                    form_options:
                        type: contains # type of string filtering option, if you one to have just one
                    default_value: ~
                enabled:
                    type: boolean # Type of filter
                    label: app.ui.enabled
                    enabled: true
                    template: ~
                    position: 100
                    options:
                        field: enabled
                    form_options: { }
                    default_value: ~
                date:
                    type: date # Type of filter
                    label: app.ui.created_at
                    enabled: true
                    template: ~
                    position: 100
                    options:
                        field: createdAt
                    form_options: { }
                    default_value: ~
                channel:
                    type: entity # Type of filter
                    label: app.ui.channel
                    enabled: true
                    template: ~
                    position: 100
                    options:
                        fields: [channel]
                    form_options:
                        class: "%app.model.channel%"
                    default_value: ~
            actions:
                main:
                    create:
                        type: create
                        label: sylius.ui.create
                        enabled: true
                        icon: ~
                        position: 100
                item:
                    update:
                        type: update
                        label: sylius.ui.edit
                        enabled: true
                        icon: ~
                        position: 100
                        options: { }
                    delete:
                        type: delete
                        label: sylius.ui.delete
                        enabled: true
                        icon: ~
                        position: 100
                        options: { }
                    show:
                        type: show
                        label: sylius.ui.show
                        enabled: true
                        icon: ~
                        position: 100
                        options:
                            link:
                                route: app_user_show
                                parameters:
                                    id: resource.id
                    archive:
                        type: archive
                        label: sylius.ui.archive
                        enabled: true
                        icon: ~
                        position: 100
                        options:
                            restore_label: sylius.ui.restore
                subitem:
                    addresses:
                        type: links
                        label: sylius.ui.manage_addresses
                        options:
                            icon: cubes
                            links:
                                index:
                                    label: sylius.ui.list_addresses
                                    icon: list
                                    route: app_admin_user_address_index
                                    visible: resource.hasAddress
                                    parameters:
                                        userId: resource.id
                                create:
                                    label: sylius.ui.generate
                                    icon: random
                                    route: app_admin_user_address_create
                                    parameters:
                                        userId: resource.id
Learn More

Note

The way Grids are used in Jedisjeux is well described in the GridBundle documentation.

Routing

SyliusResourceBundle ships with a custom route loader that can save you some time.

Generating a routing

In order to generate routing on administration, you have to create a yaml file in app/config/routing/backend/ directory and to add this file in the ``app/config/routing/backend.yml.

In order to generate routing for API Endpoints, you have to create a yaml file in app/config/routing/api/ directory and to add this file in the ``app/config/routing/api.yml.

In order to generate routing on frontend, you have to create a yaml file in app/config/routing/frontend/ directory and to add this file in the ``app/config/routing/frontend.yml.

Routing Configuration Reference
app_genre_book_remove:
    path: /{genreName}/books/{id}/remove
    methods: [DELETE]
    defaults:
        _controller: app.controller.book:deleteAction
        _sylius:
            repository:
                method: findByGenreNameAndId
                arguments: [$genreName, $id]
            criteria:
                genre.name: $genreName
                id: $id
            redirect:
                route: app_genre_show
                parameters: { genreName: $genreName }
Routing Generator Configuration Reference
app_book:
    resource: |
        alias: app.book
        path: library
        identifier: code
        criteria:
            code: $code
        section: admin
        templates: :Book
        form: AppBundle/Form/Type/SimpleBookType
        redirect: create
        except: ['show']
        only: ['create', 'index']
        serialization_version: 1
    type: sylius.resource
Learn More

The User Guide

The User guide helps to use jedisjeux administration.

The User Guide

Jeux

Jeux
Editions de jeux

On distingue 4 types d’éditions :

Ré-édition

La ré-édition est lorsque le jeu ressort dans une nouvelle édition. Cela est géré à l’aide des variantes de produit. Vous pouvez y accéder via “Gérer les variantes” dans la liste des jeux du back office.

Note

Il ne faut pas créer un nouveau jeu, mais créer un nouveau variant.

_images/variants_button.png
Traduction

La traduction se gère de la même manière que la ré-édition à l’aide des variantes de produit.

De la même série

Certains jeux ne sont pas des ré-éditions mais ont un lien entre-eux comme les différents aventuriers du rail par exemple. Un jeu de la même série se crée comme un jeu classique contrairement aux ré-éditions.

Pour la liaison avec les autres jeux de la même série, cela se gère via les associations. Vous pouvez y accéder via l’onglet “Associations” en modification du jeu (dans le formulaire).

_images/collection.png
Extension

Les extensions de jeu sont un jeu à part entière (comme les jeux de la même série). Une extension se crée comme un jeu classique.

Pour la liaison, il faut partir du jeu de base et ajouter le-s extension-s via l’onglet “Associations” en modification du jeu (le formulaire).

_images/expansion.png

Articles

Articles
Rédaction d’articles
Simple article
Test de jeu

Pour rédiger un test de jeu, il faut partir de la liste des jeux, suivre le bouton “Gérer les articles” et enfin suivre “Créer un test de jeu”.

_images/game-review.png

Ainsi, l’article sera bien relié au jeu correspondant et les paragraphes génériques seront créés.

_images/game-review-form.png
Blocs
Intégrer un contenu dynamique

On peut intégrer un contenu dynamique de différents types tels qu’un jeu. Pour commencer, passer en mode source dans l’éditeur.

_images/ckeditor-source.png
Intégrer un jeu
<div class="entity" data-entity="game">{game-code}</div>

Remplacer {game-code} par le code du jeu que vous pouvez trouver dans la liste des jeux.

The REST API Reference

The API guide covers the REST API of Sylius platform.

The REST API Reference

Products API

Getting a single product

You can view a single product by executing the following request:

GET /api/products/game-1
Response
STATUS: 200 OK
Collection of Products

To retrieve a paginated list of products you will need to call the /api/products/ endpoint with the GET method.

Definition
GET /api/v1/products/
Parameter Parameter type Description
Authorization header Token received during authentication
limit query (optional) Number of items to display per page, by default = 10
sorting[‘nameOfField’][‘direction’] query (optional) Field and direction of sorting, by default ‘asc’ and ‘name’

To see the first page of all products use the below method:

Example
$ curl http://demo.sylius.org/api/products/ \
    -H "Authorization: Bearer SampleToken" \
    -H "Accept: application/json"
Exemplary Response
STATUS: 200 OK
{
  "page": 1,
  "limit": 10,
  "pages": 3,
  "total": 22,
  "_links": {
    "self": {
      "href": "\/api\/products\/?page=1&limit=10"
    },
    "first": {
      "href": "\/api\/products\/?page=1&limit=10"
    },
    "last": {
      "href": "\/api\/products\/?page=3&limit=10"
    },
    "next": {
      "href": "\/api\/products\/?page=2&limit=10"
    }
  },
  "_embedded": {
    "items": [
      {
        "name": "Product 10",
        "id": 215,
        "code": "PRODUCT_10",
        "options": [

        ],
        "slug": "product-10",
        "min_age": 12,
        "min_player_count": 2,
        "max_player_count": 7
      },
      {
        "name": "Product 11",
        "id": 216,
        "code": "PRODUCT_11",
        "options": [

        ],
        "slug": "product-11",
        "min_age": 3,
        "min_player_count": 2,
        "max_player_count": 8
      },
      {
        "name": "Product 12",
        "id": 217,
        "code": "PRODUCT_12",
        "options": [

        ],
        "slug": "product-12",
        "min_age": 9,
        "min_player_count": 2,
        "max_player_count": 4
      },
      {
        "name": "Product 13",
        "id": 218,
        "code": "PRODUCT_13",
        "options": [

        ],
        "slug": "product-13",
        "min_age": 11,
        "min_player_count": 3,
        "max_player_count": 5
      },
      {
        "name": "Product 14",
        "id": 219,
        "code": "PRODUCT_14",
        "options": [

        ],
        "slug": "product-14",
        "min_age": 3,
        "min_player_count": 2,
        "max_player_count": 5
      },
      {
        "name": "Product 15",
        "id": 220,
        "code": "PRODUCT_15",
        "options": [

        ],
        "slug": "product-15",
        "min_age": 12,
        "min_player_count": 3,
        "max_player_count": 5
      },
      {
        "name": "Product 16",
        "id": 221,
        "code": "PRODUCT_16",
        "options": [

        ],
        "slug": "product-16",
        "min_age": 5,
        "min_player_count": 2,
        "max_player_count": 7
      },
      {
        "name": "Product 17",
        "id": 222,
        "code": "PRODUCT_17",
        "options": [

        ],
        "slug": "product-17",
        "min_age": 9,
        "min_player_count": 3,
        "max_player_count": 4
      },
      {
        "name": "Product 18",
        "id": 223,
        "code": "PRODUCT_18",
        "options": [

        ],
        "slug": "product-18",
        "min_age": 10,
        "min_player_count": 2,
        "max_player_count": 6
      },
      {
        "name": "Product 19",
        "id": 224,
        "code": "PRODUCT_19",
        "options": [

        ],
        "slug": "product-19",
        "min_age": 8,
        "min_player_count": 2,
        "max_player_count": 7
      }
    ]
  }
}

People API

People API endpoint is /api/people.

Index of all people

To browse all people available you can call the following GET request:

GET /api/people/
Parameters
page
Number of the page, by default = 1
limit
Number of items to display per page
Response

Response will contain a paginated list of people.

STATUS: 200 OK
{
  "page": 1,
  "limit": 10,
  "pages": 629,
  "total": 6287,
  "_links": {
    "self": {
      "href": "/api/people/?page=1&limit=10"
    },
    "first": {
      "href": "/api/people/?page=1&limit=10"
    },
    "last": {
      "href": "/api/people/?page=629&limit=10"
    },
    "next": {
      "href": "/api/people/?page=2&limit=10"
    }
  },
  "_embedded": {
    "items": [
      {
        "image": {
          "default": "http://92.243.10.152/media/cache/default/uploads/img/auteur1.jpg",
          "thumbnail": "http://92.243.10.152/media/cache/thumbnail/uploads/img/auteur1.jpg",
          "magazine_item": "http://92.243.10.152/media/cache/resolve/magazine_item/uploads/img/auteur1.jpg",
          "path": "auteur1.jpg",
          "id": 12355,
          "main": true
        },
        "full_name": "Andreas Seyfarth",
        "last_name": "Seyfarth",
        "first_name": "Andreas",
        "slug": "andreas-seyfarth",
        "id": 1
      },
      {
        "image": {
          "default": "http://92.243.10.152/media/cache/default/uploads/img/auteur2.jpg",
          "thumbnail": "http://92.243.10.152/media/cache/thumbnail/uploads/img/auteur2.jpg",
          "magazine_item": "http://92.243.10.152/media/cache/resolve/magazine_item/uploads/img/auteur2.jpg",
          "path": "auteur2.jpg",
          "id": 12347,
          "main": true
        },
        "full_name": "Franz Vohwinkel",
        "last_name": "Vohwinkel",
        "first_name": "Franz",
        "slug": "franz-vohwinkel",
        "id": 2
      },
      {
        "image": {
          "default": "http://92.243.10.152/media/cache/resolve/default/uploads/img/auteur3.jpg",
          "thumbnail": "http://92.243.10.152/media/cache/resolve/thumbnail/uploads/img/auteur3.jpg",
          "magazine_item": "http://92.243.10.152/media/cache/resolve/magazine_item/uploads/img/auteur3.jpg",
          "path": "auteur3.jpg",
          "id": 12353,
          "main": true
        },
        "full_name": "Bruno Faidutti",
        "last_name": "Faidutti",
        "first_name": "Bruno",
        "slug": "bruno-faidutti",
        "id": 3
      },
      {
        "image": {
          "default": "http://92.243.10.152/media/cache/default/uploads/img/auteur4.jpg",
          "thumbnail": "http://92.243.10.152/media/cache/resolve/thumbnail/uploads/img/auteur4.jpg",
          "magazine_item": "http://92.243.10.152/media/cache/resolve/magazine_item/uploads/img/auteur4.jpg",
          "path": "auteur4.jpg",
          "id": 12858,
          "main": true
        },
        "full_name": "Julien Delval",
        "last_name": "Delval",
        "first_name": "Julien",
        "slug": "julien-delval",
        "id": 4
      },
      {
        "full_name": "Florence Magnin",
        "last_name": "Magnin",
        "first_name": "Florence",
        "slug": "florence-magnin",
        "id": 5
      },
      {
        "full_name": "Jean-Louis Mourier",
        "last_name": "Mourier",
        "first_name": "Jean-Louis",
        "slug": "jean-louis-mourier",
        "id": 6
      },
      {
        "image": {
          "default": "http://92.243.10.152/media/cache/default/uploads/img/auteur7.jpg",
          "thumbnail": "http://92.243.10.152/media/cache/thumbnail/uploads/img/auteur7.jpg",
          "magazine_item": "http://92.243.10.152/media/cache/resolve/magazine_item/uploads/img/auteur7.jpg",
          "path": "auteur7.jpg",
          "id": 12348,
          "main": true
        },
        "full_name": "Richard Ulrich",
        "last_name": "Ulrich",
        "first_name": "Richard",
        "slug": "richard-ulrich",
        "id": 7
      },
      {
        "image": {
          "default": "http://92.243.10.152/media/cache/resolve/default/uploads/img/auteur8.jpg",
          "thumbnail": "http://92.243.10.152/media/cache/thumbnail/uploads/img/auteur8.jpg",
          "magazine_item": "http://92.243.10.152/media/cache/resolve/magazine_item/uploads/img/auteur8.jpg",
          "path": "auteur8.jpg",
          "id": 12345,
          "main": false
        },
        "full_name": "Wolfgang Kramer",
        "last_name": "Kramer",
        "first_name": "Wolfgang",
        "slug": "wolfgang-kramer",
        "id": 8
      },
      {
        "image": {
          "default": "http://92.243.10.152/media/cache/resolve/default/uploads/img/auteur9.jpg",
          "thumbnail": "http://92.243.10.152/media/cache/thumbnail/uploads/img/auteur9.jpg",
          "magazine_item": "http://92.243.10.152/media/cache/resolve/magazine_item/uploads/img/auteur9.jpg",
          "path": "auteur9.jpg",
          "id": 12366,
          "main": false
        },
        "full_name": "Michael Schacht",
        "last_name": "Schacht",
        "first_name": "Michael",
        "slug": "michael-schacht",
        "id": 9
      },
      {
        "image": {
          "default": "http://92.243.10.152/media/cache/resolve/default/uploads/img/auteur10.jpg",
          "thumbnail": "http://92.243.10.152/media/cache/thumbnail/uploads/img/auteur10.jpg",
          "magazine_item": "http://92.243.10.152/media/cache/resolve/magazine_item/uploads/img/auteur10.jpg",
          "path": "auteur10.jpg",
          "id": 12772,
          "main": true
        },
        "full_name": "Franck Dion",
        "last_name": "Dion",
        "first_name": "Franck",
        "slug": "franck-dion",
        "id": 10
      }
    ]
  }
}
Getting a single person

You can view a single person by executing the following request:

GET /api/people/1
Response
STATUS: 200 OK
{
  "image": {
    "default": "http://92.243.10.152/media/cache/default/uploads/img/auteur1.jpg",
    "thumbnail": "http://92.243.10.152/media/cache/thumbnail/uploads/img/auteur1.jpg",
    "magazine_item": "http://92.243.10.152/media/cache/resolve/magazine_item/uploads/img/auteur1.jpg"
  },
  "full_name": "Andreas Seyfarth",
  "last_name": "Seyfarth",
  "first_name": "Andreas",
  "description": "Andreas Seyfarth est un auteur de jeux de société, particulièrement célèbre pour avoir créé Puerto Rico, considéré par les spécialistes comme l'un des meilleurs jeux de société modernes et récompensé en 2002 par le premier prix du Deutscher Spiele Preis. \r\n\r\nUn autre de ses jeux, Manhattan, avait déjà été récompensé par le prestigieux Spiel des Jahres (jeu de l'année allemand) en 1994. \r\n\r\nEn juillet 2006, c'est le Prix du jeu de l'année allemand qui récompense son nouveau jeu L'Aventure postale, co-réalisé avec Karen Seyfarth.\r\n\r\n(provenant de wikipedia.fr)",
  "slug": "andreas-seyfarth"
}

Server

The Server guide helps you to configure server.

Production settings

PHP settings

Jedisjeux requires php 7.1.

For available list of packages you can read php71_packages.

$ sudo yum install mod_php71w php71w-cli php71w-intl php71w-pdo php71w-xml php71w-gd php71w-mysql

In order to know pathname of php.ini, you can use this following command.

$ php --ini

Edit php.ini and change these parameters.

date.timezone = Europe/Paris
memory_limit = 2048M
upload_max_filesize = 10M
post_max_size = 20M

Apache settings

Virtual host

For more details, you can read virtualHostsTutorial.

$ touch /etc/httpd/sites-available/01-jedisjeux.conf
<VirtualHost *:80>
        ServerAdmin lc.fremont@gmail.com
        DocumentRoot /home/jedisjeux/current/web/
        <Directory "/home/jedisjeux/current/web">
                DirectoryIndex app.php
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All
        </Directory>
        ServerName XX.XXX.XX.XXX
        ServerAlias XX.XXX.XX.XXX
        CustomLog logs/ovh-access_log combined
        ErrorLog  /var/log/httpd/jedisjeux-error_log
</VirtualHost>
Restart apache
service httpd restart

Install ssh key

$ ssh-keygen

Enter blank paraphrase And confirm blank paraphrase

User permissions

Adding jedisjeux to apache group

$ usermod -a -G apache jedisjeux

Ensure access

$ chmod g-w /home/jedisjeux
$ chmod 700 /home/jedisjeux/.ssh
$ chmod 600 /home/jedisjeux/.ssh/authorized_keys

Deployment

The Deployment guide helps to deploy the website on servers.

Deployment

Authorized keys API

Adding ssh authorized keys for server on your local computer

$ cat ~/.ssh/id_rsa.pub | ssh jedisjeux@92.243.10.152 "cat - >> ~/.ssh/authorized_keys"

and enter the correct password for username “jedisjeux” on server

Install dependencies

$ gem install bundler
$ bundle install

Deploy the staging environment

$ bundle exec "cap staging deploy"

Deploy the production environment

$ bundle exec "cap production deploy"