Archives de
Étiquette : php

GitHub, Travis CI et Codecov pour PHP

GitHub, Travis CI et Codecov pour PHP

GitHub

Première étape la création d’un compte GitHub.

Ensuite il faut créer un nouveau repository.

Il faut choisir un nom, une description, si le projet est publique ou priver, si on veux un fichier README ainsi qu’une licence et un fichier .gitignore.

Une fois fait direction la ligne de commande pour utiliser git.

Dans un dossier vide faites la première commande, puis votre travail et la 2eme et 3eme commande afin de commiter vos fichier. Quand vous être prêt a pousser votre projet sur GitHub faites les 2 dernières.

git init
git add .
git commit -m "first commit"
git remote add origin git@github.com:dayofr/sfdc-rest-client1.git
git push -u origin master

Dans mon cas, sur GitHub on peut voir:

Travis CI

Première étape, la création du fichier .travis.yml. C’est ce fichier qui sera utilisé par Travis CI pour exécuter ce que vous lui demanderait.

Dans notre cas, on demande un machine pour PHP version 7.4, il est possible de demander plusieurs machine en rajoutant des valeur a la liste.

La partie script contient les commandes exécutés par travis, dans notre cas nous copions un fichier, installons les dépendance avec composer puis lançons les test avec phpunit. Il faut bien sur commiter et pousser ce fichier sur GitHub.

language: php
php:
  - '7.4'

script:
  - cp .env.example .env
  - composer install
  - vendor/bin/phpunit

Direction Travis CI pour la configuration. Une fois connecté avec GitHub, cliquez sur le menu en haut a droite et sur « Settings ».

Dans la liste des projets sélectionnez celui sur lequel vous travaillez.

Cliquez alors sur le nom de votre projet et vous devriez voir:

Il vous faut alors pousser du code sur GitHub pour que le travail soit effectué. Un nouveau travail devrais alors être démarré par Travis CI et vous devriez voir:

Nous avons la sortie console du travail fait par Travis CI.

Codecov

Pour avoir accès à la couverture de code, nous utilisons Codecov. Une fois connecté avec GitHub, cliquez sur le bouton « Add new repository » puis le projet que vous souhaitez ajouter.

La page suivante nous explique qu’il n’est pas obligatoire de rajouter une variable d’environnement pour Travis CI mais il m’a fallut le faire. Direction Travis CI afin de rajouter cette variable. Cliquez sur « Settings ».

Un peu plus bas dans la page vous trouverez une section « Environment Variables », ajoutez alors la variable.

L’étape suivante consiste a modifier le fichier .travis.yml pour lui rajouter les information de couverture de code et l’appel a Codecov.

  - vendor/bin/phpunit --coverage-clover=coverage.xml

after_success:
  # Submit coverage report to https://codecov.io
  - bash <(curl -s https://codecov.io/bash)

Lors du prochain travail de Travis CI vous aurez alors dans Codecov des informations.

Et voila, a chaque fois que vous pousserais du code sur GitHub, vous aurez un job Travis CI avec vos tests et la couverture de code avec Codecov.

utf8_encode vs iconv

utf8_encode vs iconv

Attention, utf8_encode n’encode que depuis ISO-8859-1 pour tout autres encodage il faut utiliser iconv.

utf8_encode($text)

est la même chose que

iconv('ISO-8859-1', 'UTF-8', $text)
Ajouter une option dans WordPress puis la récupérer avec l’API REST

Ajouter une option dans WordPress puis la récupérer avec l’API REST

Dans cette article nous verrons comment ajouter une option dans les réglages de WordPress, puis comment la récupérer avec une route REST personnalisé.

La première étape est donc d’ajouter une nouvelle option dans l’onglet Général:

add_action( 'admin_init',
	function () {
		add_settings_field(
			'dayo_map_key',
			'Google Map Static API Key',
			function () {
				echo '<input name="dayo_map_key" id="dayo_map_key" type="text" value="' . get_option( 'dayo_map_key' ) . '" class="code" />';
			},
			'general'
		);

		register_setting( 'general', 'dayo_map_key' );
	} );

Ce qui donnera :

L’étape suivante est d’ajouter une route personnalisé a l’API REST de WordPress:

add_action( 'rest_api_init',
	function () {
		register_rest_route( 'dayo/v1',
			'/map/key',
			array(
				'methods'  => 'GET',
				'callback' => function () {
					get_option( 'dayo_map_key' );
				},
			) );
	} );

La route sera donc « dayo/v1/map/key » et renverra la valeur de l’option « dayo_map_key ».

La dernière partie de code PHP est celle qui fournira au JavaScript les informations pour la requête :

add_action( 'enqueue_block_editor_assets',
	function () {
		wp_localize_script( 'dayo_gutenberg_map',
			'DAYO',
			array(
				'api' => array(
					'url'   => esc_url_raw( rest_url( 'dayo/v1/map/key' ) ),
					'nonce' => wp_create_nonce( 'wp_rest' ),
				),
			) );
	} );

Dans le code JavaScript, nous utilisons la variable DAYO que nous avons fournit en PHP afin d’effectuer une requête

jQuery(function ($) {

  $.ajax({
    method: 'GET',
    url: DAYO.api.url,
    beforeSend: function (xhr) {
      xhr.setRequestHeader('X-WP-Nonce', DAYO.api.nonce);
    }
  }).then(function (r) {
    console.log(r)
  })

});

Et voila comment ajouter une option dans les réglages de WordPress et la récupérer avec l’API REST.

Docker et PHP

Docker et PHP

Après un petit bout de temps à maintenir et mettre a jours php, apache et mysql sur mon par diverse moyen j’ai décidé de passer a docker. Il m’a fallut plusieurs essaie et tâtonnement pour arriver à une configuration qui me convient pour un environnement de développement.

C’est disponible sur ce dépôt github. Il y a deux conteneurs.

Le premier et le conteneur mysql de base avec un seul utilisateur root et comme mot de passe root.

Le second est un conteneur php avec apache plus quelques extensions ainsi que composer accessible par la commande composer :

  • apcu
  • xdebuh
  • intl
  • opcache
  • gd
  • mysqli
  • pdo
  • zip

Apache est configuré avec ssl et rewrite.

Pour utiliser xdebug, mettez à jour le fichier php.ini avec votre IP pour xdebug.remote_host=192.168.1.10 puis dans l’url ajoutez « ?XDEBUG_SESSION_START= »

 

API Platform + FOSUserBundle + LexikJWTAuthenticationBundle

API Platform + FOSUserBundle + LexikJWTAuthenticationBundle

  • Symfony: 3.2.2
  • API Platform: 2.0.3
  • FOSUserBundle: 2.0.0-beta2
  • LexikJWTAuthenticationBundle: 2.1.1

En premier lieu nous allons cloner le dépôt API Plaftorm:

composer create-project api-platform/api-platform bookshop-api

Une fois fait, nous installons FOSUserBundle et LexikJWTAuthenticationBundle via composer:

composer require friendsofsymfony/user-bundle:2.0.0-beta-2
composer require lexik/jwt-authentication-bundle

Puis nous activons les bundles fraichement installé dans AppKernel.php:

public function registerBundles()
{
    return array(
        // ...
        new FOS\UserBundle\FOSUserBundle(),
        new Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle(),
    );
}

Nous créons notre entité User.php:

<?php

namespace AppBundle\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ORM\Entity
 * @ApiResource(attributes={
 *     "normalization_context"={"groups"={"user", "user-read"}},
 *     "denormalization_context"={"groups"={"user", "user-write"}}
 * })
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @Groups({"user"})
     */
    protected $email;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     * @Groups({"user"})
     */
    protected $fullname;

    /**
     * @Groups({"user-write"})
     */
    protected $plainPassword;

    /**
     * @Groups({"user"})
     */
    protected $username;

    public function setFullname($fullname)
    {
        $this->fullname = $fullname;

        return $this;
    }
    public function getFullname()
    {
        return $this->fullname;
    }

    public function isUser(UserInterface $user = null)
    {
        return $user instanceof self && $user->id === $this->id;
    }
}

Nous poursuivons par la génération des clés, notez bien la pass phrase qu’il faudra copié dans le fichier parameters.yml

mkdir -p var/jwt # For Symfony3+, no need of the -p option
openssl genrsa -out var/jwt/private.pem -aes256 4096
openssl rsa -pubout -in var/jwt/private.pem -out var/jwt/public.pem

Nous mettons a jours les fichier suivants:

config.yml:

framework:
    translator:      { fallbacks: ["%locale%"] }

fos_user:
    db_driver: orm # other valid values are 'mongodb', 'couchdb' and 'propel'
    firewall_name: main
    user_class: AppBundle\Entity\User

lexik_jwt_authentication:
    private_key_path: '%jwt_private_key_path%'
    public_key_path:  '%jwt_public_key_path%'
    pass_phrase:      '%jwt_key_pass_phrase%'
    token_ttl:        '%jwt_token_ttl%'

routing.yml

api:
    resource: '.'
    type:     'api_platform'

app:
    resource: '@AppBundle/Action/'
    type:     'annotation'

api_login_check:
    path: /api/login_check

fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"

fos_user_profile:
    resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
    prefix: /profile

fos_user_register:
    resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
    prefix: /register

fos_user_resetting:
    resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
    prefix: /resetting

fos_user_change_password:
    resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
    prefix: /profile

security.yml

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: bcrypt

    role_hierarchy:
        ROLE_READER: ROLE_USER
        ROLE_ADMIN: ROLE_READER

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email

    firewalls:
        login:
            pattern:  ^/login
            stateless: true
            anonymous: true
            provider: fos_userbundle
            form_login:
                check_path: /login_check
                username_parameter: _username
                password_parameter: _password
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
                require_previous_session: false

        main:
            pattern: ^/
            provider: fos_userbundle
            stateless: true
            anonymous: true
            lexik_jwt: ~

        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

    access_control:
        - { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/books, roles: [ ROLE_READER ] }
        - { path: ^/, roles: [ ROLE_READER ] }

parameters.yml.dist et parameters.yml, n’oubliez pas la pass phrase pour les clés

parameters:
    # ...
    jwt_private_key_path: '%kernel.root_dir%/../var/jwt/private.pem' # ssh private key path
    jwt_public_key_path:  '%kernel.root_dir%/../var/jwt/public.pem'  # ssh public key path
    jwt_key_pass_phrase:  ''                                         # ssh key pass phrase
    jwt_token_ttl:        3600

Puis nous mettons à jour la base de données et créons notre premier utilisateur:

php bin/console doctrine:schema:update --force
php bin/console fos:user:create testuser test@example.com p@ssword
php bin/console fos:user:promote testuser ROLE_READER

Pour tester ca un petit coup de Curl:

curl -X POST http://127.0.0.1:8000/login_check -d _username=test@example.com -d _password=p@ssword

Et comme réponse nous avons:

{"token":"eyJhbGciOiJSUzI1NiJ9.eyJyb2xlcyI6WyJST0xFX1JFQURFUiIsIlJPTEVfVVNFUiJdLCJ1c2VybmFtZSI6InRlc3R1c2VyIiwiZXhwIjoxNDg2NDk5MjczLCJpYXQiOjE0ODY0OTU2NzN9.RL8VS8MuKhvg0uW23TPnlxsZusUIE86YuE_cg44F4rToe8c7zV6s-2lmuOhP5CyeB50IVfLlb4-RC1frKQFTIrEA1LJ2FewxKFO2Mb2sIQwQonAew3MTwnxbnPRWrS0sQCsb1NbXTxohc5WH-BU1U3IkuAjuTVLcB3g7JlPor0yedUU766BRXjIhklN7IuILKsjhteqGK6F9Ilg0zmLyjQV3-BUg1nnWygQ-O4BLrU_InvhpHZVOnPfikMftcKVAhn_Z4GKGVVORQxplhc4i0lJgzdV83AaImYqOzn3WBJxKnzmitb6rnOJ-SKXjdAYRix_rFwqIzzWNdcAg1-C731b08I3qcfWXmmadI2GsygVpemlagH8v6tcFjwVsyazblqFCA8oy37N0CfSVt7av8GIbenWtIDUS5Tl3a0SMxmcwg6rlTL_1pE0-E8mPa8ZbLho-nON2hKoQcG1LhIeuatzIi7lUSLCQv_uzy29Hpq7PPJ_43cZZDdex-vk3BVHbjZCOcggVxp-mDDTcU7VxZFwmi8AiP9ZAg8AFXviKcfM7D5Er2tB2k3HHsnCqTSGRJe9czNs-GaW55748BK_u0UiEBvBdDHUgmbGw4UTRw8aNTY8p8M_tavezC36p5zilyd2CB6knsLtm0aRkqyZaiK27uvajYMt65BpxqsmXzLw"}

Et voila !!!

Disponible sur github.