Écrire du code

Comprenez les standards et processus de Elgg pour que vos propositions de modification soient acceptées aussi vite que possible.

Agrément de licence

En proposant un patch vous acceptez de publier le code sous une licence GPLv2 et une licence MIT.

Demandes de fusion - Pull Requests

Les Pull requests (PRs) sont le meilleur moyen de contribuer au noyau de Elgg. L’équipe de développement les utilise y compris pour les modifications les plus mineures.

Pour de nouvelles fonctionnalités, soumettez une demande de fonctionnalité ou parlez-en avec nous en premier lieu, et assurez-vous que l’équipe du noyau approuve votre proposition avant de passer beaucoup de temps sur du code.

Listes de vérification

Utilisez ces listes de vérification réduites pour les nouveaux PRs sur Github afin de garantir des contributions de haute qualité et d’aider tout le monde à comprendre le statut des PRs ouverts.

Demandes de correction de bug - bugfix PRs :

- [ ] Commit messages are in the standard format
- [ ] Includes regression test
- [ ] Includes documentation update (if applicable)
- [ ] Is submitted against the correct branch
- [ ] Has LGTM from at least one core developer

Demandes de fonctionnalité - feature PRs :

- [ ] Commit messages are in the standard format
- [ ] Includes tests
- [ ] Includes documentation
- [ ] Is submitted against the correct branch
- [ ] Has LGTM from at least two core developers

Choisir une branche vers laquelle publier

Le tableau suivant suppose que la dernière version stable est la 2.1.

Type de changement

Branche vers laquelle publier

Correctif de sécurité

Ne le faites pas ! Envoyez un e-mail à security@elgg.org pour des conseils.

Correctif de bug

1.12 (ou 2.1 si le correctif pour 1.12 est trop complexe)

Performance

2.x

Dépréciation

2.x

Fonctionnalité mineure

2.x

Fonctionnalité majeure

master - maître

Introduit un changement non rétro-compatible

master - maître

Si vous ne savez pas quelle branche choisir, demandez !

La différence entre des fonctionnalités mineures et majeures est subjective et soumise à l’appréciation de l’équipe du noyau.

Format du message de commit

Nous exigeons un format particulier afin de permettre de publier plus souvent, avec des journaux des modifications et un historique des modifications améliorés. Suivez simplement les étapes suivantes :

  1. Commencez par le type en sélectionnant la dernière catégorie qui s’applique dans cette liste :

    • docs - uniquement la documentation a été mise à jour

    • chore - corvée - ceci comprend les remaniements, refactorisation de code, les changements de style de code, l’ajout de tests manquants, l’intégration continue, etc.

    • perf - l’objectif principal est d’améliorer la performance

    • fix - ceci corrige un bug

    • deprecate - la modification rend obsolète une partie de l’API

    • break - le changement casse n’importe une partie de l’API

    • feature - ajoute une nouvelle fonctionnalité pour les utilisateurs ou pour les développeurs

    • removed - cela supprime une fonctionnalité destinée aux utilisateurs ou aux développeurs

    • security - la modification affecte la sécurité d’une manière ou d’une autre. Merci de ne pas pousser ce commit vers un repository public. Contactez plutôt security@elgg.org.

    Par ex., si votre commit fait des remaniements pour corriger un bug, cela reste un « fix ». Cependant, si ce bug est lié à la sécurité, le type doit être « security » et vous devriez envoyer un e-mail à security@elgg.org avant de procéder. En cas de doute, faites au mieux, et un relecteur vous fournira des conseils.

  2. Entre parenthèses, ajoutez le component, une courte chaîne qui décrit le sous-système en train d’être modifié.

    Quelques exemples : views, i18n, seo, a11y, cache, db, session, router, <plugin_name>.

  3. Ajoutez une virgule, un espace, et un court résumé summary des modifications, qui va apparaître dans le journal des modifications - changelog.

    Aucune ligne ne devrait dépasser 100 caractères en longueur, aussi gardez un résumé concis.

    Bon résumé

    Mauvais résumé (problème)

    les propriétaires de pages voient leur propre bloc propriétaire sur les pages

    correction de bug (vague)

    la vue du graphique en barres n’échoue plus si “foo” n’est pas défini

    met à jour views/default/bar.php de sorte que la vue bar ne soit plus… (info redondante)

    réduit la mise en page de la rivière pour rentrer sur un iPhone

    modifie la mise en page de la rivière (vague)

    elgg_foo() gère les tableaux pour $bar

    dans elgg_foo() vous pouvez maintenant passer un tableau pour $bar et la fonction sera… (déplacez les précisions vers la description)

    supprime la couleur du lien de l’entête des commentaires dans la rivière

    corrige la bdd pour que… (info redondante)

    requiert un titre non-vide pour enregistrer les pages

    peut enregistrer des pages sans titre (résume de manière confuse l’ancien comportement)

  4. (recommandé) Sautez une ligne et ajoutez une description des modifications. Incluez leur raison d’être, toute information sur la compatibilité ascendante ou descendante, et toute raison pour laquelle cette modification devait être faite d’une certaine manière. Par exemple :

    Nous accélérons la migration des tables en utilisant une seule requête INSERT INTO … SELECT au lieu de ligne par ligne. Cette migration se produit durant la mise à niveau vers Elgg 1.9.

    A moins que votre modification soit triviale/évidente, une description est requise.

  5. Si le commit correspond à une demande - « issue » - Github, sautez une ligne et ajoutez Fixes # suivi par le numéro de demande. Par ex. Fixes #1234. Vous pouvez inclure de multiples demande en les séparant par des virgules.

    GitHub va fermer automatiquement la demande quand le commit est fusionné. Si vous souhaitez simplement faire référence à une demande, utilisez plutôt Refs #.

Quand c’est terminé, votre message de commit aura le format :

type(component): summary

Optional body
Details about the solution.
Opportunity to call out as breaking change.

Closes/Fixes/Refs #123, #456, #789

Voici un exemple de bon message de commit :

perf(upgrade): speeds up migrating remember me codes

We speed up the Remember Me table migration by using a single INSERT INTO ... SELECT query instead of row-by-row.
This migration takes place during the upgrade to 1.9.

Fixes #6204

Réécrire des messages de commits

Si votre PR ne se conforme pas au format standard de message de commit, nous vous demanderons de le réécrire.

Pour modifier seulement le dernier commit :

  1. Amendez le commit: git commit --amend (git ouvre le message dans un éditeur de texte).

  2. Changez le message et enregistrez/quittez l’éditeur.

  3. Forcez l’envoi de votre branche : git push -f your_remote your_branch (votre PR sera mis à jour).

  4. Renommez le titre du PR pour correspondre

Sinon vous pourrez avoir besoin d’effectuer un « rebase » interactif :

  1. Faites un rebase des derniers N commits: git rebase -i HEAD~N où N est le nombre. (Git va ouvrir le fichier git-rebase-todo pour modification)

  2. Pour les commits qui ont besoin d’être modifiés, modifiez pick en r (pour « reword », reformulation) et enregistrez/quittez l’éditeur.

  3. Modifiez le message (ou les messages) de commit, enregistrez/quitter l’éditeur (git va présenter un fichier pour chaque commit qui a besoin d’une reformulation).

  4. git push -f your_remote your_branch pour forcer un push de la branche (ce qui met à jour votre PR).

  5. Renommez le titre du PR pour correspondre

Standards de développements

Elgg utilise un ensemble de normes basées en partie sur les normes PEAR et PSR2. Vous pouvez voir le jeu de règles dans vendor/elgg/sniffs/src/Elgg/ruleset.xml.

Pour vérifier les violations des standards de votre code (à condition que vous ayez installé Elgg avec les dépendances dev), exécutez :

phpcs --standard=vendor/elgg/sniffs/src/Elgg -s path/to/dir/to/check

Pour corriger automatiquement des violations réparables, exécutez :

phpcbf --standard=vendor/elgg/sniffs/src/Elgg path/to/dir/to/fix

Tester

Elgg dispose de tests automatisés à la fois pour PHP et JavaScript. Toutes les nouvelles contributions doivent intégrer les tests appropriés.

Voir aussi

Écrire des tests

Recommandations générales

Découpez les tests par comportements que vous souhaitez tester et utilisez des noms qui décrivent le comportement. Par ex. :

  • Pas si bon : Une seule grosse méthode testAdd().

  • Mieux : Des méthodes testAddingZeroChangesNothing et testAddingNegativeNumberSubtracts

Efforcez-vous d’utiliser des designs à base de composants qui permettent de tester en isolement, sans de grands graphes de dépendances ou d’accès à la base de données. L’injection de dépendances est ici critique.

Tests PHP

PHPUnit

Située dans engine/tests/phpunit, c’est notre suite de tests préférée. Elle n’utilise pas d’accès à la base de données, et n’a qu’un accès superficiel à l’API des entités.

  • Si possible, nous vous encourageons à créer des composants qui sont testables dans cette suite.

  • Envisagez de séparer le stockage de votre composant de sorte que la logique métier puisse être testée ici.

  • Dépendez des classes Elgg\Filesystem\* plutôt que d’utiliser les fonctions du système de fichiers PHP.

Tester les interactions entre services

Dans l’idéal, vos tests devraient construire vos propres graphes d’objet isolés pour des manipulations directes, mais ce n’est pas toujours possible.

Si votre test dépend des Services Internes de Elgg (_elgg_services() qui renvoie un Elgg\Di\InternalContainer), réalisez que cela maintient une instance singleton pour la plupart des services qu’il fournit, et que de nombreux services conservent également leurs propres références locales vers ces services.

Du fait de ces références locales, replacer les services sur le SP = « Service Provider » - Fournisseur de Service - au sein d’un test n’aura souvent pas l’effet désiré. Au lieu de cela, vous pourriez avoir besoin d’utiliser la fonctionnalité disponible dans les services eux-mêmes :

  • Le service events a des méthodes backup() et restore().

  • Le service logger a des méthodes disable() et enable().

Meilleures pratiques de développement

Rendez votre code plus facile à lire, plus facile à maintenir, et plus facile à déboguer. Un usage consistant de ces recommandations signifie moins de travail de devinettes pour les développeurs, ce qui signifie des développeurs plus heureux, et plus productifs.

Développement en général

Ne. Vous. Répétez. Pas

Si vous copiez-collez des morceaux significatifs de code, considérez qu’il y a une opportunité de réduire la redondance en introduisant une fonction, un argument supplémentaire, une vue, ou une nouvelle classe de composant.

Par ex. Si vous trouvez des vues qui sont identiques à l’exception d’une seule valeur, remaniez-les en une seule vue qui accepte une option.

Note: Pour la publication d’un correctif de bug, un peu de duplication est préférable à de la refactorisation. Corrigez les bugs de la manière la plus simple possible, et refactorisez pour réduire la redondance dans la branche de la prochaine version mineure.

Adoptez SOLID et GRASP

Utilisez ces principes pour le design OO pour résoudre des problèmes en utilisant des composants couplés librement, et essayez de rendre tous les composants et le code d’intégration testables.

Les espacements ne coûtent rien

N’ayez pas peur d’utiliser des blocs de code séparés. Utilisez un espace unique pour séparer les paramètres des fonctions et les concaténations de chaînes.

Noms de variable

Utilisez des noms de variables auto-documentés. $group_guids est mieux que $array.

Évitez les doubles négations. Préférez $enable = true à $disable = false.

Nom des interfaces

Utilisez le motif Elgg\{Namespace}\{Name}.

N’ajoutez pas de préfixe I ou de suffixe Interface.

Nous n’utilisons aucun préfixe ou suffixe de sorte que nous sommes encouragés à :

  • nommez les classes d’implémentation de manière plus descriptive (le nom « default » est déjà pris).

  • typez sur les interfaces, parce que c’est la manière la plus courte et la plus simple de faire.

Nommez les implémentations comme Elgg\{Namespace}\{Interface}\{Implementation}.

Fonctions

Autant que possible, ayez des fonctions/méthodes qui renvoient un type unique. Utilisez des valeurs vides telle que array(), "", ou 0 pour indiquer l’absence de résultat.

Faites attention aux cas où des valeurs de retour valides (telles que "0") pourraient être interprétées comme vides.

Les fonctions qui ne déclenchent pas une exception lors d’une erreur devraient retourner false lorsqu’elles échouent.

Note

Les fonctions/méthodes d’un particulièrement bas niveau, non API, qui ne devraient pas échouer dans des conditions normales, devraient lancer une exception au lieu de renvoyer false.

Les fonctions qui ne renvoient qu’un booléen devraient être préfixées par is_ ou has_ (par ex., elgg_is_logged_in(), elgg_has_access_to_entity()).

Syntaxe ternaire

Acceptable seulement pour des déclarations sur une seule ligne, non imbriquées.

Minimisez la complexité

Minimisez les blocs imbriqués et les chemins d’exécution distincts au sein du code. Faites un Retour rapide pour réduire les niveaux imbriqués et la charge cognitive lors de la lecture du code.

Utilisez les commentaires à bon escient

Les bons commentaires décrivent le « pourquoi. » Le bon code décrit le « comment. » Par ex. :

Mauvais :

// increment $i only when the entity is marked as active.
foreach ($entities as $entity) {
        if ($entity->active) {
                $i++;
        }
}

Bon :

// find the next index for inserting a new active entity.
foreach ($entities as $entity) {
        if ($entity->active) {
                $i++;
        }
}

Ajoutez toujours un commentaire s’il n’est pas évident que quelque chose doit être fait d’une certaine manière. D’autres développeurs qui regardent le code devraient être découragés de réorganiser le code d’une manière qui le casserait.

// Can't use empty()/boolean: "0" is a valid value
if (elgg_is_empty($str)) {
    throw new \Elgg\Exceptions\Http\BadRequestException(elgg_echo('foo:string_cannot_be_empty'));
}

Commitez de manière efficace

  • Péchez par excès de commits atomiques qui sont précisément ciblés sur la modification d’un seul aspect du système.

  • Évitez de mélanger des modifications qui ne sont pas liées ou des modifications importantes des espaces. Les commits avec de nombreux changements sont effrayants et rendent les demandes de fusion - Pull Requests - difficiles à évaluer.

  • Utilisez des outils git visuels pour façonner des diffs extrêmement précis et lisibles.

Incluez des tests

A chaque fois que c’est possible, incluez des tests unitaires pour le code que vous ajoutez ou modifiez.

Conservez des corrections simples des bugs

Évitez la tentation de refactoriser le code pour la publication d’une correction de bug. Faire cela a tendance à introduire des régressions, à casser la fonctionnalité dans ce qui devrait être une version stable.

Recommandations PHP

Voici les standards de développement requis pour le noyau de Elgg et pour tous les plugins inclus. Les développeurs de plugins sont fortement encouragés à adopter ces standards.

Les développeurs devraient lire en premier le Guide des Standards de Développement PSR-2.

Les standards de Elgg étendent PSR-2, mais diffèrent des manières suivantes :

  • Indentez en utilisant le caractère tabulation, pas des espaces.

  • Les parenthèses ouvrantes pour les classes, méthodes, et fonctions doivent être sur la même ligne.

  • Si une ligne dépasse 100 caractères, envisagez de la remanier (par ex. en introduisant des variables).

  • La compatibilité avec PSR-1 est encouragée, mais pas strictement requise.

Documentation

  • Incluez des commentaires PHPDoc sur les fonctions et les classes (toutes les méthodes ; et les propriétés déclarées quand c’est approprié), y compris les types et descriptions de tous les paramètres.

  • Dans les listes de déclarations @param, le début des noms de variables et des descriptions doivent être alignés.

  • Annotez les classes, les méthodes, les propriétés et les fonctions avec @internal à moins qu’elles ne soient destinées au public, qu’elles ne soient déjà d’une visibilité limitée ou qu’elles ne soient dans une classe déjà marquée comme @internal.

  • Utilisez // ou /* */ pour les commentaires.

  • Utilisez seulement les commentaires // à l’intérieur du corps des fonctions et méthodes.

Règles de nommage

  • Utilisez des traits de soulignements - « underscores » - pour séparer les mots dans les noms de fonctions, de variables, et les propriétés. Les noms de méthodes utilisent la syntaxe camelCase.

  • Les noms de fonctions pour un usage public doivent commencer par elgg_.

  • Tous les autres noms de fonctions doivent commencer par _elgg_.

  • Nommez les globales et les constantes en MAJUSCULE (ACCESS_PUBLIC, $CONFIG).

Divers

Pour les pré-requis PHP, voyez composer.json.

N’utilisez pas les balises PHP raccourcies <? ou <%. Il est possible d’utiliser <?= dans la mesure où cela est toujours activé à partir de PHP 5.4.

Quand vous créez des chaînes de caractères avec des variables :

  • utilisez des chaînes de caractères avec des guillemets doubles

  • enveloppez les variables avec des accolades

Mauvais (difficile à lire) :

echo 'Hello, '.$name."!  How is your {$time_of_day}?";

Bon :

echo "Hello, {$name}!  How is your {$time_of_day}?";

Retirez les espaces vides à la fin des lignes.

Validation de la valeur

Quand vous travaillez avec des saisies utilisateur, préparez les saisies en dehors de la méthode de validation.

Mauvais :

function validate_email($email) {
        $email = trim($email);

        // validate
}

$email = get_input($email);

if (validate_email($email)) {
        // the validated email value is now out of sync with an actual input
}

Bon :

function validate_email($email) {
        // validate
}

$email = get_input($email);
$email = trim($email);

if (validate_email($email)) {
        // green light
}

Utilisez les exceptions

N’ayez pas peur d’utiliser les exceptions. Elles sont plus faciles à gérer que des sorties de fonction mixtes :

Mauvais :

/**
* @return string|bool
*/
function validate_email($email) {
        if (empty($email)) {
                return 'Email is empty';
        }

        // validate

        return true;
}

Bon :

/**
* @return void
* @throws \Elgg\Exceptions\InvalidArgumentException
*/
function validate_email($email) {
        if (empty($email)) {
                throw new \Elgg\Exceptions\InvalidArgumentException('Email is empty');
        }

        // validate and throw if invalid
}

Documentez les valeurs de retour

N’utilisez pas @return void sur des méthodes qui renvoient une valeur ou null.

Mauvais :

/**
* @return bool|void
*/
function validate_email($email) {
        if (empty($email)) {
                return;
        }

        // validate

        return true;
}

Bon :

/**
* @return bool|null
*/
function validate_email($email) {
        if (empty($email)) {
                return null;
        }

        // validate

        return true;
}

Recommandations CSS

Enregistrez le CSS dans des fichiers avec une extension .css.

Utilisez des abréviations quand c’est possible

Mauvais :

background-color: #333333;
background-image:  url(...);
background-repeat:  repeat-x;
background-position:  left 10px;
padding: 2px 9px 2px 9px;

Bon :

background: #333 url(...) repeat-x left 10px;
padding: 2px 9px;

Utilisez les traits d’union « - », pas les tirets de soulignement ou underscores « _ »

Mauvais :

.example_class {}

Bon :

.example-class {}

Note

Vous devriez préfixer vos identifiants et noms de classe avec un texte qui identifie votre plugin.

Une propriété par ligne

Mauvais :

color: white;font-size: smaller;

Bon :

color: white;
font-size: smaller;

Déclarations de propriété

Celles-ci devraient être espacées comme ceci : propriété: valeur;

Mauvais :

color:value;
color :value;
color : value;

Bon :

color: value;

Préfixes fournisseurs - vendor

  • Regroupez les préfixes fournisseurs pour la même propriété

  • La version la plus longue des préfixes fournisseurs en premier

  • Incluez toujours la version sans préfixe fournisseur

  • Ajoutez une ligne supplémentaire entre les groupes avec préfixes fournisseurs et les autres propriétés

Mauvais :

-moz-border-radius: 5px;
border: 1px solid #999999;
-webkit-border-radius: 5px;
width: auto;

Bon :

border: 1px solid #999999;

-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;

width: auto;

Regroupez les sous-propriétés

Mauvais :

background-color: white;
color: #0054A7;
background-position: 2px -257px;

Bon :

background-color: white;
background-position: 2px -257px;
color: #0054A7;

Recommandations JavaScript

Les mêmes standards de formatage que PHP s’appliquent.

Related functions should be in a namespaced ECMAScript module.

Les expressions d’une fonction devraient se terminer par un point-virgule.

APIs obsolètes

De temps en temps, des fonctions et des classes doivent être dépréciées au profit de nouveaux remplacements. Dans la mesure où les auteurs de plugins tierce-partie s’appuient sur une API cohérente, la compatibilité ascendante doit être maintenue, mais ne sera pas maintenue indéfiniment dans la mesure où les auteurs de plugins sont supposés mettre à jour leurs plugins. Afin de maintenir la compatibilité ascendante, les API obsolètes vont suivre les recommandations suivantes :

  • Les versions mineures (1.x) qui déprécient une API doivent inclure une fonction/classe d’emballage « wrapper » (ou tout autre moyen approprié) qui maintient la compatibilité ascendante, y compris tout bug de la fonction/classe originelle. Cette couche de compatibilité utilise elgg_deprecated_notice('...', '1.11') pour journaliser le fait que cette fonction est obsolète.

  • La révision majeure suivante (2.0) supprime la couche de compatibilité. Toute utilisation de l’API obsolète devrait être corrigé auparavant.