├── .gitignore ├── Gemfile ├── Gemfile.lock ├── Gruntfile.js ├── LICENSE ├── README.md ├── _config.yml ├── _includes └── welcome.md ├── _layouts ├── default.html └── page.html ├── _posts ├── 01-01-01-Getting-Started.md ├── 01-02-01-Use-the-Current-Stable-Version.md ├── 01-03-01-Built-in-Web-Server.md ├── 01-04-01-Mac-Setup.md ├── 01-05-01-Windows-Setup.md ├── 02-01-01-Code-Style-Guide.md ├── 03-01-01-Language-Highlights.md ├── 03-02-01-Programming-Paradigms.md ├── 03-03-01-Namespaces.md ├── 03-04-01-Standard-PHP-Library.md ├── 03-05-01-Command-Line-Interface.md ├── 03-06-01-XDebug.md ├── 04-01-01-Dependency-Management.md ├── 04-02-01-Composer-and-Packagist.md ├── 04-03-01-PEAR.md ├── 05-01-01-Coding-Practices.md ├── 05-02-01-The-Basics.md ├── 05-03-01-Date-and-Time.md ├── 05-04-01-Design-Patterns.md ├── 05-05-01-PHP-and-UTF8.md ├── 06-01-01-Dependency-Injection.md ├── 06-02-01-Basic-Concept.md ├── 06-03-01-Complex-Problem.md ├── 06-04-01-Containers.md ├── 06-05-01-Further-Reading.md ├── 07-01-01-Databases.md ├── 07-02-01-Databases_MySQL.md ├── 07-03-01-Databases_PDO.md ├── 07-04-01-Interacting-via-Code.md ├── 07-05-01-Abstraction-Layers.md ├── 08-01-01-Templating.md ├── 08-02-01-Benefits.md ├── 08-03-01-Plain-PHP-Templates.md ├── 08-04-01-Compiled-Templates.md ├── 08-05-01-Further-Reading.md ├── 09-01-01-Errors-and-Exceptions.md ├── 09-02-01-Errors.md ├── 09-03-01-Exceptions.md ├── 10-01-01-Security.md ├── 10-02-01-Web-Application-Security.md ├── 10-03-01-Password-Hashing.md ├── 10-04-01-Data-Filtering.md ├── 10-05-01-Configuration-Files.md ├── 10-06-01-Register-Globals.md ├── 10-07-01-Error-Reporting.md ├── 11-01-01-Testing.md ├── 11-02-01-Test-Driven-Development.md ├── 11-03-01-Behavior-Driven-Development.md ├── 11-04-01-Complementary-Testing-Tools.md ├── 12-01-01-Servers-and-Deployment.md ├── 12-02-01-Platform-as-a-Service.md ├── 12-03-01-Virtual-or-Dedicated-Servers.md ├── 12-04-01-Shared-Servers.md ├── 12-05-01-Building-your-Application.md ├── 13-01-01-Virtualization.md ├── 13-02-01-Vagrant.md ├── 13-03-01-Docker.md ├── 14-01-01-Caching.md ├── 14-02-01-Bytecode-Cache.md ├── 14-03-01-Object-Caching.md ├── 15-01-01-Documenting.md ├── 15-02-01-PHPDoc.md ├── 16-01-01-Resources.md ├── 16-05-01-PHP-PaaS-Providers.md ├── 16-06-01-Frameworks.md ├── 16-07-01-Components.md ├── 16-10-01-Books.md └── 17-01-01-Community.md ├── banners.md ├── css └── all.css ├── images ├── banners │ ├── btn1-120x90.png │ ├── btn2-120x60.png │ ├── leaderboard-728x90.png │ ├── lg-rect-386x280.png │ ├── med-rect-300x250.png │ ├── rect-180x150.png │ ├── sq-btn-125x125.png │ └── vert-rect-240x400.png ├── favicon.png ├── nmc-logo.gif ├── og-image.png └── og-logo.png ├── index.html ├── less └── all.less ├── package.json ├── pages ├── Design-Patterns.md ├── Functional-Programming.md ├── The-Basics.md └── example.md ├── scripts ├── fastclick.js └── setup.js └── styles ├── all.css ├── all.less ├── base ├── all.less ├── bars-buttons.less ├── buttons.less ├── grid.less ├── idioms.less ├── prefixer.less ├── reset.less ├── spacing.less ├── typography.less └── variables.less ├── print.css ├── site ├── site-content.less ├── site-footer.less ├── site-header.less ├── site-navigation.less └── variables.less └── syntax.css /.gitignore: -------------------------------------------------------------------------------- 1 | /_site/ 2 | *.DS_Store 3 | node_modules 4 | vendor 5 | .bundle 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages' 3 | gem 'rouge' 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | RedCloth (4.2.9) 5 | activesupport (5.0.0.1) 6 | concurrent-ruby (~> 1.0, >= 1.0.2) 7 | i18n (~> 0.7) 8 | minitest (~> 5.1) 9 | tzinfo (~> 1.1) 10 | addressable (2.4.0) 11 | blankslate (2.1.2.4) 12 | classifier-reborn (2.0.4) 13 | fast-stemmer (~> 1.0) 14 | coffee-script (2.4.1) 15 | coffee-script-source 16 | execjs 17 | coffee-script-source (1.10.0) 18 | colorator (0.1) 19 | concurrent-ruby (1.0.2) 20 | ethon (0.9.1) 21 | ffi (>= 1.3.0) 22 | execjs (2.7.0) 23 | faraday (0.10.0) 24 | multipart-post (>= 1.2, < 3) 25 | fast-stemmer (1.0.2) 26 | ffi (1.9.14) 27 | ffi (1.9.14-x64-mingw32) 28 | gemoji (2.1.0) 29 | github-pages (39) 30 | RedCloth (= 4.2.9) 31 | github-pages-health-check (~> 0.2) 32 | jekyll (= 2.4.0) 33 | jekyll-coffeescript (= 1.0.1) 34 | jekyll-feed (= 0.3.1) 35 | jekyll-mentions (= 0.2.1) 36 | jekyll-redirect-from (= 0.8.0) 37 | jekyll-sass-converter (= 1.3.0) 38 | jekyll-sitemap (= 0.8.1) 39 | jemoji (= 0.5.0) 40 | kramdown (= 1.5.0) 41 | liquid (= 2.6.2) 42 | maruku (= 0.7.0) 43 | mercenary (~> 0.3) 44 | pygments.rb (= 0.6.3) 45 | rdiscount (= 2.1.7) 46 | redcarpet (= 3.3.2) 47 | terminal-table (~> 1.4) 48 | github-pages-health-check (0.3.2) 49 | net-dns (~> 0.6) 50 | public_suffix (~> 1.4) 51 | typhoeus (~> 0.7) 52 | html-pipeline (1.9.0) 53 | activesupport (>= 2) 54 | nokogiri (~> 1.4) 55 | i18n (0.7.0) 56 | jekyll (2.4.0) 57 | classifier-reborn (~> 2.0) 58 | colorator (~> 0.1) 59 | jekyll-coffeescript (~> 1.0) 60 | jekyll-gist (~> 1.0) 61 | jekyll-paginate (~> 1.0) 62 | jekyll-sass-converter (~> 1.0) 63 | jekyll-watch (~> 1.1) 64 | kramdown (~> 1.3) 65 | liquid (~> 2.6.1) 66 | mercenary (~> 0.3.3) 67 | pygments.rb (~> 0.6.0) 68 | redcarpet (~> 3.1) 69 | safe_yaml (~> 1.0) 70 | toml (~> 0.1.0) 71 | jekyll-coffeescript (1.0.1) 72 | coffee-script (~> 2.2) 73 | jekyll-feed (0.3.1) 74 | jekyll-gist (1.4.0) 75 | octokit (~> 4.2) 76 | jekyll-mentions (0.2.1) 77 | html-pipeline (~> 1.9.0) 78 | jekyll (~> 2.0) 79 | jekyll-paginate (1.1.0) 80 | jekyll-redirect-from (0.8.0) 81 | jekyll (>= 2.0) 82 | jekyll-sass-converter (1.3.0) 83 | sass (~> 3.2) 84 | jekyll-sitemap (0.8.1) 85 | jekyll-watch (1.5.0) 86 | listen (~> 3.0, < 3.1) 87 | jemoji (0.5.0) 88 | gemoji (~> 2.0) 89 | html-pipeline (~> 1.9) 90 | jekyll (>= 2.0) 91 | kramdown (1.5.0) 92 | liquid (2.6.2) 93 | listen (3.0.8) 94 | rb-fsevent (~> 0.9, >= 0.9.4) 95 | rb-inotify (~> 0.9, >= 0.9.7) 96 | maruku (0.7.0) 97 | mercenary (0.3.6) 98 | mini_portile2 (2.1.0) 99 | minitest (5.9.1) 100 | multipart-post (2.0.0) 101 | net-dns (0.8.0) 102 | nokogiri (1.6.8.1) 103 | mini_portile2 (~> 2.1.0) 104 | nokogiri (1.6.8.1-x64-mingw32) 105 | mini_portile2 (~> 2.1.0) 106 | octokit (4.6.1) 107 | sawyer (~> 0.8.0, >= 0.5.3) 108 | parslet (1.5.0) 109 | blankslate (~> 2.0) 110 | posix-spawn (0.3.12) 111 | public_suffix (1.5.3) 112 | pygments.rb (0.6.3) 113 | posix-spawn (~> 0.3.6) 114 | yajl-ruby (~> 1.2.0) 115 | rb-fsevent (0.9.8) 116 | rb-inotify (0.9.7) 117 | ffi (>= 0.5.0) 118 | rdiscount (2.1.7) 119 | redcarpet (3.3.2) 120 | rouge (2.0.7) 121 | safe_yaml (1.0.4) 122 | sass (3.4.22) 123 | sawyer (0.8.1) 124 | addressable (>= 2.3.5, < 2.6) 125 | faraday (~> 0.8, < 1.0) 126 | terminal-table (1.7.3) 127 | unicode-display_width (~> 1.1.1) 128 | thread_safe (0.3.5) 129 | toml (0.1.2) 130 | parslet (~> 1.5.0) 131 | typhoeus (0.8.0) 132 | ethon (>= 0.8.0) 133 | tzinfo (1.2.2) 134 | thread_safe (~> 0.1) 135 | unicode-display_width (1.1.1) 136 | yajl-ruby (1.2.1) 137 | 138 | PLATFORMS 139 | ruby 140 | x64-mingw32 141 | 142 | DEPENDENCIES 143 | github-pages 144 | rouge 145 | 146 | BUNDLED WITH 147 | 1.13.6 148 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | // Project configuration 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | less: { 6 | dist: { 7 | options: { 8 | cleancss: true, 9 | compress: true, 10 | ieCompat: true 11 | }, 12 | files: { 13 | "css/all.css": "less/all.less" 14 | } 15 | } 16 | }, 17 | postcss: { 18 | options: { 19 | map: true, 20 | processors: [ 21 | require('autoprefixer')({ 22 | browsers: ['last 2 versions', 'ie 9'] 23 | }) 24 | ] 25 | }, 26 | dist: { 27 | src: 'css/all.css' 28 | } 29 | }, 30 | watch: { 31 | less: { 32 | files: ['less/**/*.less'], 33 | tasks: ['less:dist', 'postcss:dist'], 34 | options: { 35 | spawn: false 36 | } 37 | } 38 | } 39 | }); 40 | 41 | // Load plugins 42 | grunt.loadNpmTasks('grunt-contrib-less'); 43 | grunt.loadNpmTasks('grunt-contrib-watch'); 44 | grunt.loadNpmTasks('grunt-postcss'); 45 | 46 | // Default task(s) 47 | grunt.registerTask('default', ['less', 'postcss:dist']); 48 | }; 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Josh Lockhart 2 | 3 | http://creativecommons.org/licenses/by-nc-sa/3.0/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP: La bonne manière 2 | 3 | ## Vue d'ensemble 4 | 5 | Vous êtes sur la page github du projet _PHP: La bonne manière (en: The right way)_. 6 | 7 | * Ce site web est un projet Jekyll. 8 | * Chaque section et sous-section correspondent à un fichier Markdown se trouvant dans `_posts/`. 9 | * Les sous-sections possèdent `isChild: true` en début de fichier. 10 | * La navigation et la structure de la page sont automatiquement générées. 11 | 12 | ## Faites passer le mot ! 13 | 14 | _PHP: La bonne manière_ contient des bannières que vous pouvez utiliser sur votre site web. Montrez votre soutien et 15 | faites découvrir aux nouveaux développeurs PHP où trouver les infos pour bien débuter! 16 | 17 | [Voir les images](http://www.phptherightway.com/banners.html) 18 | 19 | ## How to Contribute 20 | 21 | 1. Fork and edit 22 | 2. Optionally install [Ruby](https://rvm.io/rvm/install/) with [Jekyll](https://github.com/mojombo/jekyll/) gem to preview locally 23 | 3. Submit pull request for consideration 24 | 25 | ### Contributor Style Guide 26 | 27 | 1. Use American English spelling (*primary English repo only*) 28 | 2. Use four (4) spaces to indent text; do not use tabs. 29 | 3. Wrap all text to 120 characters. 30 | 4. Code samples should adhere to PSR-1 or higher. 31 | 32 | ## Where 33 | 34 | 35 | 36 | * [English](http://www.phptherightway.com) 37 | * [Deutsch](http://rwetzlmayr.github.io/php-the-right-way) 38 | * [Español](http://phpdevenezuela.github.io/php-the-right-way) 39 | * [Français](http://eilgin.github.io/php-the-right-way/) 40 | * [Indonesia](http://id.phptherightway.com) 41 | * [Italiano](http://it.phptherightway.com) 42 | * [Polski](http://pl.phptherightway.com) 43 | * [Português do Brasil](http://br.phptherightway.com) 44 | * [Română](https://bgui.github.io/php-the-right-way/) 45 | * [Slovenščina](http://sl.phptherightway.com) 46 | * [Srpski](http://phpsrbija.github.io/php-the-right-way/) 47 | * [Türkçe](http://hkulekci.github.io/php-the-right-way/) 48 | * [български](http://bg.phptherightway.com) 49 | * [Русский язык](http://getjump.github.io/ru-php-the-right-way) 50 | * [Українська](http://iflista.github.com/php-the-right-way) 51 | * [العربية](https://adaroobi.github.io/php-the-right-way/) 52 | * [فارسى](http://novid.github.io/php-the-right-way/) 53 | * [ภาษาไทย](https://apzentral.github.io/php-the-right-way/) 54 | * [한국어판](http://modernpug.github.io/php-the-right-way) 55 | * [日本語](http://ja.phptherightway.com) 56 | * [简体中文](http://laravel-china.github.io/php-the-right-way/) 57 | * [繁體中文](http://laravel-taiwan.github.io/php-the-right-way) 58 | 59 | ### Translations 60 | 61 | If you are interested in translating _PHP: The Right Way_, fork this repo on GitHub and publish your localized fork to your own GitHub Pages account. We'll link to your translation from the primary document. 62 | 63 | To avoid fragmentation and reader confusion, please choose one of these options: 64 | 65 | 1. We link to your GitHub Pages fork with `[username].github.com/php-the-right-way` 66 | 2. We link to your GitHub Pages fork with a subdomain (e.g. "ru.phptherightway.com") 67 | 68 | If you use a subdomain, enter the subdomain into the `CNAME` file, and ask us to setup DNS for you. If you do not use a subdomain, remove the `CNAME` file entirely else your fork will not build when pushed. 69 | 70 | When your translation is ready, open an issue on the Issue Tracker to let us know. 71 | 72 | ## Why 73 | 74 | There's been a lot of discussion lately about how the PHP community lacks sufficient, credible information for programmers new to PHP. This repository aims to solve this problem. 75 | 76 | ## Who 77 | 78 | My name is [Josh Lockhart](http://twitter.com/codeguy). I'm the author of the [Slim Framework](http://www.slimframework.com/), and I work for [New Media Campaigns](http://www.newmediacampaigns.com/). 79 | 80 | ### Collaborators 81 | 82 | * [Kris Jordan](http://krisjordan.com/) 83 | * [Phil Sturgeon](http://philsturgeon.co.uk/) 84 | 85 | ## License 86 | 87 | [Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-nc-sa/3.0/) 88 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | baseurl: /php-the-right-way 2 | highlighter: rouge 3 | markdown: kramdown 4 | permalink: date 5 | maruku: 6 | use_tex: false 7 | use_divs: false 8 | png_engine: blahtex 9 | png_dir: images/latex 10 | png_url: /images/latex 11 | 12 | gems: 13 | - jekyll-sitemap 14 | 15 | defaults: 16 | - 17 | scope: 18 | path: "" 19 | values: 20 | sitemap: false 21 | 22 | exclude: ['LICENSE', 'README.md', 'pages/example.md', 'vendor'] 23 | 24 | future: true 25 | -------------------------------------------------------------------------------- /_includes/welcome.md: -------------------------------------------------------------------------------- 1 | # Bienvenue 2 | 3 | Il existe énormément d'informations obsolètes sur la toile à propos de PHP, ce qui conduit les nouveaux utilisateurs de PHP à prendre de mauvaises habitudes, propageant de mauvaises pratiques et du code peu sûr. 4 | _PHP: La bonne manière_ est une référence concise et facile à lire à propos des conventions d'écriture 5 | les plus connues sur le PHP, des liens sur les tutoriaux faisant autorité sur le web et des pratiques que les contributeurs de ce document considèrent comme meilleures à l'heure actuelle. 6 | 7 | _Il n'existe pas une seule et unique façon d'utiliser PHP_. Ce site web a pour but d'amener les nouveaux développeurs PHP sur des sujets qu'ils n'auraient pas pu découvrir avant qu'il ne soit trop tard, et vise 8 | à donner aux professionnels chevronnés des idées neuves sur ces sujets qu'ils ont pu traiter pendant des années sans 9 | s'être penchés dessus. Ce site web ne vous dira pas quels outils utiliser, mais au lieu de cela vous offre 10 | des suggestions sur plusieurs options, et quand c'est possible en vous expliquant les différences dans l'approche et 11 | les cas d'utilisations. 12 | 13 | Ce document n'est pas figé et sera amené à être mis à jour avec des informations utiles et des exemples au fur et à 14 | mesure qu'ils seront disponibles. 15 | 16 | ## Traductions {#translations} 17 | 18 | _PHP: La bonne manière_ est (déjà) traduit en plusieurs langues : 19 | 20 | * [English](http://www.phptherightway.com) 21 | * [Deutsch](http://rwetzlmayr.github.io/php-the-right-way) 22 | * [Español](http://phpdevenezuela.github.io/php-the-right-way) 23 | * [Français](http://eilgin.github.io/php-the-right-way/) 24 | * [Indonesia](http://id.phptherightway.com) 25 | * [Italiano](http://it.phptherightway.com) 26 | * [Polski](http://pl.phptherightway.com) 27 | * [Português do Brasil](http://br.phptherightway.com) 28 | * [Română](https://bgui.github.io/php-the-right-way/) 29 | * [Slovenščina](http://sl.phptherightway.com) 30 | * [Srpski](http://phpsrbija.github.io/php-the-right-way/) 31 | * [Türkçe](http://hkulekci.github.io/php-the-right-way/) 32 | * [български](http://bg.phptherightway.com) 33 | * [Русский язык](http://getjump.github.io/ru-php-the-right-way) 34 | * [Українська](http://iflista.github.com/php-the-right-way) 35 | * [العربية](https://adaroobi.github.io/php-the-right-way/) 36 | * [فارسى](http://novid.github.io/php-the-right-way/) 37 | * [ภาษาไทย](https://apzentral.github.io/php-the-right-way/) 38 | * [한국어판](http://modernpug.github.io/php-the-right-way) 39 | * [日本語](http://ja.phptherightway.com) 40 | * [简体中文](http://laravel-china.github.io/php-the-right-way/) 41 | * [繁體中文](http://laravel-taiwan.github.io/php-the-right-way) 42 | 43 | ## Livre 44 | 45 | La version la plus récente de _PHP: The Right Way_ (en) est aussi disponible au format PDF, EPUB et MOBI. [Voir sur Leanpub][1] 46 | 47 | ## Comment contribuer {#how-to-contribute} 48 | 49 | Aidez-nous à faire de ce site la meilleure ressource disponible 50 | pour les nouveaux programmeurs PHP. [Contribuer sur GitHub][2] 51 | 52 | [1]: https://leanpub.com/phptherightway 53 | [2]: https://github.com/codeguy/php-the-right-way/tree/gh-pages 54 | -------------------------------------------------------------------------------- /_posts/01-01-01-Getting-Started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pour démarrer 3 | anchor: getting_started 4 | --- 5 | 6 | # Pour démarrer {#getting_started_title} 7 | -------------------------------------------------------------------------------- /_posts/01-02-01-Use-the-Current-Stable-Version.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Utiliser la dernière version stable (8.0) 3 | isChild: true 4 | anchor: use_the_current_stable_version 5 | --- 6 | 7 | ## Utiliser la dernière version stable (8.0) {#use_the_current_stable_version_title} 8 | 9 | Si vous venez juste de commencer à utiliser PHP, prenez soin de débuter avec la dernière version stable 10 | de [PHP][php-release]. PHP 8.x a fait de grands progrès en ajoutant de [puissantes fonctionnalités](#les_points_importants_du_language) 11 | au cours des dernières années. Le moteur de PHP a par ailleurs été largement ré-écrit pour être beaucoup plus rapide que les versions précédentes. 12 | 13 | Vous trouverez encore de nombreuses références à PHP 5.x dont la dernière itération est la 5.6. 14 | Vous devriez migrer vers cette dernière version stable car PHP 5.6 ne reçoit plus de [mise à jour de sécurité](http://php.net/supported-versions.php). 15 | La migration reste néanmoins très aisée car il n'existe pas énormement de [changements 16 | incompatibles][php-compatibility-breaks]. 17 | 18 | Si vous cherchez des informations sur l'utilisation d'une fonction particulière, n'hésitez pas à consulter la documentation sur le site [php.net][php-docs]. 19 | 20 | [php-release]: http://www.php.net/downloads.php 21 | [php-docs]: http://www.php.net/manual/fr/ 22 | [php-compatibility-breaks]: https://www.php.net/manual/fr/migration80.php 23 | -------------------------------------------------------------------------------- /_posts/01-03-01-Built-in-Web-Server.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Serveur web intégré 3 | isChild: true 4 | anchor: builtin_web_server 5 | --- 6 | 7 | ## Serveur web intégré {#builtin_web_server_title} 8 | 9 | Vous pouvez commencer à apprendre PHP sans avoir à installer et configurer un serveur web (vous devrez utiliser au minimum PHP 5.4). 10 | Pour démarrer le serveur intégré, exécutez la ligne de commande suivante dans un terminal à la racine de votre projet : 11 | 12 | {% highlight console %} 13 | > php -S localhost:8000 14 | {% endhighlight %} 15 | 16 | * [Apprenez en plus sur l'outil en ligne de commandes][cli-server] 17 | 18 | [cli-server]: http://www.php.net/manual/fr/features.commandline.webserver.php 19 | -------------------------------------------------------------------------------- /_posts/01-04-01-Mac-Setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation sous Mac 3 | isChild: true 4 | anchor: mac_setup 5 | --- 6 | 7 | ## Installation sous Mac {#mac_setup_title} 8 | 9 | Le système d'exploitation OSX contient une version précompilée de PHP mais est généralement en retard sur la dernière version stable. 10 | Sierra contient la version 5.6.24, High Sierra la version 7.1.6 et Catalina la version 7.3.11. 11 | 12 | ### Installation via un gestionnaire de paquets 13 | 14 | Pour mettre à jour la version de PHP sur OSX vous pouvez passer via 15 | de nombreux [gestionnaire de paquets][mac-package-managers], [php-osx de Liip][php-osx-downloads] étant recommandé. 16 | 17 | ### Installation depuis la source 18 | 19 | L'autre option est de le [compiler soi-même][mac-compile]. Dans ce cas, faites attention à ce que l'IDE Xcode soit 20 | installé ou bien son [substitut en ligne de commande][apple-developer] téléchargeable 21 | sur le Mac Developer Center d'Apple. 22 | 23 | ### Installation "Tout-en-un" 24 | 25 | Pour une installation "tout-en-un" incluant PHP, le serveur web Apache et la base de données MySQL, le tout contrôlé 26 | par une jolie interface graphique, essayez [MAMP][mamp-downloads] ou [XAMPP][xampp]. 27 | 28 | [mac-package-managers]: http://www.php.net/manual/fr/install.macosx.packages.php 29 | [mac-compile]: http://www.php.net/manual/fr/install.macosx.compile.php 30 | [xcode-gcc-substitution]: https://github.com/kennethreitz/osx-gcc-installer 31 | [apple-developer]: https://developer.apple.com/downloads 32 | [mamp-downloads]: http://www.mamp.info/en/downloads/index.html 33 | [php-osx-downloads]: http://php-osx.liip.ch/ 34 | [xampp]: http://www.apachefriends.org/fr/index.html 35 | -------------------------------------------------------------------------------- /_posts/01-05-01-Windows-Setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation sous Windows 3 | isChild: true 4 | anchor: windows_setup 5 | --- 6 | 7 | ## Installation sous Windows {#windows_setup_title} 8 | 9 | PHP est disponible sous Windows de plusieurs façons. Vous pouvez [télécharger les binaires][php-downloads] et jusqu'à récemment, vous pouviez utiliser un installateur '.msi'. 10 | Cependant il n'est plus maintenu depuis la version 5.3.0. 11 | 12 | Pour l'apprentissage et le développement en local, vous pouvez dorénavant utiliser le serveur intégré à PHP 8.0+, ainsi 13 | vous n'aurez plus à vous soucier de la configuration du serveur web. Si vous souhaitez un système "tout-en-un" incluant 14 | un serveur web et MySQL alors des outils tels que [WPI][wpi], [Zend Server CE][zsce], [XAMPP][xampp] ou encore 15 | [WAMP][wamp] vous permettront d'avoir un environnement de développement complet rapidement. Ceci étant dit, ces 16 | outils sont différents de ce que l'on trouve en production donc faites attention sur les différences d'environnement si 17 | vous travaillez sur Windows et déployez sur Linux. 18 | 19 | Si vous désirez utiliser Windows comme plateforme de production alors le serveur IIS vous donnera le meilleur compromis 20 | entre stabilité et performance. Vous pouvez utiliser [phpmanager][phpmanager] qui est un plugin graphique pour IIS 21 | afin d'effectuer les configurations nécessaires pour faire tourner PHP. IIS intègre FastCGI prêt à l'emploi, vous 22 | n'avez qu'à configurer PHP en tant qu'extension. Pour plus d'informations, visitez le site dédié sur [iis.net][php-iis]. 23 | 24 | Généralement, faire tourner une application sur différents environnement de développement peut conduire à des comportements étranges ce qui peut être hasardeux une fois déployé en production. 25 | Si vous développez sous Windows mais que vos machines de production tournent sous Linux, vous feriez mieux de considérer l'utilisation de [machines virtuelles](/#virtualization_title). 26 | 27 | Il existe toutefois un excellent article en anglais écrit par Chris Tankersley sur les [outils à utiliser][windows-tools] si vous souhaitez travailler sous Windows. 28 | 29 | [php-downloads]: http://windows.php.net 30 | [phpmanager]: http://phpmanager.codeplex.com/ 31 | [wpi]: http://www.microsoft.com/web/downloads/platform.aspx 32 | [zsce]: http://www.zend.com/fr/products/server/free-edition 33 | [xampp]: https://www.apachefriends.org/fr/index.html 34 | [wamp]: http://www.wampserver.com/ 35 | [php-iis]: http://php.iis.net/ 36 | [windows-tools]: http://ctankersley.com/2016/11/13/developing-on-windows-2016/ 37 | -------------------------------------------------------------------------------- /_posts/02-01-01-Code-Style-Guide.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Normes 3 | anchor: code_style_guide 4 | --- 5 | 6 | # Normes {#code_style_guide_title} 7 | 8 | La communauté PHP est large et diverse, composée d'innombrables bibliothèques, de frameworks et de composants. Il est 9 | courant pour les développeurs PHP de choisir plusieurs d'entre eux et de les combiner en un seul projet. Il est important 10 | que le code PHP adhère (de façon aussi proche que possible) à un style commun pour rendre le partage plus facile 11 | entre développeurs et de garder une certaine cohérence avec l'utilisation de code tiers. 12 | 13 | Le [Framework Interop Group][fig] a proposé et approuvé une série de conventions de codage. Celles qui sont liées aux 14 | conventions d'écriture sont le [PSR-0][psr0], le [PSR-1][psr1], le [PSR-2][psr2] et le [PSR-4][psr4]. Ces recommandations sont 15 | un ensemble de règles que certains projets ont adoptées comme Drupal, Zend, Symfony, Laravel, CakePHP, phpBB, AWS SDK, 16 | FuelPHP, Lithium, etc. Vous pouvez les utiliser dans vos projets ou bien la vôtre si vous en avez une. 17 | 18 | Idéalement, vous devriez écrire du code PHP qui adhère à des standards connus. Cela peut être une combinaison des PSR ou 19 | un des standards créés par PEAR ou Zend. 20 | 21 | * [En savoir plus sur PSR-0][psr0] 22 | * [En savoir plus sur PSR-1][psr1] 23 | * [En savoir plus sur PSR-2][psr2] 24 | * [En savoir plus sur PSR-4][psr4] 25 | * [Lire les conventions de codage de PEAR][pear-cs] 26 | * [Lire les conventions de codage de Zend][zend-cs] 27 | * [Lire les conventions de codage de Symfony][symfony-cs] 28 | 29 | Vous pouvez utiliser [PHP_CodeSniffer][phpcs] pour vérifier que votre code respecte une de ces recommandations. Des 30 | plugins pour des éditeurs de texte comme [Sublime Text 2][st-cs] vous permettent d'avoir un aperçu des écarts en temps réel. 31 | 32 | Utiliser le [PHP Coding Standards Fixer][phpcsfixer] de Fabien Potencier afin de formatter automatiquement la syntaxe de 33 | votre code selon les standards définis, ce qui vous évite de le faire vous-même à la main. 34 | 35 | Faites en sorte que l'infrastructure de votre code et que les noms des variables choisis soient en anglais. Les 36 | commentaires peuvent être écrits dans n'importe quelle langue du moment que l'ensemble des personnes ayant à travailler 37 | dessus puissent les comprendre. 38 | 39 | [fig]: http://www.php-fig.org/ 40 | [psr0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md 41 | [psr1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md 42 | [psr2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md 43 | [psr4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md 44 | [pear-cs]: http://pear.php.net/manual/en/standards.php 45 | [zend-cs]: http://framework.zend.com/wiki/display/ZFDEV2/Coding+Standards 46 | [symfony-cs]: http://symfony.com/doc/current/contributing/code/standards.html 47 | [phpcs]: http://pear.php.net/package/PHP_CodeSniffer/ 48 | [st-cs]: https://github.com/benmatselby/sublime-phpcs 49 | [phpcsfixer]: http://cs.sensiolabs.org/ 50 | -------------------------------------------------------------------------------- /_posts/03-01-01-Language-Highlights.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Les points importants du langage 3 | anchor: language_highlights 4 | --- 5 | 6 | # Les points importants du langage {#language_highlights_title} 7 | -------------------------------------------------------------------------------- /_posts/03-02-01-Programming-Paradigms.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Les paradigmes de programmation 3 | isChild: true 4 | anchor: programming_paradigms 5 | --- 6 | 7 | ## Les paradigmes de programmation {#programming_paradigms_title} 8 | 9 | Le PHP est un langage flexible et dynamique, supportant une variété de techniques de programmation. Il a énormément évolué au 10 | cours des années en ajoutant notamment un solide modèle orienté objet avec PHP 5.0 (2004), les fonctions anonymes et 11 | les espaces de noms avec PHP 5.3 (2009) et les "traits" avec PHP 5.4 (2012). 12 | 13 | ### Programmation orientée objet 14 | 15 | Le PHP a un ensemble très complet de principes de programmation orientée objet en prenant en compte le support des classes, 16 | des classes abstraites, des interfaces, de l'héritage, des constructeurs, du clonage, des exceptions, etc. 17 | 18 | * [En savoir plus sur l'orienté objet][oop] 19 | * [En savoir plus sur les "traits"][traits] 20 | 21 | ### Programmation fonctionnelle 22 | 23 | Le PHP supporte les fonctions de "première classe" ce qui signifie qu'une fonction peut être affectée à une variable. 24 | Les fonctions définies par l'utilisateur ainsi que les fonctions intégrées au langage peuvent être référencées par une 25 | variable et invoquées dynamiquement. Les fonctions peuvent être passées en tant qu'argument à d'autres fonctions (on 26 | parle alors de fonctions d'ordre supérieur) et elles peuvent retourner d'autres fonctions. 27 | 28 | La récursion est une fonctionnalité permettant à une fonction de s'appeler elle-même, cependant la plupart des fonctions 29 | PHP se concentrent sur la partie "itération". 30 | 31 | Les nouvelles fonctions anonymes avec le support pour les fermetures (_closures_ en anglais) sont présentes depuis 32 | PHP 5.3 (2009). 33 | 34 | Le PHP 5.4 a rajouté la possibilité de lier ("bind") les fermetures à la portée d'un objet et a aussi amélioré le support pour 35 | les "callables" de façon à ce qu'elles puissent être utilisées aussi bien avec les fonctions anonymes (dans la plupart des 36 | cas). 37 | 38 | * Continuer la lecture sur la [programmation fonctionnelle en PHP]({{ site.baseurl }}/pages/Functional-Programming.html) 39 | * [En savoir plus sur les fonctions anonymes][anonymous-functions] 40 | * [En savoir plus sur la classe Closure][closure-class] 41 | * [Plus de détails sur Closures RFC][closures-rfc] 42 | * [En savoir plus sur les callables][callables] 43 | * [En savoir plus sur les fonctions invoquées dynamiquement avec `call_user_func_array`][call-user-func-array] 44 | 45 | ### Méta-programmation 46 | 47 | Le PHP supporte différentes formes de méta-programmation à travers des mécanismes tels que l'API Reflection et les 48 | méthodes magiques. Il existe un grand nombre de méthodes magiques comme `__get()`, `__set()`, `__clone()`, 49 | `__toString()`, `__invoke()`, etc permettant aux développeurs d'interférer avec le comportement d'une classe. Les 50 | développeurs Ruby répètent souvent que le PHP manque de `method_missing` mais cela est pourtant disponible avec 51 | `__call()` et `__callStatic()`. 52 | 53 | PHP 8.0 (2020) apporte maintenant le principe d'[annotations](https://www.php.net/manual/fr/language.attributes.overview.php) avec PHP 8.0 (2020) permettant de rajouter des métadonnées sur les classes et les méthodes. 54 | 55 | * [En savoir plus sur les méthodes magiques][magic-methods] 56 | * [En savoir plus sur l'API Reflection][reflection] 57 | 58 | [namespaces]: http://php.net/manual/fr/language.namespaces.php 59 | [overloading]: http://php.net/manual/fr/language.oop5.overloading.php 60 | [oop]: http://www.php.net/manual/fr/language.oop5.php 61 | [anonymous-functions]: http://www.php.net/manual/fr/functions.anonymous.php 62 | [closure-class]: http://php.net/manual/fr/class.closure.php 63 | [callables]: http://php.net/manual/fr/language.types.callable.php 64 | [magic-methods]: http://php.net/manual/fr/language.oop5.magic.php 65 | [reflection]: http://www.php.net/manual/fr/intro.reflection.php 66 | [traits]: http://www.php.net/traits 67 | [call-user-func-array]: http://php.net/manual/fr/function.call-user-func-array.php 68 | [closures-rfc]: https://wiki.php.net/rfc/closures 69 | -------------------------------------------------------------------------------- /_posts/03-03-01-Namespaces.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Les espaces de noms 3 | isChild: true 4 | anchor: namespaces 5 | --- 6 | 7 | ## Les espaces de noms {#namespaces_title} 8 | 9 | Comme mentionné plus haut, la communauté PHP a beaucoup de développeurs créant beaucoup de code. Cela signifie que le 10 | code d'une bibliothèque PHP peut utiliser le même nom de classe qu'une autre bibliothèque. Quand plusieurs bibliothèques 11 | sont utilisées dans le même espace de nom, il peut y avoir des collisions de noms, ce qui pose problème. 12 | 13 | _Les espaces de nom_ résolvent ce problème. Comme décrit dans le manuel de référence PHP, les espaces de nom peuvent 14 | être comparés aux répertoires d'un système de fichiers. De même, deux classes PHP peuvent avoir le même nom si elles sont 15 | créées dans des espaces de nom distincts. 16 | 17 | Il est important pour vous que vous utilisiez les espaces de nom dans votre code. Ainsi vous et d'autres développeurs 18 | pourrez utiliser ce code sans crainte d'entrer en collision avec d'autres bibliothèques. 19 | 20 | Une bonne manière d'utiliser les espaces de nom se trouve dans le [PSR-0][psr0] qui vise à fournir un fichier standard, 21 | une convention pour les classes et les espaces de nom pour permettre d'avoir du code "plug-and-play". 22 | 23 | En décembre 2013, le PHP-FIG a créé un nouveau standard d'autochargement: [PSR-4][psr4], qui un jour va probablement 24 | remplacer PSR-0. Pour le moment, les 2 sont utilisables étant donné que PSR-4 ne tourne que sur PHP 5.3+ et que 25 | beaucoup de projets implémentent PSR-0. Si vous pensez utiliser un standard d'autochargement pour une nouvelle 26 | application ou un paquetage alors vous devriez certainement voir du côté de PSR-4. 27 | 28 | * [En savoir plus sur les espaces de noms][namespaces] 29 | * [En savoir plus sur PSR-0][psr0] 30 | * [En savoir plus sur PSR-4][psr4] 31 | 32 | [namespaces]: http://php.net/manual/fr/language.namespaces.php 33 | [psr0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md 34 | [psr4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md 35 | -------------------------------------------------------------------------------- /_posts/03-04-01-Standard-PHP-Library.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bibliothèque PHP standard 3 | isChild: true 4 | anchor: standard_php_library 5 | --- 6 | 7 | ## La bibliothèque PHP standard {#standard_php_library_title} 8 | 9 | La bibliothèque standard PHP (SPL en anglais) est fournie avec PHP et donne accès à une collection de classes et 10 | d'interfaces. Elle est composée de classes permettant de manipuler les structures de données les plus courantes comme les 11 | piles (stack), les files (queue), les tas (heap) et des itérateurs qui peuvent parcourir ces structures ou vos propres 12 | classes implémentant les interfaces SPL. 13 | 14 | * [En savoir plus sur la SPL][spl] 15 | 16 | [spl]: http://php.net/manual/fr/book.spl.php 17 | -------------------------------------------------------------------------------- /_posts/03-05-01-Command-Line-Interface.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Interface en ligne de commande 3 | isChild: true 4 | anchor: command_line_interface 5 | --- 6 | 7 | ## L'interface en ligne de commande {#command_line_interface_title} 8 | 9 | Le PHP a été créé principalement pour écrire des applications web mais il peut être tout aussi utile pour écrire des 10 | programmes en ligne de commande (_command line interface_ ou CLI en anglais). Ces programmes peuvent vous aider à 11 | automatiser les tâches les plus courantes comme les tests, le déploiement et l'administration du site. 12 | 13 | Les programmes PHP CLI sont puissants car vous pouvez directement utiliser le code de votre application sans avoir à 14 | créer et à réaliser une interface web "sécurisée". Faites juste attention à ne pas mettre vos scripts PHP à la racine 15 | de votre répertoire web public. 16 | 17 | Essayez de faire tourner PHP en ligne de commande: 18 | 19 | {% highlight bash %} 20 | > php -i 21 | {% endhighlight %} 22 | 23 | L'option `-i` va afficher votre configuration exactement comme la fonction [`phpinfo`][phpinfo]. 24 | 25 | L'option `-a` fournit un terminal interactif similaire aux terminaux ruby (IRB) et python. Il existe par ailleurs 26 | d'autres [options utiles][cli-options]. 27 | 28 | Écrivons un simple programme CLI "Hello, $nom". Pour faire ces essais, créez un fichier nommé `hello.php` et écrivez le 29 | code ci-dessous. 30 | 31 | {% highlight php %} 32 | php hello.php 52 | Usage: php hello.php [nom] 53 | > php hello.php world 54 | Hello, world 55 | {% endhighlight %} 56 | 57 | 58 | * [En savoir plus sur l'exécution de PHP en ligne de commande][php-cli] 59 | * [Comment mettre en place PHP en ligne de commande sur Windows][php-cli-windows] 60 | 61 | [phpinfo]: http://php.net/manual/fr/function.phpinfo.php 62 | [cli-options]: http://www.php.net/manual/fr/features.commandline.options.php 63 | [argc]: http://php.net/manual/fr/reserved.variables.argc.php 64 | [argv]: http://php.net/manual/fr/reserved.variables.argv.php 65 | [php-cli]: http://php.net/manual/fr/features.commandline.php 66 | [php-cli-windows]: http://www.php.net/manual/fr/install.windows.commandline.php 67 | [exit-codes]: http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits 68 | -------------------------------------------------------------------------------- /_posts/03-06-01-XDebug.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: XDebug 3 | isChild: true 4 | anchor: xdebug 5 | --- 6 | 7 | ## XDebug {#xdebug_title} 8 | 9 | Un des outils les plus utiles dans le développement logiciel est un bon débogueur. Il vous permet de tracer l'exécution 10 | de votre code et de surveiller le contenu de la pile. XDebug, le debogueur de PHP, peut être utilisé par de nombreux 11 | EDIs pour fournir des fonctionnalités telles que les point d'arrêts ou l'inspection de la pile. Il permet aussi à des outils comme 12 | PHPUnit et KCacheGrind de faire de l'analyse pour la couverture de code et du "profiling". 13 | 14 | Si vous vous trouvez dans une closure, que vous avez recours à var_dump/print_r et que vous ne trouvez toujours pas de 15 | solution - alors vous devriez utiliser un débogueur. 16 | 17 | [Installer XDebug][xdebug-install] peut se révéler compliqué mais l'une des fonctionnalités les plus importantes est 18 | le "deboguage à distance" - Si vous développez du code localement et que vous testez ensuite sur une machine virtuelle 19 | voir un autre serveur alors le déboguage à distance vous permettra de le faire sans problème. 20 | 21 | Traditionellement, vous allez modifier votre fichier VHost Apache ou votre .htaccess avec les valeurs suivantes: 22 | 23 | php_value xdebug.remote_host=192.168.?.? 24 | php_value xdebug.remote_port=9000 25 | 26 | Le "remote host" et "remote port" correspondent à l'IP de votre ordinateur et au port sur lequel votre EDI va écouter. 27 | Il suffit alors de configurer votre EDI pour écouter sur le port choisi et de charger l'URL: 28 | 29 | http://votre-site.exemple.com/index.php?XDEBUG_SESSION_START=1 30 | 31 | Votre EDI va maintenant intercepter l'état courant au fur et à mesure que le script s'exécute vous permettant de mettre 32 | des points d'arrêts et d'inspecter les valeurs en mémoire. 33 | 34 | Les débogueurs graphiques permettent de se déplacer très facilement dans le code, d'inspecter les variables et 35 | d'évaluer du code à l'exécution. 36 | Beaucoup d'EDI ont un support intégré ou via un plugin pour le déboguage avec xdebug. MacGDBp est un xdebug gratuit, 37 | open-source pour Mac. 38 | 39 | * [En savoir plus sur XDebug][xdebug-docs] 40 | * [En savoir plus sur MacGDBp][macgdbp-install] 41 | 42 | [xdebug-docs]: http://xdebug.org/docs/ 43 | [xdebug-install]: http://xdebug.org/docs/install 44 | [macgdbp-install]: http://www.bluestatic.org/software/macgdbp/ 45 | -------------------------------------------------------------------------------- /_posts/04-01-01-Dependency-Management.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: La gestion des dépendances 3 | anchor: dependency_management 4 | --- 5 | 6 | # La gestion des dépendances {#dependency_management_title} 7 | 8 | Il existe une tonne de bibliothèques PHP, de frameworks et de composants pour gérer les dépendances. Votre projet va 9 | sûrement utiliser plusieurs d'entre eux — ce sont les dépendances d'un projet. Jusqu'à récemment, le PHP n'avait pas de 10 | moyen fiable pour gérer ces dépendances : même si vous les gériez de façon manuelle, vous deviez toujours vous 11 | inquiéter des autoloaders. Mais plus maintenant. 12 | 13 | À l'heure actuelle, il existe deux gestionnaires de packaging pour PHP - Composer et PEAR. Lequel correspond le mieux à 14 | vos attentes ? Cela dépend de la taille de votre projet. 15 | 16 | * Utiliser **Composer** pour la gestion des dépendances d'un seul projet. 17 | * Utiliser **PEAR** lorsque vous devez gérer les dépendances pour un système complet. 18 | 19 | En général, les packages Composer seront disponibles uniquement pour les projets auxquels vous les aurez explicitement 20 | spécifiés alors qu'un package PEAR sera disponible pour tous vos projets PHP. Bien que PEAR semble être la meilleure 21 | approche au premier regard, il existe de nombreux avantages à utiliser une approche de gestion des dépendances par 22 | projet. 23 | -------------------------------------------------------------------------------- /_posts/04-02-01-Composer-and-Packagist.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Composer et Packagist 3 | isChild: true 4 | anchor: composer_and_packagist 5 | --- 6 | 7 | ## Composer et Packagist {#composer_and_packagist_title} 8 | 9 | Composer est un **excellent** gestionnaire de dépendances pour PHP. Listez les dépendances de votre projet dans un fichier 10 | `composer.json` et en quelques commandes, Composer va automatiquement télécharger ces dépendances et les installer pour 11 | vous. 12 | 13 | Il existe déjà un grand nombre de bibliothèques PHP compatibles avec Composer, prêtes à être utilisées par votre projet. 14 | Ces "paquets" sont listés sur [Packagist][1], le répertoire officiel pour les bibliothèques compatibles avec Composer. 15 | 16 | ### Comment installer Composer 17 | 18 | Vous pouvez installer Composer localement (dans votre répertoire de travail courant; bien que cela ne soit plus 19 | recommandé) ou globalement (par ex., /usr/local/bin). Supposons que vous vouliez installer Composer localement. 20 | Depuis la racine de votre projet, tapez : 21 | 22 | curl -s https://getcomposer.org/installer | php 23 | 24 | Cela va télécharger `composer.phar` qui est une archive PHP binaire. Vous pouvez la lancer avec `php` pour gérer vos 25 | dépendances. Attention : Si vous redirigez du code téléchargé directement dans un interpréteur, 26 | veuillez d'abord lire le code en ligne pour confirmer qu'il est sûr. 27 | 28 | #### Installation sous Windows 29 | Pour les utilisateurs de Windows, la façon la plus pratique de mettre en place Composer est d'installer [ComposerSetup][6] 30 | qui va faire tout le travail pour vous (modification du `$PATH`) afin d'appeler l'utilitaire `composer` directement 31 | depuis votre terminal. 32 | 33 | ### Comment installer Composer (manuellement) 34 | 35 | Installer manuellement Composer est une technique avancée, cependant il existe diverses raisons pour lesquelles un 36 | développeur aurait besoin de le faire. L'installation interactive va vérifier que la version installée: 37 | 38 | - contient une version suffisamment récente pour être utilisable 39 | - peut exécuter correctement des fichiers `.phar` 40 | - a des permissions suffisantes sur certaines répertoires 41 | - possède des extensions problématiques qui ne seront alors pas chargées 42 | - a les bonnes configurations au niveau du fichier `php.ini` 43 | 44 | Étant donné qu'une installation manuelle n'effectue aucune de ces vérifications, vous devrez décider vous-même 45 | du meilleur compromis à faire. Voici comment obtenir Composer manuellement : 46 | 47 | curl -s https://getcomposer.org/composer.phar -o $HOME/local/bin/composer 48 | chmod +x $HOME/local/bin/composer 49 | 50 | Le chemin `$HOME/local/bin` (ou le répertoire de votre choix) doit être dans la variable d'environement `$PATH`. Ainsi, 51 | la commande `composer` peut être accessible de partout. 52 | 53 | Quand vous tombez sur de la documentation qui indique de lancer Composer avec `php composer.phar install`, vous pouvez 54 | substituer cette commande avec: 55 | 56 | composer install 57 | 58 | La section suivante part du principe que vous avez installé Composer "globlalement". 59 | 60 | ### Comment définir et installer les dépendances 61 | 62 | Composer garde la trace des dépendances de votre projet dans un fichier nommé `composer.json`. Vous pouvez le maintenir 63 | vous même à la main ou utiliser Composer. La commande `composer require` ajoute une dépendance à votre projet et, si 64 | vous n'avez pas de fichier `composer.json`, va le créer. Voici un exemple qui ajoute [Twig][2] en tant que dépendance 65 | pour votre projet: 66 | 67 | composer require twig/twig:~1.8 68 | 69 | Alternativement, la commande `composer init` va vous guider à travers la création du fichier `composer.json`. De toute 70 | manière, une fois que ce fichier est créé, vous pouvez indiquer à Composer de télécharger et d'installer vos dépendances 71 | dans le répertoire `vendors/`. Cela s'applique aussi aux projets que vous avez téléchargés et qui possèdent déjà un 72 | fichier `composer.json`: 73 | 74 | composer install 75 | 76 | Ensuite, ajoutez cette ligne dans le fichier PHP principal de votre application; cela va dire à PHP d'utiliser 77 | l'auto-chargeur de Composer pour les dépendances de votre projet: 78 | 79 | {% highlight php %} 80 | pear-channel/Package 62 | 63 | Le préfixe "pear" est écrit en dur pour éviter tout conflit étant donné que le canal pear peut être le même que d'autres 64 | paquets par exemple. Puis le nom court du canal (ou l'URL complète) peut être utilisé pour référencer dans quel canal se 65 | trouve le paquet. 66 | 67 | Quand ce paquet est installé, il sera accessible dans votre répertoire de façon automatique grâce à l'auto-chargeur de 68 | Composer: 69 | 70 | > vendor/pear-pear2.php.net/PEAR2_HTTP_Request/pear2/HTTP/Request.php 71 | 72 | Pour utiliser ce paquet PEAR, référencez-le simplement de cette façon: 73 | 74 | {% highlight php %} 75 | $request = new pear2\HTTP\Request(); 76 | {% endhighlight %} 77 | 78 | * [En savoir plus sur la façon d'utiliser PEAR avec Composer][6] 79 | 80 | [1]: http://pear.php.net/ 81 | [2]: http://pear.php.net/manual/fr/installation.getting.php 82 | [3]: http://pear.php.net/packages.php 83 | [4]: http://pear.php.net/manual/fr/guide.users.commandline.channels.php 84 | [5]: /#composer_and_packagist 85 | [6]: http://getcomposer.org/doc/05-repositories.md#pear 86 | -------------------------------------------------------------------------------- /_posts/05-01-01-Coding-Practices.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pratiques de programmation 3 | anchor: coding_practices 4 | --- 5 | 6 | # Pratiques de programmation {#coding_practices_title} 7 | -------------------------------------------------------------------------------- /_posts/05-02-01-The-Basics.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Les bases 3 | isChild: true 4 | anchor: the_basics 5 | --- 6 | 7 | ## Les bases {#the_basics_title} 8 | 9 | PHP est un language vaste permettant aux programmeurs de tout niveau de produire du code non seulement rapidement mais 10 | aussi efficacement. Cependant, en avançant dans le langage, nous oublions parfois les bases que nous avions apprises 11 | (ou survolées) de façon un peu légère en faveur de raccourcis et autres mauvaises habitudes. Pour combattre ce problème 12 | récurrent, cette section tient à rappeler aux programmeurs les pratiques de programmation de base de PHP. 13 | 14 | * Continuer en lisant [les bases]({{ site.baseurl }}/pages/The-Basics.html). 15 | -------------------------------------------------------------------------------- /_posts/05-03-01-Date-and-Time.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: La date et le temps 3 | isChild: true 4 | anchor: date_and_time 5 | --- 6 | 7 | ## La date et le temps {#date_and_time_title} 8 | 9 | Le PHP a une classe nommée DateTime afin d'aider à lire, écrire, comparer et calculer avec les dates et le temps. Il existe 10 | beaucoup de fonctions liées aux dates en PHP en plus de DateTime, mais cette dernière fournit une interface orientée objet à 11 | la plupart des usages courants. Elle peut gérer les fuseaux horaires mais cela dépasse le cadre de notre introduction. 12 | 13 | Pour commencer à travailler avec DateTime, convertissez les chaînes de caractères représentant des dates ou du temps avec 14 | la méthode `createFromFormat()` ou faites `new \DateTime`. Utilisez la méthode `format()` pour convertir la date 15 | vers une représentation sous forme de chaîne de caractères. 16 | 17 | {% highlight php %} 18 | format('m/d/Y') . "\n"; 23 | {% endhighlight %} 24 | 25 | Le calcul des dates avec DateTime est possible à l'aide de la classe DateInterval. DateTime a des méthodes comme `add()` 26 | et `sub()` qui prennent une variable de type DateInterval en argument. N'écrivez pas du code qui attend que chaque jour 27 | ait le même nombre de secondes car le passage à l'heure d'été/d'hiver et les changements de fuseaux horaires brisent cette 28 | assertion. Utilisez plutôt les intervalles de date. Pour calculer ces différences, utilisez la méthode `diff()`. Cette 29 | dernière va retourner un objet DateInterval qui est très facile à afficher. 30 | 31 | {% highlight php %} 32 | add(new \DateInterval('P1M6D')); 36 | 37 | $diff = $end->diff($start); 38 | echo 'Différence: ' . $diff->format('%m mois, %d jours (total: %a jours)') . "\n"; 39 | // Différence: 1 mois, 6 jours (total: 37 jours) 40 | {% endhighlight %} 41 | 42 | Avec les objets DateTime vous pouvez utilisez les opérateurs de comparaison : 43 | {% highlight php %} 44 | format('m/d/Y') . ' '; 62 | } 63 | {% endhighlight %} 64 | 65 | * [En savoir plus sur DateTime][datetime] 66 | * [En savoir plus sur le formatage des dates][dateformat] (les formats et options acceptées) 67 | 68 | [datetime]: http://www.php.net/manual/book.datetime.php 69 | [dateformat]: http://www.php.net/manual/function.date.php 70 | -------------------------------------------------------------------------------- /_posts/05-04-01-Design-Patterns.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Les motifs de conception 3 | isChild: true 4 | anchor: design_patterns 5 | --- 6 | 7 | 8 | ## Les motifs de conception {#design_patterns_title} 9 | 10 | Lorsque vous construisez votre application, il est souvent utile d'utiliser des motifs courants dans votre code et dans 11 | la structure générale de votre projet. Utiliser ces motifs est utile car il devient alors plus facile de gérer le code 12 | et de permettre aux autres développeurs de comprendre plus rapidement comment tout cela tient. 13 | 14 | Si vous utilisez un framework, alors la plupart du code métier et la structure du projet se baseront sur ce framework, 15 | donc de nombreuses décisions sur les motifs à utiliser seront prises à votre place. Mais c'est à vous de choisir les 16 | motifs les plus utiles à utiliser au sein de votre code. Si, d'un autre côté, vous n'utilisez pas 17 | de framework pour construire votre application, cela ne vous empêchera pas de choisir un certain nombre de motifs que 18 | vous jugerez nécessaires. 19 | 20 | * Continuer la lecture sur les [motifs de conceptions]({{ site.baseurl }}/pages/Design-Patterns.html). 21 | -------------------------------------------------------------------------------- /_posts/05-05-01-PHP-and-UTF8.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Travailler avec de l'UTF-8 3 | isChild: true 4 | anchor: php_and_utf8 5 | --- 6 | 7 | ## Travailler avec de l'UTF-8 {#php_and_utf8_title} 8 | 9 | _Cette section a été traduite à partir de la page d'[Alex Cabal](https://alexcabal.com/) sur les 10 | [meilleures pratiques PHP](https://phpbestpractices.org/#utf-8) et sert de base pour vous donner des conseils sur 11 | l'utilisation de l'UTF-8_. 12 | 13 | ### Il n'y a pas de recette magique. Faites attention, soyez consciencieux et cohérent. 14 | 15 | Jusqu'à présent PHP n'inclut pas de support bas niveau pour l'unicode. Il existe des moyens de s'assurer que les chaînes 16 | de caractères encodées en UTF-8 seront traitées correctement mais cela n'est pas facile et demande une attention particulière 17 | tout le long de la chaîne de traitement, allant de la page HTML à vos requêtes SQL en passant par le PHP. Les prochains 18 | paragraphes vont tenter de vous résumer la bonne approche à adopter face à du contenu Unicode. 19 | 20 | ### UTF-8 au niveau de PHP 21 | 22 | Les opérations basiques sur les chaînes de caractères comme la concaténation ou l'affectation de chaînes à des variables 23 | ne demandent rien de particulier en ce qui concerne l'UTF-8. En revanche, la plupart des fonctions manipulant les chaînes 24 | comme `strpos()` et `strlen()` ont besoin d'une attention particulière. Ces fonctions ont en effet souvent leur contre-partie 25 | `mb_*` comme `mb_strpos()` et `mb_strlen()`. Ces fonctions `mb_*` proviennent de 26 | l'[extension pour les chaînes de caractères multi-octets] et ont été conçus spécialement pour les chaînes Unicode. 27 | 28 | Vous devez utiliser les fonctions `mb_*` à chaque fois que vous manipulez une chaîne de caractère Unicode. Par exemple, 29 | si vous utilisez `substr()` sur une chaîne UTF-8, il y a de forte chance pour que le résultat contienne des caractères 30 | à moitié tronqués. La fonction correcte dans ce genre de cas serait d'utiliser `mb_substr()`. 31 | 32 | La difficulté réside dans le fait de se souvenir à chaque fois d'utiliser les fonctions `mb_*` quand c'est nécessaire. 33 | Si jamais vous l'oubliez ne serait-ce qu'une seule fois alors votre chaîne Unicode aura de grande chance d'être incompréhensible 34 | en sortie de traitement. 35 | 36 | Les fonctions traitant les chaînes n'ont pas toutes leur équivalent `mb_*`. S'il y en a une qui est dans ce cas alors 37 | vous n'avez pas de chance. 38 | 39 | Vous devriez utiliser la fonction `mb_internal_encoding()` en haut de tout vos scripts PHP (ou en haut d'un fichier d'en-tête 40 | global) et la fonction `mb_http_output()` juste après si vous devez afficher du texte en sortie. Définir explicitement 41 | l'encodage de caractère de vos chaînes vous simplifiera énormement la vie. 42 | 43 | Par ailleurs, beaucoup de fonctions PHP opérant sur les chaînes ont un paramètre optionnel vous permettant de spécifier 44 | l'encodage de caractère. Vous devriez alors toujours indiquer explicitement que vous utilisez de l'UTF-8. Par exemple, 45 | la fonction `htmlentities()` possède une option pour l'encodage des caractères. Notez que depuis PHP 5.4.0, l'UTF-8 est 46 | l'encodage par défaut pour `htmlentities()` et `htmlspecialchars()`. 47 | 48 | Au final, si vous développez et déployez une application utilisant l'UTF-8 sans être certain que l'extension `mbstring` 49 | sera présente, pensez alors à utiliser des alternatives comme le package Composer [patchwork/utf8]. Il utilisera `mbstring` 50 | si jamais il le trouve sinon il utilisera les fonctions non-UTF8. 51 | 52 | [extension pour les chaînes de caractères multi-octets]: http://php.net/manual/fr/book.mbstring.php 53 | [patchwork/utf8]: https://packagist.org/packages/patchwork/utf8 (en) 54 | 55 | ### UTF-8 au niveau de la base de données 56 | 57 | Si votre script PHP a accès à MySQL, il y a une forte chance que vos chaînes de caractères soient stockées en tant que chaînes 58 | non-UTF8 même si vous suivez les précautions vues plus haut. 59 | 60 | Pour vous assurer que vos chaînes aillent de PHP vers MySQL en UTF-8, vérifiez que votre base de données et les tables 61 | qu'elle contient sont toutes enregistrées avec l'encodage de caractères et la collation `utf8mb4` et que votre connexion 62 | PDO soit aussi mise sur cet encodage. Voir l'exemple plus bas. Ceci est _extrêmement important_. 63 | 64 | Notez que pour utiliser le support complet pour UTF-8, vous devez utiliser l'encodage de caractères `utf8mb4` et non 65 | `utf8` ! Voir les détails plus loin pour comprendre pourquoi. 66 | 67 | ### UTF-8 au niveau du navigateur web 68 | 69 | Utilisez la fonction `mb_http_output()` pour vous assurer que votre script PHP affichera du texte en UTF-8 dans votre 70 | navigateur. 71 | 72 | Le navigateur devra ensuite être averti par le biais de la réponse HTTP que cette page est encodée en UTF-8. L'approche 73 | historique pour faire cela était d'inclure le [tag ``](http://htmlpurifier.org/docs/enduser-utf8.html) dans le tag 74 | ``. Cette approche est parfaitement valide mais indiquer l'encodage directement dans l'en-tête HTTP `Content-Type` 75 | est en fait [plus rapide](https://developers.google.com/speed/docs/best-practices/rendering#SpecifyCharsetEarly). 76 | 77 | {% highlight php %} 78 | \PDO::ERRMODE_EXCEPTION, 101 | \PDO::ATTR_PERSISTENT => false 102 | ) 103 | ); 104 | 105 | // Stocke notre chaîne en tant que chaîne UTF-8 dans la base de données 106 | // Votre base ainsi que ses tables doivent être encodées avec utf8mb4 (character set et collation). 107 | $handle = $link->prepare('insert into ElvishSentences (Id, Body) values (?, ?)'); 108 | $handle->bindValue(1, 1, PDO::PARAM_INT); 109 | $handle->bindValue(2, $string); 110 | $handle->execute(); 111 | 112 | // Récupère la chaîne que l'on vient juste de stocker pour prouver qu'elle a été correctement stockée 113 | $handle = $link->prepare('select * from ElvishSentences where Id = ?'); 114 | $handle->bindValue(1, 1, PDO::PARAM_INT); 115 | $handle->execute(); 116 | 117 | // stocke le résultat dans un objet que l'on affichera dans notre HTML 118 | $result = $handle->fetchAll(\PDO::FETCH_OBJ); 119 | 120 | header('Content-Type: text/html; charset=utf-8'); 121 | ?> 122 | 123 | 124 | page de test UTF-8 125 | 126 | 127 | Body); // Cela devrait correctement afficher notre contenu en UTF-8 130 | } 131 | ?> 132 | 133 | 134 | {% endhighlight %} 135 | 136 | ### Pour aller plus loin 137 | 138 | * [Manuel PHP: Opérations sur les chaînes de caractères](http://php.net/manual/fr/language.operators.string.php) 139 | * [Manuel PHP: Fonctions sur les chaînes de caractères](http://php.net/manual/fr/ref.strings.php) 140 | * [`strpos()`](http://php.net/manual/fr/function.strpos.php) 141 | * [`strlen()`](http://php.net/manual/fr/function.strlen.php) 142 | * [`substr()`](http://php.net/manual/fr/function.substr.php) 143 | * [Manuel PHP: Fonctions sur les chaînes multi-octets](http://php.net/manual/fr/ref.mbstring.php) 144 | * [`mb_strpos()`](http://php.net/manual/fr/function.mb-strpos.php) 145 | * [`mb_strlen()`](http://php.net/manual/fr/function.mb-strlen.php) 146 | * [`mb_substr()`](http://php.net/manual/fr/function.mb-substr.php) 147 | * [`mb_internal_encoding()`](http://php.net/manual/fr/function.mb-internal-encoding.php) 148 | * [`mb_http_output()`](http://php.net/manual/fr/function.mb-http-output.php) 149 | * [`htmlentities()`](http://php.net/manual/fr/function.htmlentities.php) 150 | * [`htmlspecialchars()`](http://www.php.net/manual/fr/function.htmlspecialchars.php) 151 | * [PHP UTF-8 Cheatsheet](http://blog.loftdigital.com/blog/php-utf-8-cheatsheet)(en) 152 | * [Stack Overflow: What factors make PHP Unicode-incompatible?](http://stackoverflow.com/questions/571694/what-factors-make-php-unicode-incompatible)(en) 153 | * [Stack Overflow: Best practices in PHP and MySQL with international strings](http://stackoverflow.com/questions/140728/best-practices-in-php-and-mysql-with-international-strings)(en) 154 | * [How to support full Unicode in MySQL databases](http://mathiasbynens.be/notes/mysql-utf8mb4)(en) 155 | * [Bringing Unicode to PHP with Portable UTF-8](http://www.sitepoint.com/bringing-unicode-to-php-with-portable-utf8/)(en) 156 | -------------------------------------------------------------------------------- /_posts/06-01-01-Dependency-Injection.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Injection de dépendance 3 | anchor: dependency_injection 4 | --- 5 | 6 | # Injection de dépendance {#dependency_injection_title} 7 | 8 | De [Wikipedia](http://fr.wikipedia.org/wiki/Injection_de_d%C3%A9pendances): 9 | 10 | > L'injection de dépendances est un mécanisme qui permet d'implanter le principe de l'inversion de contrôle. 11 | > Il consiste à créer dynamiquement (injecter) les dépendances entre les différentes classes en s'appuyant 12 | > sur une description (fichier de configuration ou métadonnées) ou de manière programmatique. 13 | > Ainsi les dépendances entre composants logiciels ne sont plus exprimées dans le code de manière statique 14 | > mais déterminées dynamiquement à l'exécution. 15 | 16 | Cette citation rend le concept plus compliqué qu'il n'y paraît. L'injection de dépendances fournit un composant avec 17 | ses dépendances que ce soit via un constructeur, des appels de méthodes ou la configuration de propriétés. C'est tout. 18 | -------------------------------------------------------------------------------- /_posts/06-02-01-Basic-Concept.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Concepts de base 3 | isChild: true 4 | anchor: basic_concept 5 | --- 6 | 7 | ## Concepts de base {#basic_concept_title} 8 | 9 | Nous pouvons démontrer le concept avec un exemple tout bête. 10 | 11 | Imaginons que nous ayons une classe `Database` qui exige un adaptateur (_adapter_ en anglais) pour communiquer avec la 12 | base de données. Nous instantions l'adaptateur à l'intérieur du constructeur et créons une dépendance forte. Cela 13 | rend les tests compliqués étant donné que la classe `Database` est fortement couplée à l'adaptateur. 14 | 15 | {% highlight php %} 16 | adapter = new MySqlAdapter; 26 | } 27 | } 28 | 29 | class MysqlAdapter {} 30 | {% endhighlight %} 31 | 32 | Ce code peut être refactorisé pour utiliser l'injection de dépendances et ainsi séparer l'adaptateur de la classe. 33 | 34 | {% highlight php %} 35 | adapter = $adapter; 45 | } 46 | } 47 | 48 | class MysqlAdapter {} 49 | {% endhighlight %} 50 | 51 | Maintenant nous fournissons à la classe `Database` les dépendances nécessaires en argument au lieu de les créer nous-mêmes. 52 | Nous pouvons même créer une méthode qui accepterait les paramètres des dépendances afin de les fixer nous-mêmes, 53 | ou si la propriété `$adapter` était `public`, nous pourrions la définir directement. 54 | -------------------------------------------------------------------------------- /_posts/06-03-01-Complex-Problem.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Problèmes complexes 3 | isChild: true 4 | anchor: complex_problem 5 | --- 6 | 7 | ## Problèmes complexes {#complex_problem_title} 8 | 9 | Si vous avez déjà lu des articles sur l'injection de dépendances alors vous avez probablement vu des termes comme 10 | *"Inversion de contrôle"* ou *"Principe d'inversion de dépendances"*. Ces termes sont les problèmes complexes que 11 | l'injection de dépendances cherche à résoudre. 12 | 13 | ### Inversion de contrôle 14 | 15 | L'inversion de contrôle est, comme il le sous-entend, un système cherchant à "inverser le contrôle" en gardant le contrôle 16 | organisationnel entièrement séparé des objets. En terme d'injection de dépendances, cela signifie que l'on sépare les 17 | dépendances en les contrôlant et en les instanciant ailleurs dans le système. 18 | 19 | Pendant des années, les frameworks PHP ont fait de l'inversion de contrôle, cependant la question est devenue : quelle 20 | partie du contrôle doit-on inverser ? Et vers où ? Par exemple, les frameworks MVC fourniront généralement un super-objet 21 | ou un contrôleur de base dont les autres contrôleurs doivent hériter pour avoir accès à ses dépendances. C'est 22 | **ça** l'inversion de contrôle, cependant au lieu de séparer les différentes dépendances, cette méthode ne fait que les 23 | déplacer. 24 | 25 | L'injection de dépendances nous permet de résoudre ce problème de façon plus élégante en injectant uniquement les dépendances 26 | dont nous avons besoin, quand nous avons besoin et ce sans avoir à écrire en dur quelque dépendance que ce soit. 27 | 28 | ### Principe d'inversion des dépendances 29 | 30 | Le principe d'inversion des dépendances (en anglais _Dependency Inversion Principle_) correspond au "D" dans "S.O.L.I.D." 31 | qui est un ensemble de principes et de conceptions orientés objet. Il est dit que l'on doit *"dépendre des abstactions et 32 | non des implémentations."*. Cela signifie que nos dépendances doivent se faire sur des interfaces/contrats ou encore sur 33 | des classes abstraites plutôt que sur des classes "concrètes". Nous pouvons facilement refactoriser l'exemple ci-dessus 34 | en suivant ce principe. 35 | 36 | {% highlight php %} 37 | adapter = $adapter; 47 | } 48 | } 49 | 50 | interface AdapterInterface {} 51 | 52 | class MysqlAdapter implements AdapterInterface {} 53 | {% endhighlight %} 54 | 55 | Il y a plusieurs avantages à ce que la classe `Database` dépende d'une interface plutôt que de son implémentation. 56 | 57 | Imaginons que vous êtes en train de travailler dans une équipe et que l'adaptateur est écrit par un de vos collègues. 58 | Dans notre premier exemple, nous aurions d'abord attendu que notre collègue ait fini l'adaptateur avant de pouvoir 59 | l'utiliser dans nos tests unitaires. Maintenant que la dépendance correspond à une interface, nous pouvons créer un 60 | objet factice implémentant cette interface en sachant que notre collègue constuira l'adaptateur en respectant le contrat 61 | de base. 62 | 63 | Un bénéfice encore plus grand de cette méthode est que notre code est maintenant plus facilement évolutif (_scalable_ en anglais). 64 | Si dans un an nous décidons que nous voulons migrer sur un autre type de base de données alors nous n'avons qu'à écrire et 65 | utiliser l'adaptateur qui implémente l'interface spécifique et ainsi, nous n'avons plus besoin de refactoriser du code. 66 | -------------------------------------------------------------------------------- /_posts/06-04-01-Containers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Conteneurs 3 | isChild: true 4 | anchor: containers 5 | --- 6 | 7 | ## Conteneurs {#containers_title} 8 | 9 | La première chose que vous devriez comprendre sur les conteneurs d'injection de dépendances est qu'il ne s'agit pas de 10 | la même chose que l'injection de dépendances. Un conteneur est un moyen pratique d'implémenter l'injection de dépendances, 11 | cependant ils peuvent être souvent mal utilisés et devenir un anti-pattern. Injecter un composant ID en tant que 12 | localisateur de services à l'intérieur de vos classes crée sans aucun doute une dépendance plus forte que la dépendance 13 | que vous remplacez. Cela rend aussi votre code moins transparent et finalement plus dur à tester. 14 | 15 | La plupart des frameworks modernes ont leur propre conteneur d'injection de dépendances qui permettent de brancher 16 | vos dépendances ensemble à travers un fichier de configuration. Cela signifie en pratique que vous écrivez du code métier 17 | aussi propre et découplé que le framework sur lequel vous vous basez. 18 | -------------------------------------------------------------------------------- /_posts/06-05-01-Further-Reading.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Lecture approfondie 3 | isChild: true 4 | anchor: dependency_injection_further_reading 5 | --- 6 | 7 | ## Lecture approfondie {#dependency_injection_further_reading_title} 8 | 9 | Attention, les liens qui suivent sont tous en anglais : 10 | 11 | - [En apprendre plus sur l'injection de dépendances et PHP](http://ralphschindler.com/2011/05/18/learning-about-dependency-injection-and-php) 12 | - [Qu'est-ce que l'injection de dépendances ?](http://fabien.potencier.org/article/11/what-is-dependency-injection) 13 | - [Injection de dépendances : une analogie](http://mwop.net/blog/260-Dependency-Injection-An-analogy.html) 14 | - [Injection de dépendances : Hein?](http://net.tutsplus.com/tutorials/php/dependency-injection-huh/) 15 | - [Injection de dépendances en tant qu'outil de test](http://www.happyaccidents.me/dependency-injection-as-a-tool-for-testing/) 16 | -------------------------------------------------------------------------------- /_posts/07-01-01-Databases.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bases de données 3 | anchor: databases 4 | --- 5 | 6 | # Bases de données {#databases_title} 7 | 8 | Votre code PHP va souvent faire appel aux bases de données pour préserver l'information. Vous avez un certain nombre 9 | d'options pour vous connecter et interagir avec votre base de données. L'option recommandée _avant PHP 5.1.0_ était 10 | d'utiliser les pilotes natifs tels que [mysql][mysql], [mysqli][mysqli], [pgsql][pgsql], etc. 11 | 12 | Les pilotes natifs sont géniaux si vous n'utilisez qu'un seul type de base de données dans votre application mais si, 13 | par exemple, vous utilisez MySQL et un peu de MSSQL, ou vous avez besoin de vous connecter à une base Oracle alors vous 14 | ne pourrez pas utiliser les mêmes pilotes. Vous aurez besoin d'apprendre une nouvelle API pour chaque type de BDD — ce 15 | qui peut devenir lourd. 16 | 17 | [mysql]: http://php.net/mysql 18 | [mysqli]: http://php.net/mysqli 19 | [pgsql]: http://php.net/pgsql 20 | -------------------------------------------------------------------------------- /_posts/07-02-01-Databases_MySQL.md: -------------------------------------------------------------------------------- 1 | --- 2 | isChild: true 3 | title: Extension MySQL 4 | anchor: mysql_extension 5 | --- 6 | 7 | ## Extension MySQL {#mysql_extension_title} 8 | 9 | L'extension [mysql] pour PHP est aujourd'hui au point mort et est [officiellement dépréciée depuis PHP 5.5.0](http://php.net/manual/fr/migration55.deprecated.php) ce qui 10 | signifie qu'elle sera retirée dans les prochaines versions. Si vous utilisez n'importe quelle fonction commençant par 11 | `mysql_*` (comme `mysql_connect()`) dans votre application alors cela donnera des erreurs dans votre code. Vous serez 12 | donc obligé de faire la transition vers [mysqli] ou [PDO]. 13 | 14 | **Si vous venez de commencer votre projet alors n'utilisez surtout pas l'extension [mysql] mais préférez [mysqli] ou PDO** 15 | 16 | * [PHP: Choisir une API pour MySQL](http://php.net/manual/fr/mysqlinfo.api.choosing.php) 17 | * [Tutoriel sur PDO pour les développeurs MySQL](http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers) 18 | 19 | [PDO]: http://php.net/pdo 20 | [mysql]: http://php.net/mysql 21 | [mysqli]: http://php.net/mysqli 22 | -------------------------------------------------------------------------------- /_posts/07-03-01-Databases_PDO.md: -------------------------------------------------------------------------------- 1 | --- 2 | isChild: true 3 | title: Extension PDO 4 | anchor: pdo_extension 5 | --- 6 | 7 | ## Extension PDO {#pdo_extension_title} 8 | 9 | PDO est une couche d'abstraction pour se connecter à une base de données — intégrée à PHP depuis la version 5.1.0 — 10 | qui fournit une interface commune pour communiquer avec différentes bases de données. PDO ne va pas traduire vos requêtes 11 | SQL ou émuler les fonctionnalités manquantes; il ne gère que la connexion entre différents types de bases de données avec 12 | la même API. 13 | 14 | Plus important encore, PDO vous permet d'injecter en toute sécurité des entrées étrangères (par ex., les identifiants) 15 | dans vos requêtes SQL sans que vous ayez à vous soucier des attaques par injection SQL. Cela est rendu possible grâce à 16 | l'utilisation des fonctions de PDO et des paramètres liés. 17 | 18 | Supposons qu'un script PHP reçoit un identifiant numérique en tant que paramètre d'entrée. Cet ID devrait être utilisé 19 | pour récupérer les enregistrements d'un utilisateur dans la base de données. Voici la mauvaise façon de s'y prendre : 20 | 21 | {% highlight php %} 22 | query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NON! 25 | {% endhighlight %} 26 | 27 | Ce code est mauvais. Vous insérez un paramètre en brut directement dans une requête SQL. C'est la porte ouverte pour 28 | le piratage comme [l'injection SQL](http://wiki.hashphp.org/Validation). Imaginez un instant que si un pirate envoie un paramètre `id` en invoquant l'URL 29 | `http://domain.com/?id=1%3BDELETE+FROM+users`. Cela va définir la variable `$_GET['id']` à `1;DELETE FROM users` ce qui 30 | va effacer l'ensemble de vos utilisateurs ! Au lieu de faire ça, vous devriez nettoyer les entrées en utilisant la liaison 31 | des paramètres avec PDO. 32 | 33 | {% highlight php %} 34 | prepare('SELECT name FROM users WHERE id = :id'); 37 | $stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); // <-- Nettoyé automatiquement par PDO 38 | $stmt->execute(); 39 | {% endhighlight %} 40 | 41 | Voici le code correct. Il utilise un paramètre lié à une expression PDO. Cela "échappe" les entrées étrangères avant 42 | qu'elles ne soient introduites dans la base de données, ce qui empêche les attaques potentielles par injection SQL. 43 | 44 | * [En savoir plus sur PDO][1] 45 | 46 | Vous devriez savoir que les connexions à la base de données utilisent pas mal de ressources et il arrivait souvent 47 | que les ressources finissaient par tarir si les connexions n'étaient pas implicitement fermées. Cependant c'était plus 48 | souvent le cas dans les autres langages. En utilisant PDO, vous pouvez implicitement fermer la connexion en détruisant 49 | l'objet et en s'assurant que toutes les références à cet objet ont été supprimées, c'est-à-dire, mises à NULL. Si vous 50 | ne le faites pas explicitement, PHP va automatiquement fermer la connexion quand votre script s'arrêtera - à moins bien 51 | sûr que vous n'utilisiez une connexion persistante. 52 | 53 | * [En savoir plus sur les connexions avec PDO][5] 54 | 55 | ## Couches d'abstractions 56 | 57 | Beaucoup de frameworks fournissent leur propre couche d'abstraction qui peut être ou non basée sur PDO. Cette couche va 58 | souvent émuler les fonctionnalités d'une base de données qui seraient manquantes dans une autre base en enveloppant 59 | vos requêtes dans des méthodes PHP vous donnant ainsi une réelle abstraction avec la base de données. 60 | Cela engendre évidemment un léger surplus mais si vous voulez développer une application portable ayant besoin de 61 | communiquer avec MySQL, PostgreSQL et SQLite alors ce petit surplus en vaudra la peine par souci de propreté et de 62 | maintenance du code. 63 | 64 | Plusieurs couches d'abstractions ont été construites en utilisant les standards d'espace de noms [PSR-0][psr0] ou 65 | [PSR-4][psr4]; elles peuvent donc être installées dans n'importe quelle application qui vous plaira : 66 | 67 | * [Aura SQL][6] 68 | * [Doctrine2 DBAL][2] 69 | * [Propel][7] 70 | * [ZF2 Db][4] 71 | * [ZF1 Db][3] 72 | 73 | [1]: http://www.php.net/manual/fr/book.pdo.php 74 | [2]: http://www.doctrine-project.org/projects/dbal.html 75 | [3]: http://framework.zend.com/manual/fr/zend.db.html 76 | [4]: http://packages.zendframework.com/docs/latest/manual/fr/index.html#zend-db 77 | [5]: http://php.net/manual/fr/pdo.connections.php 78 | [6]: https://github.com/auraphp/Aura.Sql 79 | [7]: http://propelorm.org/Propel/ 80 | 81 | [psr0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md 82 | [psr4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md 83 | -------------------------------------------------------------------------------- /_posts/07-04-01-Interacting-via-Code.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Interagir avec les bases de données 3 | isChild: true 4 | anchor: interacting_via_code 5 | --- 6 | 7 | ## Interagir avec les bases de données {#interacting_via_code_title} 8 | 9 | Quand les développeurs commencent à utiliser PHP, ils finissent souvent par mélanger le code métier avec celui gérant 10 | la base de données et l'affichage, ce qui donne quelque chose de ce genre : 11 | 12 | {% highlight php %} 13 | 19 | {% endhighlight %} 20 | 21 | Ceci est une mauvaise pratique pour toutes sortes de raisons, principalement dû au fait que le code est plus difficile à 22 | déboguer et à lire et qu'il est plus difficile de réaliser des tests. 23 | 24 | Bien qu'il existe un certain nombre de solutions pour parer à ce problème comme l'utilisation de la [POO](#programmation_oriente_objet) 25 | ou bien la [programmation fonctionnelle](#programmation_fonctionnelle), les parties logiques de votre code doivent être 26 | clairement délimitées. 27 | 28 | Considérez l'exemple suivant : 29 | 30 | {% highlight php %} 31 | query('SELECT * FROM table'); 34 | } 35 | 36 | foreach (getAllFoos() as $row) { 37 | echo "
  • ".$row['field1']." - ".$row['field1']."
  • "; // MAUVAIS!! 38 | } 39 | {% endhighlight %} 40 | 41 | C'est un bon début. La séparation entre l'interaction avec la base de données et l'affichage est déjà bien distincte. 42 | 43 | Créez une classe où vous placerez les méthodes de votre code métier (votre "modèle"). Puis créez un fichier `.php` 44 | qui contient la logique d'affichage (votre "vue") ce qui revient grosso-modo à utiliser le pattern [MVC] - un modèle 45 | d'architecture très courant dans la plupart des [frameworks](#frameworks_title). 46 | 47 | **foo.php** 48 | 49 | {% highlight php %} 50 | db = $db; 76 | } 77 | 78 | public function getAllFoos() { 79 | return $this->db->query('SELECT * FROM table'); 80 | } 81 | } 82 | {% endhighlight %} 83 | 84 | **views/foo-list.php** 85 | 86 | {% highlight php %} 87 | 88 | - 89 | 90 | {% endhighlight %} 91 | 92 | C'est l'essentiel de ce que font les frameworks de façon plus manuelle. Vous n'avez pas forcément besoin de l'utiliser 93 | constamment mais mélanger la présentation et la logique métier peut être un réel casse-tête si vous devez ensuite 94 | utiliser les [tests unitaires](/#unit-testing) dans votre application. 95 | 96 | [PHPBridge] contient un excellent tutoriel appellé [Creating a Data Class] qui couvre un sujet similaire à celui-ci et 97 | permet de bien s'imprégner du concept d'interaction avec les bases de données. 98 | 99 | [MVC]: http://code.tutsplus.com/tutorials/mvc-for-noobs--net-10488 (en) 100 | [PHPBridge]: http://phpbridge.org/ (en) 101 | [Creating a Data Class]: http://phpbridge.org/intro-to-php/creating_a_data_class (en) 102 | -------------------------------------------------------------------------------- /_posts/07-05-01-Abstraction-Layers.md: -------------------------------------------------------------------------------- 1 | --- 2 | isChild: true 3 | title: Couches d'abstraction 4 | anchor: databases_abstraction_layers 5 | --- 6 | 7 | ## Couches d'abstraction {#databases_abstraction_layers_title} 8 | 9 | Pratiquement tous les frameworks contiennent leurs propres couches d'abstraction qui peut ou non se baser sur [PDO][1]. Il simule la plupart du temps les caractéristiques manquantes d'un système à l'autre en englobant vos requêtes dans des méthodes PHP vous donnant une réelle abstraction des données contrairement à PDO qui ne vous fournit que la partie connexion. 10 | Cela rajoute évidemment une surcouche mais si vous devez construire une application portable qui nécessite de travailler à la fois avec MySQL, PostgreSQL et/ou SQLite alors ce petit surplus ne sera pas de trop afin d'avoir un code plus maintenable. 11 | 12 | Certains couches d'abstraction ont été construites en utilisant la norme [PSR-0][psr0] ou [PSR-4][psr4] afin d'être utilisable par n'importe quelle application: 13 | 14 | * [Aura SQL][6] 15 | * [Doctrine2 DBAL][2] 16 | * [Propel][7] 17 | * [Zend-db][4] 18 | 19 | 20 | [1]: http://php.net/book.pdo 21 | [2]: http://www.doctrine-project.org/projects/dbal.html 22 | [4]: https://packages.zendframework.com/docs/latest/manual/en/index.html#zendframework/zend-db 23 | [6]: https://github.com/auraphp/Aura.Sql 24 | [7]: http://propelorm.org/ 25 | [psr0]: http://www.php-fig.org/psr/psr-0/ 26 | [psr4]: http://www.php-fig.org/psr/psr-4/ 27 | -------------------------------------------------------------------------------- /_posts/08-01-01-Templating.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Templating 3 | anchor: templating 4 | --- 5 | 6 | # Templating {#templating_title} 7 | 8 | Les templates fournissent un moyen pratique de séparer les différentes préoccupations (contrôleur, logique, présentation). 9 | Les templates contiennent typiquement l'HTML de votre application mais ils peuvent aussi être utilisés avec d'autres 10 | formats comme l'XML. Les templates sont souvent classés dans la catégorie "vues", le second composant du pattern [MVC](pages/Design-Patterns.html#modlevuecontrleur). 11 | -------------------------------------------------------------------------------- /_posts/08-02-01-Benefits.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bénéfices 3 | isChild: true 4 | anchor: templating_benefits 5 | --- 6 | 7 | ## Bénéfices {#templating_benefits_title} 8 | 9 | L'intérêt principal d'utiliser les templates tient dans la séparation nette qui se créée entre la logique de présentation 10 | et le reste de l'application. Les templates sont seuls responsables de l'affichage du contenu formaté. Ils ne sont pas 11 | responsables de la récupération des données, ni de la persistance ou d'autres tâches complexes. Cela conduit à du code 12 | plus propre et plus lisible, ce qui est particulièrement utile lorsque l'on travaille en équipe où l'on peut trouver 13 | à la fois des développeurs côté serveur (responsables de la partie "contrôleurs, modèles") et les designers qui, eux, 14 | travaillent sur le code côté client. 15 | 16 | Les templates améliorent aussi l'organisation du code pour l'affichage. Ils sont généralement placés dans un répertoire 17 | "views", chacun étant défini dans un seul fichier. Cette approche encourage la réutilisation de code où de larges blocs 18 | de code sont découpés de façon à obtenir un ensemble de briques "atomiques" et utilisables plus facilement. Par exemple, 19 | l'en-tête et le pied de page de votre site peuvent être définis dans des templates qui seront par la suite inclus 20 | respectivement au début et à la fin de chaque template d'une page. 21 | 22 | Finalement, selon la bibliothèque que vous utilisez, les templates peuvent vous offrir plus de sécurité en échappant 23 | par exemple automatiquement les variables définis par les entrées d'un utilisateur. Quelques bibliothèques vous offrent 24 | même la possibilité d'isoler les variables et les fonctions (on parlera de _sandboxing_) définis dans une liste blanche 25 | de façon, par exemple, à limiter les dégats collatéraux provoqués par une mauvaise utilisation faites par les designers. 26 | -------------------------------------------------------------------------------- /_posts/08-03-01-Plain-PHP-Templates.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Templates en PHP pur 3 | isChild: true 4 | anchor: plain_php_templates 5 | --- 6 | 7 | ## Templates en PHP "pur" {#plain_php_templates_title} 8 | 9 | Les templates "pur" PHP sont ceux qui n'utilisent que du code PHP natif. C'est un choix naturel étant donné que PHP est 10 | lui-même un language de templating. Ce terme signifie tout simplement que vous pouvez combiner du code PHP avec un autre 11 | langage comme l'HTML. Cela peut être considéré comme un atout du fait même que les développeurs n'ont pas à apprendre 12 | une syntaxe particulière. Par ailleurs, ces templates tendent à être plus rapides étant donné qu'il n'y a pas de phase de 13 | compilation. 14 | 15 | Tous les frameworks PHP modernes utilisent un système de templating, la plupart se basant uniquement sur la syntaxe PHP. 16 | En dehors des frameworks, des bibliothèques comme [Plates](http://platesphp.com/) ou [Aura.View](https://github.com/auraphp/Aura.View) 17 | rendent le travail avec les templates en PHP "pur" plus facile en offrant des fonctionnalités "modernes" telles que 18 | l'héritage, le layout et des extensions. 19 | 20 | Exemple d'un template en PHP "pur" (utilisant [Plates](http://platesphp.com/)): 21 | 22 | {% highlight php %} 23 | insert('header', ['title' => 'Profil utilisateur']) ?> 24 | 25 |

    Profil utilisateur

    26 |

    Bonjour, escape($name)?>

    27 | 28 | insert('footer') ?> 29 | {% endhighlight %} 30 | -------------------------------------------------------------------------------- /_posts/08-04-01-Compiled-Templates.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Templates compilés 3 | isChild: true 4 | anchor: compiled_templates 5 | --- 6 | 7 | ## Templates compilés {#compiled_templates_title} 8 | 9 | Bien que le PHP ait évolué en un langage orienté objet mature, il ne s'est 10 | [pas énormément amélioré](http://fabien.potencier.org/article/34/templating-engines-in-php) en tant que langage de 11 | templating. Les templates compilés comme [Twig](http://twig.sensiolabs.org/) ou [Smarty](http://www.smarty.net/) 12 | remplissent ce vide en offrant une nouvelle syntaxe, adaptée aux exigences des applications modernes. Cela va de 13 | l'échappement automatique à l'héritage en passant par des structures de contrôles simplifiées. Ces templates ont été 14 | conçus dans l'idée de faciliter l'écriture, la sécurité et la maintenance du code gérant la partie visuelle de l'application. 15 | Les templates compilés peuvent même être partagés entre différents langages, [Mustache](http://mustache.github.io/) étant 16 | un bon exemple de cela. Étant donné que ces templates doivent être compilés, il y a une légère baisse de performances. 17 | Cependant, cela peut être anecdotique si un système de cache approprié est utilisé. 18 | 19 | Exemple d'un template compilé (utilisant [Twig](http://twig.sensiolabs.org/)): 20 | 21 | {% highlight text %} 22 | {% raw %} 23 | {% include 'header.html' with {'title': 'Profil utilisateur'} %} 24 | 25 |

    Profil utilisateur

    26 |

    Bonjour, {{ name }}

    27 | 28 | {% include 'footer.html' %} 29 | {% endraw %} 30 | {% endhighlight %} 31 | -------------------------------------------------------------------------------- /_posts/08-05-01-Further-Reading.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Aller plus loin 3 | isChild: true 4 | anchor: templating_further_reading 5 | --- 6 | 7 | ## Aller plus loin {#templating_further_reading_title} 8 | 9 | ### Articles & Tutoriels 10 | 11 | - [Templating Engines in PHP](http://fabien.potencier.org/article/34/templating-engines-in-php) 12 | - [An Introduction to Views & Templating in CodeIgniter](http://code.tutsplus.com/tutorials/an-introduction-to-views-templating-in-codeigniter--net-25648) 13 | - [Getting Started With PHP Templating](http://www.smashingmagazine.com/2011/10/17/getting-started-with-php-templating/) 14 | - [Roll Your Own Templating System in PHP](http://code.tutsplus.com/tutorials/roll-your-own-templating-system-in-php--net-16596) 15 | - [Master Pages](https://laracasts.com/series/laravel-from-scratch/episodes/7) 16 | - [Working With Templates in Symfony 2](http://code.tutsplus.com/tutorials/working-with-templates-in-symfony-2--cms-21172) 17 | 18 | ### Bibliothèques 19 | 20 | - [Aura.View](https://github.com/auraphp/Aura.View) *(native)* 21 | - [Blade](http://laravel.com/docs/templates) *(compilée, spécifique au framework)* 22 | - [Dwoo](http://dwoo.org/) *(compilée)* 23 | - [Latte](https://github.com/nette/latte) *(compilée)* 24 | - [Mustache](https://github.com/bobthecow/mustache.php) *(compilée)* 25 | - [PHPTAL](http://phptal.org/) *(compilée)* 26 | - [Plates](http://platesphp.com/) *(native)* 27 | - [Smarty](http://www.smarty.net/) *(compilée)* 28 | - [Twig](http://twig.sensiolabs.org/) *(compilée)* 29 | - [Zend\View](http://framework.zend.com/manual/2.3/en/modules/zend.view.quick-start.html) *(native, spécifique au framework)* 30 | -------------------------------------------------------------------------------- /_posts/09-01-01-Errors-and-Exceptions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Les erreurs et exceptions 3 | anchor: errors_and_exceptions 4 | --- 5 | 6 | # Les erreurs et exceptions {#errors_and_exceptions_title} 7 | -------------------------------------------------------------------------------- /_posts/09-02-01-Errors.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Erreurs 3 | isChild: true 4 | anchor: errors 5 | --- 6 | 7 | ## Erreurs {#errors_title} 8 | 9 | Le PHP a plusieurs niveaux de gravité pour les erreurs. Les 3 types de messages d'erreurs les plus communs sont les 10 | erreurs, les avertissements et les remarques. Il existe différents niveaux de gravité; 11 | `E_ERROR`, `E_WARNING` et `E_NOTICE`. Les erreurs sont des erreurs d'exécution fatales et sont souvent causées par 12 | des bogues qui ont besoin d'être réglés étant donné qu'ils stoppent l'interprétation du reste du code. Les 13 | avertissements sont des erreurs non fatales, autrement dit l'exécution du script continuera. Les remarques sont des 14 | messages informatifs sur du code qui pourrait poser problème lors de l'exécution du script, cependant l'exécution ne 15 | sera pas arrêtée. 16 | 17 | Il existe un autre type de message d'erreur qui se présente lors de la phase de compilation; c'est le message `E_STRICT`. 18 | Ces messages sont utilisés pour suggérer des changements dans votre code afin de s'assurer de la meilleure 19 | interopérabilité et de la meilleure compatibilité ascendante possible. 20 | 21 | * [Constantes prédéfinies pour la gestion des erreurs](http://www.php.net/manual/fr/errorfunc.constants.php) 22 | -------------------------------------------------------------------------------- /_posts/09-03-01-Exceptions.md: -------------------------------------------------------------------------------- 1 | --- 2 | isChild: true 3 | anchor: exceptions 4 | --- 5 | 6 | ## Exceptions {#exceptions_title} 7 | 8 | Les exceptions sont une partie standardisée dans la plupart des langages de programmation populaire mais elles sont 9 | souvent négligées par les programmeurs PHP. Les langages comme Ruby sont très fortement équipés pour gérer les exceptions. 10 | Ainsi, à chaque fois qu'une chose se passe mal comme l'échec d'une requête HTTP ou d'une requête à la BDD, Ruby (ou les 11 | "gems" utilisées) va lancer une exception à l'écran vous indiquant immédiatement qu'il y a eu une erreur. 12 | 13 | Le PHP en lui-même est plutôt laxiste avec ce type d'erreur, ainsi un appel à `file_get_contents()` va généralement 14 | renvoyer un `FALSE` accompagné d'un avertissement. Beaucoup d'anciens frameworks PHP comme CodeIgniter vont juste 15 | retourner `false`, enregistrer un message dans leur fichier de log et peut-être vous laisser utiliser une méthode 16 | comme `$this->upload->get_error()` pour voir ce qu'il s'est mal passé. Le problème ici est que vous devez vous-même 17 | chercher l'erreur et vérifier dans la doc ce qu'elle signifie pour cette fonction au lieu de l'avoir rendu évidente à 18 | comprendre. 19 | 20 | L'autre problème arrive lorsque les classes lancent automatiquement une erreur à l'écran et terminent le processus. Si 21 | vous faites cela, un autre développeur ne sera plus capable de gérer cette erreur à l'exécution. Les exceptions 22 | devraient être lancées afin d'avertir le développeur qu'une chose ne s'est pas passée comme prévu; ça devrait être à eux 23 | de décider comment ils veulent gérer cela, par exemple: 24 | 25 | {% highlight php %} 26 | subject('Mon sujet'); 29 | $email->body('Comment allez-vous ?'); 30 | $email->to('guy@exemple.com', 'Un gars'); 31 | 32 | try 33 | { 34 | $email->send(); 35 | } 36 | catch(Fuel\Email\ValidationFailedException $e) 37 | { 38 | // La validation a échoué 39 | } 40 | catch(Fuel\Email\SendingFailedException $e) 41 | { 42 | // Le pilote ne peut pas envoyé l'email 43 | } 44 | finally 45 | { 46 | // ce bloc est exécuté même si une exception a été levée et avant que l'exécution normale reprenne 47 | } 48 | {% endhighlight %} 49 | 50 | ### Les exceptions SPL 51 | 52 | La classe générique `Exception` ne fournit pas un contexte intéressant pour le déboguage. Pour remédier à cela, il est 53 | possible de créer une sous-classe du type générique `Exception` : 54 | 55 | {% highlight php %} 56 | beaucoup de classes personnalisées qui aurait pu être évitées si les exceptions de la SPL avaient 62 | été utilisées avec l'[extension SPL][splext]. 63 | 64 | Si par exemple vous utilisez la méthode magique `__call()` et qu'une méthode invalide est demandée alors, au lieu de lever 65 | une exception standard vague ou d'utiliser une sous-classe personnalisée, vous pourriez tout simplement faire 66 | `throw new BadFunctionCallException;`. 67 | 68 | * [En savoir plus sur les exceptions][exceptions] 69 | * [En savoir plus sur les exceptions de la SPL][splexe] 70 | * [Les exceptions imbriquées en PHP][nesting-exceptions-in-php] 71 | * [Les meilleurs pratiques de gestion d'exception en PHP 5.3][exception-best-practices53] 72 | 73 | [exceptions]: http://php.net/manual/fr/language.exceptions.php 74 | [splexe]: http://php.net/manual/fr/spl.exceptions.php 75 | [splext]: #bibliothèque_php_standard 76 | [exception-best-practices53]: http://ralphschindler.com/2010/09/15/exception-best-practices-in-php-5-3 77 | [nesting-exceptions-in-php]: http://www.brandonsavage.net/exceptional-php-nesting-exceptions-in-php/ 78 | -------------------------------------------------------------------------------- /_posts/10-01-01-Security.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sécurité 3 | anchor: security 4 | --- 5 | 6 | # Sécurité {#security_title} 7 | -------------------------------------------------------------------------------- /_posts/10-02-01-Web-Application-Security.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: La sécurité dans une application web 3 | isChild: true 4 | anchor: web_application_security 5 | --- 6 | 7 | ## La sécurité dans une application web {#web_application_security_title} 8 | 9 | De nombreuses personnes mal intentionnées tenteront d'exploiter les possibles failles dans votre application web. 10 | Il est important que vous ayez conscience de cela et que vous preniez les précautions nécessaires afin de renforcer 11 | la sécurité dans votre application. Heureusement, les gens du projet ["Open Web Application Security"][1] 12 | (OWASP en anglais) ont compilé une liste exhaustive des principaux problèmes de sécurité connus et les méthodes pour 13 | vous en prémunir. C'est une lecture indispensable pour tout développeur consciencieux de la sécurité. 14 | 15 | * [Lire le guide de sécurité OWASP][2] 16 | 17 | [1]: https://www.owasp.org/ 18 | [2]: https://www.owasp.org/index.php/Guide_Table_of_Contents 19 | -------------------------------------------------------------------------------- /_posts/10-03-01-Password-Hashing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hachage de mots de passe 3 | isChild: true 4 | anchor: password_hashing 5 | --- 6 | 7 | ## Hachage de mots de passe {#password_hashing_title} 8 | 9 | Pratiquement tout le monde construit une application PHP qui se base sur une authentification de l'utilisateur. Les 10 | identifiants et les mots de passe sont stockés dans une base de données et utilisés plus tard pour authentifier les 11 | utilisateurs. 12 | 13 | Il est important que vous utilisiez correctement les fonctions de [hachage][3] avant de les stocker. Le hachage de 14 | mots de passe est une opération irréversible produisant une chaîne de caractères de longueur fixe. Cela signifie que 15 | vous pouvez comparer le produit d'une fonction de hachage avec le hash stocké en base de données pour déterminer s'il 16 | s'agit du même texte. Si les mots de passe stockés en base de données ne sont pas "hachés" alors n'importe qui ayant 17 | accès à cette base peut compromettre les comptes utilisateurs. Il arrive souvent que les utilisateurs utilisent le 18 | même mot de passe pour d'autres services. C'est pourquoi il faut prendre la sécurité des informations avec sérieux. 19 | 20 | **Hachage de mot de passe avec `password_hash`** 21 | 22 | La fonction `password_hash` a été introduite avec la version 5.5 de PHP. À l'heure actuelle, elle utilise BCrypt qui est 23 | l'algorithme le plus robuste. Cela va être mis à jour dans le futur afin de supporter plus d'algorithmes. La 24 | bibliothèque `password_compat` a été créée afin de fournir une compatibilité ascendante avec PHP >= 5.3.7. 25 | 26 | Dans l'exemple ci-dessous, nous hachons une chaîne de caractères et faisons une vérification sur une chaîne différente. 27 | Étant donné que les 2 chaînes sont différentes ('secret-password' vs. 'bad-password'), l'authentification va échouer. 28 | 29 | {% highlight php %} 30 | = 5.3.7 && < 5.5] [2] 47 | * [En savoir plus sur les fonctions de hachage (cryptographie)] [3] 48 | * [PHP `password_hash` RFC] [4] 49 | 50 | [1]: http://us2.php.net/manual/fr/function.password-hash.php 51 | [2]: https://github.com/ircmaxell/password_compat 52 | [3]: http://fr.wikipedia.org/wiki/Fonction_de_hachage_cryptographique 53 | [4]: https://wiki.php.net/rfc/password_hash 54 | -------------------------------------------------------------------------------- /_posts/10-04-01-Data-Filtering.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Filtrage des données 3 | isChild: true 4 | anchor: data_filtering 5 | --- 6 | 7 | ## Filtrage des données {#data_filtering_title} 8 | 9 | Une règle d'or: ne jamais faire confiance aux entrées extérieures dans votre code PHP. Prenez toujours soin de 10 | "nettoyer" et valider ces entrées avant de les utiliser dans le code. Les fonctions `filter_var` et `filter_input` 11 | peuvent nettoyer les entrées textuelles et valider les données comme les emails. 12 | 13 | Les entrées étrangères viennent de n'importe où : les données de formulaire envoyées via `$_GET` ou `$_POST`, des valeurs 14 | dans la variable superglobale `$_SERVER` et le corps des requêtes HTTP via `fopen('php://input', 'r')`. N'oubliez pas, 15 | les entrées étrangères ne se limitent pas aux données envoyées par l'utilisateur. Les fichiers uploadés et téléchargés, 16 | les valeurs de session, les données des cookies et les données provenant de services tiers sont aussi des entrées 17 | étrangères. 18 | 19 | Demandez-vous à chaque fois que vous traitez, affichez, concaténez ou incluez des données dans votre code si ces données 20 | ont été correctement filtrées et qu'elles peuvent être considérées comme sûres. 21 | 22 | Les données peuvent être _filtrées_ différemment selon le contexte. Par exemple, quand des données brutes sont envoyées 23 | en sortie vers la page HTML, elles peuvent exécuter du Javascript et de l'HTML. Cette technique est connue sous le nom de 24 | "Cross-Site Scripting" (XSS) et peut se révéler très dangereuse. Une façon d'éviter les attaques XSS est de nettoyer 25 | toutes les données générées par l'utilisateur avant de les afficher sur votre page en retirant toutes balises HTML avec 26 | la fonction `strip_tags` ou en échappant les caractères spéciaux tels que '<' ou '>' avec les fonctions `htmlentities` ou 27 | `htmlspecialchars`. 28 | 29 | Un autre exemple est lorsque l'on passe des options à exécuter en ligne de commandes. Cela peut être très dangereux 30 | (et est souvent une mauvaise idée) mais vous pouvez utiliser la fonction `escapeshellarg` pour nettoyer les arguments 31 | d'une commande. 32 | 33 | Un dernier exemple concerne le fait d'autoriser les entrées étrangères pour déterminer le fichier à télécharger depuis 34 | le système de fichiers. Cela peut être exploité en changeant le chemin vers le fichier. Vous devez supprimer 35 | "/", "../", [les octets null][6] ou d'autres caractères du chemin de façon à empêcher le chargement de fichiers 36 | cachés, privés ou contenant des données sensibles. 37 | 38 | * [En savoir plus sur le filtrage des données][1] 39 | * [En savoir plus sur `filter_var`][4] 40 | * [En savoir plus sur `filter_input`][5] 41 | * [En savoir plus sur la gestion des octets null][6] 42 | 43 | ### Nettoyage 44 | 45 | Le "nettoyage" supprime (ou échappe) les caractères illégaux ou considérés comme dangereux. 46 | 47 | Par exemple, vous devriez nettoyer les entrées étrangères avant d'inclure les entrées en HTML ou de les insérer 48 | dans une requête SQL. Si vous utilisez les paramètres liés avec [PDO](#bases_de_données), il nettoyera les entrées pour 49 | vous. 50 | 51 | Parfois il est nécessaire d'autoriser certains tags HTML dans les entrées quand on les inclus dans la page HTML. Cela 52 | se révèle souvent très compliqué à mettre en oeuvre et beaucoup l'évite, c'est pourquoi il existe des syntaxes de 53 | formattage telles que Markdown or BBCode bien que des bibliothèques comme [HTML Purifier][html-purifier] vous permettent 54 | d'intégrer directement de l'HTML. 55 | 56 | [Voir les filtres de nettoyage][2] 57 | 58 | ### Validation 59 | 60 | La validation s'assure que les entrées extérieures correspondent à ce que vous vous attendiez. Par exemple, vous 61 | pourriez vouloir valider une adresse email, un numéro de téléphone ou un âge lors du traitement de l'enregistrement 62 | d'un compte. 63 | 64 | [Voir les filtres de validation][3] 65 | 66 | [1]: http://www.php.net/manual/fr/book.filter.php 67 | [2]: http://www.php.net/manual/fr/filter.filters.sanitize.php 68 | [3]: http://www.php.net/manual/fr/filter.filters.validate.php 69 | [4]: http://php.net/manual/fr/function.filter-var.php 70 | [5]: http://www.php.net/manual/fr/function.filter-input.php 71 | [6]: http://php.net/manual/fr/security.filesystem.nullbytes.php 72 | [html-purifier]: http://htmlpurifier.org/ 73 | -------------------------------------------------------------------------------- /_posts/10-05-01-Configuration-Files.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fichiers de configuration 3 | isChild: true 4 | anchor: configuration_files 5 | --- 6 | 7 | ## Fichiers de configuration {#configuration_files_title} 8 | 9 | Lorsque vous créez des fichiers de configuration pour vos applications, les meilleurs pratiques recommandent que 10 | les méthodes ci-dessous soient suivies : 11 | 12 | - Il est recommandé que vous stockiez vos informations de configuration là où aucun utilisateur non autorisé ne peut y 13 | accéder (via le système de fichiers). 14 | - Si vous devez stocker vos fichiers de configuration à la racine du projet, nommez les fichiers avec l'extension `.php`. 15 | Cela permet de s'assurer que même si le fichier est accédé directement il ne s'affichera pas en texte brut. 16 | - Les informations contenues dans les fichiers de configuration doivent être protégées correctement, que ce soit via le 17 | chiffrage et/ou via le système de permissions des utilisateurs/groupes du système de fichiers. 18 | -------------------------------------------------------------------------------- /_posts/10-06-01-Register-Globals.md: -------------------------------------------------------------------------------- 1 | --- 2 | isChild: true 3 | anchor: register_globals 4 | --- 5 | 6 | ## Register Globals {#register_globals_title} 7 | 8 | ** NOTE: ** Depuis la version 5.4.0 de PHP, le paramètre `register_globals` a été retiré et ne peut plus être utilisé. 9 | Les applications plus anciennes n'afficheront plus qu'un avertissement si ce paramètre est utilisé. 10 | 11 | Quand il est activé, le paramètre de configuration `register_globals` permet à plusieurs types de variables (cela inclus 12 | notamment les paramètres `$_POST`, `$_GET` and `$_REQUEST`) d'être accessibles partout dans votre application. Cela 13 | peut facilement conduire à des problèmes de sécurité étant donné que votre application ne peut de façon claire dire 14 | d'où proviennent les données. 15 | 16 | Par exemple: `$_GET['foo']` sera accessible via `$foo` ce qui peut écraser des variables non encore déclarées. Si vous 17 | utilisez PHP < 5.4.0 __assurez vous__ que ce paramètre est à __off__. 18 | 19 | * [Register_globals dans le manuel PHP](http://www.php.net/manual/fr/security.globals.php) 20 | -------------------------------------------------------------------------------- /_posts/10-07-01-Error-Reporting.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rapport des erreurs 3 | isChild: true 4 | anchor: error_reporting 5 | --- 6 | 7 | ## Rapport d'erreurs {#error_reporting_title} 8 | 9 | La journalisation des erreurs peut être utile pour repérer les points qui posent problème dans votre application mais 10 | cela permet aussi d'afficher des informations sur la structure de votre application au monde extérieur. Pour vous 11 | protéger efficacement contre ce genre de problèmes, vous avez besoin de configurer votre serveur différemment entre 12 | la version de développement et celle pour la production. 13 | 14 | ### Développement 15 | 16 | Pour afficher toutes les erreurs possible durant le dévelopement, configurez les paramètres suivants 17 | dans votre fichier `php.ini`: 18 | 19 | display_errors = On 20 | display_startup_errors = On 21 | error_reporting = -1 22 | log_errors = On 23 | 24 | > En passant la valeur `-1`, toutes les erreurs possibles seront affichées, même lors de l'ajout d'autres niveaux et 25 | > constantes dans les futures versions de PHP. La constante E_ALL fonctionne de la même façon depuis PHP 5.4. - 26 | > [php.net](http://php.net/manual/function.error-reporting.php) 27 | 28 | Le niveau d'erreur `E_STRICT` a été introduit avec PHP 5.3.0 et ne fait pas parti de `E_ALL`, cependant il est 29 | dorénavant inclu dans `E_ALL` depuis la 5.4.0. Pour pouvoir rapporter toutes les erreurs en 5.3, il est donc nécessaire 30 | d'utiliser soit `-1` ou `E_ALL | E_STRICT`. 31 | 32 | **Rapporter toutes les erreurs possibles par version PHP** 33 | 34 | * < 5.3 `-1` ou `E_ALL` 35 | *   5.3 `-1` ou `E_ALL | E_STRICT` 36 | * > 5.3 `-1` ou `E_ALL` 37 | 38 | ### Production 39 | 40 | Pour cacher l'affichage d'erreurs dans votre environnement de production, configurez votre fichier 41 | `php.ini` de cette façon: 42 | 43 | display_errors = Off 44 | display_startup_errors = Off 45 | error_reporting = E_ALL 46 | log_errors = On 47 | 48 | Avec ces paramètres, les erreurs seront toujours enregistrées dans les journaux d'erreurs de votre serveur web mais ne 49 | seront pas affichées à l'utilisateur. Pour plus d'informations sur ces paramètres, voir le manuel PHP: 50 | 51 | * [error_reporting](http://php.net/manual/errorfunc.configuration.php#ini.error-reporting) 52 | * [display_errors](http://php.net/manual/errorfunc.configuration.php#ini.display-errors) 53 | * [display_startup_errors](http://php.net/manual/errorfunc.configuration.php#ini.display-startup-errors) 54 | * [log_errors](http://php.net/manual/errorfunc.configuration.php#ini.log-errors) 55 | -------------------------------------------------------------------------------- /_posts/11-01-01-Testing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tests 3 | anchor: testing 4 | --- 5 | 6 | # Tests {#testing_title} 7 | 8 | Écrire des tests automatisés pour votre code PHP est considéré comme une très bonne pratique et permet de construire 9 | des applications plus robustes. Les tests automatisés sont un excellent outil pour s'assurer que votre application 10 | fonctionne toujours (lorsque vous faites des changements ou quand vous ajoutez de nouvelles fonctionnalités) et ne 11 | devraient pas être ignorés. 12 | 13 | Il existe différentes types d'outils de test (ou framework) disponibles pour PHP qui utilisent différentes approches - 14 | tous tentent d'éviter les tests manuels et le besoin d'un socle pour l'équipe chargée de faire l'assurance qualité (QA) 15 | , s'assurant ainsi que les récents changements ne viendront pas casser l'existant. 16 | -------------------------------------------------------------------------------- /_posts/11-02-01-Test-Driven-Development.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Développement dirigé par les tests 3 | isChild: true 4 | anchor: test_driven_development 5 | --- 6 | 7 | ## Développement dirigé par les tests (TDD) {#test_driven_development_title} 8 | 9 | Citation tirée de [Wikipedia](http://fr.wikipedia.org/wiki/Test_Driven_Development): 10 | 11 | > Le Test Driven Development (TDD) ou en français développement piloté par les tests est une technique de développement 12 | > de logiciel qui préconise d'écrire les tests unitaires avant d'écrire le code source d'un logiciel. 13 | 14 | Il existe différents types de test que vous pouvez faire sur votre application. 15 | 16 | ### Test unitaire 17 | 18 | Le test unitaire est une approche dans la programmation qui s'assure que les fonctions, les classes et les méthodes 19 | écrites fonctionnent comme prévu tout le long du cycle de développement. En vérifiant les valeurs en entrée et en sortie 20 | des différentes fonctions, vous vous assurez du bon fonctionnement de la logique interne. En utilisant l'injection de 21 | dépendances et en construisant des classes [mocks](http://fr.wikipedia.org/wiki/Mock_%28programmation_orient%C3%A9e_objet%29) 22 | et des classes [stubs](http://fr.wikipedia.org/wiki/Stub), vous pouvez vérifier que les dépendances sont correctement 23 | utilisées pour une meilleure couverture du code. 24 | 25 | Quand vous créez une classe ou une fonction, vous devriez aussi créer un test unitaire couvrant l'ensemble des états 26 | possibles. À un niveau très basique, vous devriez vous assurer que les changements effectués sur une fonction ou une 27 | classe ne modifieront pas le comportement attendu de l'application. La seule alternative pour les tests unitaires serait 28 | l'utilisation de la fonction `var_dump()` ce qui n'est pas viable que ce soit pour une petite ou une grande application. 29 | 30 | L'autre cas d'utilisation des tests unitaires est la contribution à la communauté open-source. Vous pouvez ainsi 31 | écrire un test montrant une fonctionnalité boguée puis la réparer en montrant cette fois qu'elle passe le test. Les 32 | patches auront plus de chances d'être acceptés de cette manière. Si vous travaillez sur un projet acceptant les 33 | "pull requests" alors vous devriez exiger un (ou plusieurs) test(s) avant chaque patch. 34 | 35 | [PHPUnit](http://phpunit.de) est le framework de test standard (de facto) pour écrire des tests unitaires pour des 36 | applications PHP mais il existe d'autres alternatives : 37 | 38 | * [atoum](https://github.com/atoum/atoum) 39 | * [Enhance PHP](https://github.com/Enhance-PHP/Enhance-PHP) 40 | * [PUnit](http://punit.smf.me.uk/) 41 | * [SimpleTest](http://simpletest.org) 42 | 43 | 44 | ### Test d'intégration 45 | 46 | Citation tirée de [Wikipedia](http://fr.wikipedia.org/wiki/Test_d%27int%C3%A9gration): 47 | 48 | > Un test d'intégration est un test qui se déroule dans une phase d'un projet informatique suivant les tests unitaires. 49 | > Il consiste, une fois que les développeurs ont chacun validé leurs développements ou leurs correctifs, 50 | > à regrouper leurs modifications ensemble dans le cadre d'une livraison. 51 | 52 | Beaucoup des outils utilisés pour les tests unitaires peuvent aussi l'être pour les tests d'intégration étant donné 53 | qu'ils partagent les mêmes principes. 54 | 55 | 56 | ### Test fonctionnel 57 | 58 | Les tests fonctionnels servent à vérifier que chaque fonction est correctement implémentée, c'est-à-dire conforme aux 59 | exigences et aux spécifications. On vérifie chaque fonction indépendamment les unes des autres, 60 | généralement en terme d'entrées/sorties. 61 | 62 | Une autre variante connue est le test d'acceptation qui lui vérifie que le produit répond aux attentes de l'utilisateur, 63 | c'est-à-dire qu'il est conforme aux besoins et au cahier des charges. On vérifie le produit dans son ensemble, 64 | généralement avec des scenarii réalistes d'utilisation. 65 | 66 | #### Outils pour les tests fonctionnels 67 | 68 | * [Selenium](http://seleniumhq.com) 69 | * [Mink](http://mink.behat.org) 70 | * [Codeception](http://codeception.com) est un framework de test complet incluant aussi des outils pour les tests d'acceptance 71 | * [Storyplayer](http://datasift.github.io/storyplayer) est un framework de test complet qui inclue un support pour 72 | créer et détruire des environnements de test à la demande 73 | -------------------------------------------------------------------------------- /_posts/11-03-01-Behavior-Driven-Development.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Behavior Driven Development 3 | isChild: true 4 | anchor: behavior_driven_development 5 | --- 6 | 7 | ## Behavior Driven Development {#behavior_driven_development_title} 8 | 9 | Il existe 2 types de développement orientés comportement (BDD en anglais) : SpecBDD et StoryBDD. SpecBDD se concentre sur les 10 | aspects techniques du code alors que StoryBDD lui se concentre sur la partie métier, les fonctionnalités apportées ou 11 | bien encore les interactions. Le PHP possède des frameworks pour ces types de BDD. 12 | 13 | Avec StoryBDD, vous écrivez des histoires "humainement" lisibles qui décrivent le comportement de votre application. 14 | Ces histoires peuvent ensuite être transformées en tests se lançant sur votre application. Le framework utilisé dans 15 | les applications PHP pour StoryBDD est Behat qui s'inspire de [Cucumber] pour Ruby et implémente 16 | le language Gherkin DSL pour décrire les fonctionnalités. 17 | 18 | Avec SpecBDD, vous écrivez des spécifications décrivant comment votre code devrait se comporter. Au lieu de tester 19 | une fonction ou une méthode, vous décrivez comment cette fonction ou méthode devrait s'exécuter. Pour atteindre ce but 20 | il existe un framework qui s'appelle PHPSpec. Ce framework s'inspire lui aussi d'un projet Ruby, 21 | [RSpec](http://rspec.info/). 22 | 23 | ### Liens sur le BDD 24 | 25 | * [Behat](http://behat.org/), le framework StoryBDD pour PHP, inspiré de [Cucumber]; 26 | * [PHPSpec](http://www.phpspec.net/), le framework SpecBDD pour PHP, inspiré de [RSpec](http://rspec.info/); 27 | * [Codeception](http://www.codeception.com) est un framework de test complet utilisant les principes du BDD. 28 | 29 | 30 | [Cucumber]: https://cucumber.io/ 31 | -------------------------------------------------------------------------------- /_posts/11-04-01-Complementary-Testing-Tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Outils de test complémentaire 3 | isChild: true 4 | anchor: complementary_testing_tools 5 | --- 6 | 7 | ## Outils de test complémentaire {#complementary_testing_tools_title} 8 | 9 | Hormis les tests unitaires et les frameworks orientés comportement, il y a aussi un certain nombre de frameworks 10 | génériques et de bibliothèque utilitaires selon l'approche désirée. 11 | 12 | ### Liens vers les outils 13 | 14 | * [Selenium](http://seleniumhq.org/) est un outil d'automatisation d'utilisation d'un navigateur web qui peut être 15 | [intégré à PHPUnit](http://phpunit.de/manual/current/en/selenium.html). 16 | * [Mockery](https://github.com/padraic/mockery) est un framework de 17 | [Mock](http://fr.wikipedia.org/wiki/Mock_%28programmation_orient%C3%A9e_objet%29) qui peut être intégré avec 18 | [PHPUnit](http://phpunit.de/) ou [PHPSpec](http://www.phpspec.net/). 19 | * [Prophecy](https://github.com/phpspec/prophecy) est un framework de Mock très puissant et flexible. Il est intégré à 20 | [PHPSpec](http://www.phpspec.net/) et peut être utilisé avec [PHPUnit](http://phpunit.de/). 21 | -------------------------------------------------------------------------------- /_posts/12-01-01-Servers-and-Deployment.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Les serveurs et le déploiement 3 | anchor: servers_and_deployment 4 | --- 5 | 6 | # Les serveurs et le déploiement {#servers_and_deployment_title} 7 | 8 | Les applications PHP peuvent être déployées et exécutées sur les serveurs de production de diverses manières. 9 | -------------------------------------------------------------------------------- /_posts/12-02-01-Platform-as-a-Service.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Platform as a Service (PaaS) 3 | isChild: true 4 | anchor: platform_as_a_service 5 | --- 6 | 7 | ## Platform as a Service (PaaS) {#platform_as_a_service_title} 8 | 9 | Les PaaS fournissent l'architecture système et réseaux nécessaires pour faire tourner une application PHP sur le web. 10 | Cela signifie qu'il n'y a pratiquement aucune configuration requise pour lancer des applications ou des frameworks PHP. 11 | 12 | Les PaaS sont devenues récemment une méthode populaire pour déployer, héberger et monter en puissance (notion de 13 | 'scalabilité') des applications PHP de toutes tailles. Vous pouvez trouver une liste de [fournisseurs de PaaS PHP](#fournisseurs_paas_pour_php) 14 | dans la [section ressources](#ressources). 15 | -------------------------------------------------------------------------------- /_posts/12-03-01-Virtual-or-Dedicated-Servers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Serveurs virtuels et dédiés 3 | isChild: true 4 | anchor: virtual_or_dedicated_servers 5 | --- 6 | 7 | ## Serveurs virtuels et dédiés {#virtual_or_dedicated_servers_title} 8 | 9 | Si vous vous sentez à l'aise avec l'administration des systèmes ou êtes intéressé pour en connaître plus sur ce domaine, 10 | les serveurs virtuels et dédiés vous donne un contrôle absolu sur l'environement de production de votre application. 11 | 12 | ### nginx et PHP-FPM 13 | 14 | PHP via le gestionnaire de processus intégré FastCGI (FPM en anglais) s'accorde très bien avec [nginx](http://nginx.org) 15 | qui est un serveur web léger et hautement performant. Il utilise moins de mémoire qu'Apache et gère mieux les requêtes 16 | faites en parallèle. Cela est spécialement important pour les serveurs virtuels manquant de mémoire. 17 | 18 | 19 | * [En savoir plus sur nginx](http://nginx.org) 20 | * [En savoir plus sur PHP-FPM](http://php.net/manual/fr/install.fpm.php) 21 | * [En savoir plus sur la configuration de nginx et PHP-FPM](https://nealpoole.com/blog/2011/04/setting-up-php-fastcgi-and-nginx-dont-trust-the-tutorials-check-your-configuration/) 22 | 23 | ### Apache et PHP 24 | 25 | PHP et Apache ont une longue histoire commune. Apache est très largement configurable et un très grand nombre de 26 | [modules](http://httpd.apache.org/docs/2.4/mod/) sont disponibles pour étendre ses fonctionnalités. C'est un choix populaire 27 | pour les serveurs mutualisés car il est très simple pour des frameworks PHP comme Wordpress de s'installer dessus. 28 | Malheureusement, Apache utilise plus de ressources que nginx par défaut et ne peut gérer qu'un nombre limité de clients 29 | à la fois. 30 | 31 | Apache possède différentes configurations possibles pour faire tourner PHP. La plus commune et la plus facile est 32 | d'installer le [prefork MPM](http://httpd.apache.org/docs/2.4/mod/prefork.html) avec le module mod_php5. Bien qu'il ne 33 | soit pas le plus efficace en terme de gestion de la mémoire, il est le plus simple à lancer et utiliser. C'est 34 | probablement le meilleur choix si vous ne souhaitez pas vous plonger dans les aspects trop techniques de 35 | l'administration d'un serveur. Notez que si vous utilisez mod_php5, vous DEVEZ utiliser le prefork MPM. 36 | 37 | Alternativement, si vous voulez profiter de plus de perfomances et de stabilité avec Apache alors vous pouvez tirer 38 | avantage à utiliser le même FPM que nginx et faire tourner le [worker MPM](http://httpd.apache.org/docs/2.4/mod/worker.html) 39 | ou l'[event MPM](http://httpd.apache.org/docs/2.4/mod/event.html) avec mod_fastcgi ou mod_fcgid. Cette configuration 40 | sera nettement meilleure en terme d'utilisation mémoire et plus rapide mais cela demandera plus de travail pour la 41 | mettre en place. 42 | 43 | * [En savoir plus sur Apache](http://httpd.apache.org/) 44 | * [En savoir plus sur les modules Multi-Processing](http://httpd.apache.org/docs/2.4/mod/mpm_common.html) 45 | * [En savoir plus sur mod_fastcgi](http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html) 46 | * [En savoir plus sur mod_fcgid](http://httpd.apache.org/mod_fcgid/) 47 | -------------------------------------------------------------------------------- /_posts/12-04-01-Shared-Servers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hébergement mutualisé 3 | isChild: true 4 | anchor: shared_servers 5 | --- 6 | 7 | ## Hébergement mutualisé {#shared_servers_title} 8 | 9 | Grâce à la popularité de PHP, il existe de nombreuses solutions d'hébergements mutualisés. Il est difficile d'ailleurs 10 | de trouver un hébergeur qui ne propose pas l'installation de PHP mais vérifiez tout de même que ce soit la 11 | dernière version qui soit installée. Les hébergements mutualisés vous permettent à vous et à d'autres développeurs de 12 | déployer des sites sur une seule machine. L'avantage est que cela est une solution économique. L'inconvénient est 13 | que vous ne savez jamais quel genre de grabuge vos "voisins" peuvent faire; ralentir le serveur ou laisser des failles 14 | de sécurité sont les principaux problèmes. Si votre budget le permet, évitez d'utiliser cette solution. 15 | -------------------------------------------------------------------------------- /_posts/12-05-01-Building-your-Application.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Constuire et déployer votre application 3 | isChild: true 4 | anchor: building_your_application 5 | --- 6 | 7 | ## Constuire et déployer votre application {#building_your_application_title} 8 | 9 | Si vous vous retrouvez à faire des changements sur le schéma de la base de données vous-même ou que vous exécutez vos 10 | tests manuellement avant de mettre à jour vos fichiers (là aussi manuellement), vous devriez sans doute repenser votre 11 | méthodologie de développement! Avec l'ensemble des étapes manuelles que vous devez réaliser pour déployer une 12 | nouvelle version de votre application, il y a de fortes chances pour que des erreurs potentiellement fatales viennent 13 | se glisser durant l'une des étapes. Que ce soit une simple mise à jour, un processus de construction et de déploiement 14 | voir même une stratégie d'intégration continue, le [moteur de production](http://fr.wikipedia.org/wiki/Moteur_de_production) 15 | est votre ami. 16 | 17 | Parmi les tâches que vous pourriez vouloir automatiser, vous trouverez: 18 | 19 | * le gestionnaire de dépendances 20 | * la compilation, la minification de vos ressources 21 | * l'exécution des tests 22 | * la création de la documentation 23 | * le "packaging" 24 | * le déploiement 25 | 26 | 27 | ### Outil de construction automatique 28 | 29 | Les outils de contruction automatique ("build tools" en anglais) peuvent être souvent vus comme un ensemble de scripts 30 | gérant les tâches les plus répétitives pour le déploiement d'un logiciel. Ils ne font généralement pas parti du logiciel 31 | en lui-même, agissant ainsi depuis l'extérieur. 32 | 33 | Il existe beaucoup d'outils open-source disponibles pour vous aider à automatiser la construction de votre application, 34 | certains étant même écrits en PHP. Cela ne devrait pas vous empêcher de les utiliser, si jamais ils correspondent mieux 35 | au travail demandé. Voici quelques exemples: 36 | 37 | [Phing](http://www.phing.info/) est le moyen le plus facile pour commencer à utiliser le déploiement automatisé avec PHP. 38 | Avec Phing, vous pouvez contrôler les processus de "packaging", de déploiement et d'exécution de tests à l'aide d'un 39 | simple fichier XML. Phing (qui est basé sur [Apache Ant](http://ant.apache.org/)) fournit un riche ensemble de tâches 40 | généralement nécessaires pour installer ou mettre à jour une application web et peut être amélioré avec l'ajout de 41 | tâches personnalisées, écrit en PHP. 42 | 43 | [Capistrano](https://github.com/capistrano/capistrano/wiki) est un système pour les *programmeurs de niveau intermédiaire 44 | à avancé* pour exécuter des commandes de façon structuré et répétable sur une ou plusieurs machines distantes. Il est 45 | pré-configuré pour déployer des applications Ruby On Rails, cependant nombreux sont ceux à l'utiliser pour *déployer 46 | avec succès des applications PHP*. La bonne utilisation de Capistrano dépend de vos connaissances en Ruby et Rake. 47 | 48 | Le post du blog de Dave Gardner sur le [déploiement PHP avec Capistrano](http://www.davegardner.me.uk/blog/2012/02/13/php-deployment-with-capistrano/) 49 | est un bon point de départ pour les développeurs qui seraient intéressés. 50 | 51 | [Chef](http://www.opscode.com/chef/) est plus qu'un framework de déploiement basé sur Ruby car il peut aussi générer 52 | l'ensemble de l'environnement de votre serveur ou de votre machine virtuelle. 53 | 54 | Les ressources sur Chef pour les développeurs PHP: 55 | 56 | * [Une série en trois parties sur la façon de déployer une application LAMP avec Chef, Vagrant, et EC2](http://www.jasongrimes.org/2012/06/managing-lamp-environments-with-chef-vagrant-and-ec2-1-of-3/) (en) 57 | * [Un aide-mémoire pour "Chef" sur la façon d'installer et de configurer PHP 5.3 et le gestionnaire de paquet PEAR](https://github.com/opscode-cookbooks/php) (en) 58 | 59 | Allez plus loin: 60 | 61 | * [Automatiser votre projet avec Apache Ant](http://net.tutsplus.com/tutorials/other/automate-your-projects-with-apache-ant/) (en) 62 | * [Maven](http://maven.apache.org/), un framework de construction automatisée basé sur Ant et [comment l'utiliser avec PHP](http://www.php-maven.org/) 63 | 64 | ### Intégration continue 65 | 66 | > L'intégration continue est une pratique en génie logiciel où les membres d'une équipe intègrent leurs travaux 67 | > fréquemment, souvent plusieurs fois par jour. Beaucoup d'équipes trouvent que cette approche permet de réduire de 68 | > façon significative les problèmes d'intégrations et ainsi permet un développement plus cohérent et rapide. 69 | 70 | *-- Martin Fowler* 71 | 72 | Il existe différents moyens pour faire de l'intégration continue en PHP. [Travis CI](https://travis-ci.org/) a récemment 73 | fait un excellent travail pour faire de l'intégration continue une réalité et ce même pour de petits projets. Travis 74 | CI est un service hébergé d'intégration continue pour la communauté open-source. IL est intégré à Github et offre un 75 | support de haut niveau pour de nombreux langages (incluant PHP). 76 | 77 | Allez plus loin: 78 | 79 | * [Intégration continue avec Jenkins](http://jenkins-ci.org/) 80 | * [Intégration continue avec PHPCI](http://www.phptesting.org/) 81 | * [Intégration continue avec Teamcity](http://www.jetbrains.com/teamcity/) 82 | -------------------------------------------------------------------------------- /_posts/13-01-01-Virtualization.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Virtualisation 3 | anchor: virtualization 4 | --- 5 | 6 | # Virtualisation {#virtualization_title} 7 | 8 | Faire tourner vos applications sur différents environnements en développement et en production peut vous amener à 9 | rencontrer d'étranges bugs lorsque vous passez le code en production. Par ailleurs, il est difficile de maintenir 10 | différents environnements à jour avec les mêmes versions pour l'ensemble des bibliothèques utilisées lorsque vous 11 | travaillez en équipe. 12 | 13 | Si vous développez sur Windows et que vous déployez votre code sur Linux (ou n'importe quoi qui ne soit pas Windows) 14 | ou que vous travaillez en équipe, vous devriez penser à utiliser une machine virtuelle (Virtual Machine, abrégé en VM 15 | en anglais). 16 | -------------------------------------------------------------------------------- /_posts/13-02-01-Vagrant.md: -------------------------------------------------------------------------------- 1 | --- 2 | isChild: true 3 | anchor: vagrant 4 | --- 5 | 6 | ## Vagrant {#vagrant_title} 7 | 8 | [Vagrant][vagrant] vous permet de mettre en place une machine 9 | virtuelle en seulement quelques étapes. 10 | Ces systèmes de base peuvent ensuite être configurés manuellement ou via des outils comme [Puppet][puppet] ou 11 | [Chef][chef]. Configurer ces systèmes de façon automatisée est un bon moyen de s'assurer que les différents systèmes 12 | mis en place seront configurés de la même manière sans avoir à maintenir une liste de commandes pour l'installation. 13 | Vous pouvez aussi "détruire" votre système et en recréer un nouveau de façon entièrement automatisée, ce qui facilite 14 | les nouvelles installations. 15 | 16 | Vagrant crée des dossiers partagés utilisés pour permettre à l'hôte et à la machine virtuelle d'accéder 17 | de façon bidirectionnelle à votre code, ce qui signifie que vous pouvez créer et éditer vos fichiers sur le système 18 | hôte et exécuter votre code sur la machine virtuelle. 19 | 20 | ### Un coup de pouce 21 | 22 | Si vous avez besoin d'aide pour commencer à utiliser Vagrant, il existe 3 services qui pourraient vous être utiles : 23 | 24 | - [Rove][rove]: Un service qui vous autorise à pré-générer des builds Vagrant typiques avec PHP. L'installation se fait 25 | avec Chef. 26 | - [Puphpet][puphpet]: une interface graphique simple pour mettre en place des machines virtuelles pour développer en PHP. 27 | **Il se concentre énormement sur PHP**. Par ailleurs, des VMs locales peuvent être utilisées pour déployer des services 28 | clouds. L'installation se fait avec Puppet. 29 | - [Protobox][protobox]: est composé d'une couche au-dessus de Vagrant et d'une interface web pour installer des machines 30 | virtuelles pour le développement web. Un seul document YAML contrôle tout ce qui peut être installé sur la machine 31 | virtuelle. 32 | 33 | [vagrant]: http://vagrantup.com/ 34 | [puppet]: http://www.puppetlabs.com/ 35 | [chef]: http://www.opscode.com/ 36 | [rove]: http://rove.io/ 37 | [puphpet]: https://puphpet.com/ 38 | [protobox]: http://getprotobox.com/ 39 | -------------------------------------------------------------------------------- /_posts/13-03-01-Docker.md: -------------------------------------------------------------------------------- 1 | --- 2 | isChild: true 3 | anchor: docker 4 | --- 5 | 6 | ## Docker {#docker_title} 7 | 8 | [Docker] est une alternative légère par rapport à une machine virtuelle. Son nom provient du fait qu'il manipule des "conteneurs". 9 | Un conteneur est le bloc de base qui dans un cas simple n'accomplit qu'une tâche spécifique, par exemple faire tourner un serveur web. 10 | Une "image" est l'instantané que vous utilisez pour construire un conteneur - Docker en répertorie un grand nombre. 11 | 12 | Une application LAMP peut typiquement avoir 3 conteneurs: un pour le serveur web, un pour le processus PHP-FPM et le dernier pour MySQL. 13 | Tout comme les dossiers partagés avec Vagrant, vous pouvez laisser vos fichiers où ils se trouvent et indiquer leurs emplacements à Docker. 14 | 15 | Vous pouvez générer des conteneurs depuis la ligne de commande (voir l'exemple ci-dessous) ou, pour des questions de maintenance, créer un fichier `docker-compose.yml` qui contiendra l'ensemble des éléments et la façon dont ils communiquent entre eux. 16 | 17 | Docker peut vous aider si vous développez plusieurs sites et que vous souhaitez avoir la séparation d'environnement que vous pourriez l'avoir avec une machine virtuelle sans la lourdeur de devoir installer un système d'exploitation complet. 18 | Non seulement le téléchargement et l'installation d'un conteneur se fait très rapidement mais en plus vous bénéficiez aussi d'un stockage réduit car vous pourrez réutiliser les images communes entre vos différents sites. 19 | 20 | ### Exemple: Faire tourner PHP sous Docker 21 | 22 | Après avoir [installer docker][docker-install] sur votre machine vous pouvez démarrer le serveur web en une commande. 23 | La commande suivante vous permettra de disposer d'une installation Apache complète avec la dernière version de PHP visible sur `http://localhost:8080` où la racine du projet pointe vers `/mon/chemin/vers/fichiers_php` : 24 | 25 | {% highlight console %} 26 | docker run -d --name my-php-webserver -p 8080:80 -v /mon/chemin/vers/fichiers_php:/var/www/html/ php:apache 27 | {% endhighlight %} 28 | 29 | Cela va initialiser puis installer votre conteneur. l'option `-d` le fait tourner en arrière plan. Pour l'arrêter ou le démarrer, lancer tout simplement `docker stop my-php-webserver` ou `docker start my-php-webserver` (pas besoin de renseigner les autres paramètres). 30 | 31 | ### En savoir plus sur Docker 32 | 33 | La commande ci-dessus vous montre une façon rapide de mettre en place un serveur web. Il y a encore pleins de choses possibles à faire (et des milliers d'images disponibles sur [Docker Hub][docker-hub]). Prenez le temps de vous familiariser avec la terminologie et lisez [le manuel utilisateur][docker-doc] pour en savoir plus. Gardez cependant à l'esprit de ne jamais faire tourner d'images inconnues et en cas de doute, n'utilisez que les [dépôts officiels][docker-hub-official]. 34 | 35 | Le site [PHPDocker.io] vous permet d'auto-générer les fichiers nécessaires pour créer une pile LAMP/LEMP en y incluant la version PHP de votre choix ainsi que ses extensions. 36 | 37 | * [Site web de Docker][Docker] 38 | * [Installation de Docker][docker-install] 39 | * [Manuel d'utilisation de Docker][docker-doc] 40 | * [Docker Hub][docker-hub] 41 | * [Images officielles du Docker Hub][docker-hub-official] 42 | 43 | [Docker]: http://docker.com/ 44 | [docker-hub]: https://hub.docker.com/ 45 | [docker-hub-official]: https://hub.docker.com/explore/ 46 | [docker-install]: https://docs.docker.com/installation/ 47 | [docker-doc]: https://docs.docker.com/userguide/ 48 | [PHPDocker.io]: https://phpdocker.io/generator 49 | -------------------------------------------------------------------------------- /_posts/14-01-01-Caching.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cache 3 | anchor: caching 4 | --- 5 | 6 | # Cache {#caching_title} 7 | 8 | Le PHP est plutôt rapide en lui-même mais certains points de congestion peuvent apparaître quand vous établissez des 9 | connexions distantes, des chargements de fichiers, etc. Heureusement, il y a de nombreux outils disponibles pour 10 | accélérer certaines parties de vos appplications ou pour réduire le nombre de fois où ces actions consommatrices de temps 11 | ont besoin de se lancer. 12 | -------------------------------------------------------------------------------- /_posts/14-02-01-Bytecode-Cache.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cache du bytecode 3 | isChild: true 4 | anchor: bytecode_caching 5 | --- 6 | 7 | ## Cache du bytecode {#bytecode_caching_title} 8 | 9 | Quand un fichier PHP est exécuté, il est d'abord compilé sous forme de bytecode (aussi connu sous le nom d'opcode) 10 | puis ce bytecode est ensuite exécuté. 11 | Si le fichier PHP n'est pas modifié, le bytecode restera toujours le même ce qui signifie que sa compilation lors de 12 | chaque appel sera une perte de ressources CPU. 13 | 14 | C'est là que le cache du bytecode intervient. Il empêche la compilation récurrente en stockant le bytecode en mémoire 15 | et en le ré-utilisant à chaque appel successif. Mettre en place le cache ne prend que quelques minutes mais cela 16 | augmentera de façon significative la réactivité de votre application. Il n'y a donc aucune raison de ne pas l'utiliser. 17 | 18 | Avec PHP 5.5, il existe un cache intégré pour le bytecode appelé [OPcache](http://php.net/manual/fr/book.opcache.php). 19 | Il est aussi disponible pour les versions précédentes. 20 | 21 | Les autres caches pour bytecode sont: 22 | 23 | * [APC](http://php.net/manual/fr/book.apc.php) (PHP 5.4 et antérieur) 24 | * [XCache](http://xcache.lighttpd.net/) 25 | * [Zend Optimizer+](http://www.zend.com/products/server/) (fait parti de Zend Server) 26 | * [WinCache](http://www.iis.net/download/wincacheforphp) (extension pour MS Windows Server) 27 | -------------------------------------------------------------------------------- /_posts/14-03-01-Object-Caching.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cache des objets 3 | isChild: true 4 | anchor: object_caching 5 | --- 6 | 7 | ## Cache des objets {#object_caching_title} 8 | 9 | Il arrive parfois qu'il soit plus avantageux de mettre en cache des objets individuels dans votre code comme par 10 | exemple dans les cas où l'on souhaite récupérer le même résultat provenant d'une base de données. Vous pouvez utiliser 11 | des logiciels de cache objet pour maintenir ces bouts de données en mémoire pour un usage ultérieur. Si vous enregistrez 12 | ces éléments en mémoire après les avoir récupérés, vous pouvez considérablement gagner en rapidité d'accès; de même 13 | qu'une réduction de l'utilisation de la base de données. 14 | 15 | Beaucoup de solutions de cache du bytecode vous permettent de mettre aussi en cache les données; il y a donc encore 16 | plus d'avantages à les utiliser. APCu, XCache, et WinCache fournissent tous des APIs pour stocker les données de votre 17 | code PHP dans leur système de cache mémoire. 18 | 19 | Les systèmes de cache objet les plus courants sont APCu and memcached. APCu est un excellent choix en ce qui concerne 20 | le cache objet. Il inclut une API simple pour ajouter vos propres données dans son cache et est très facile à 21 | configurer. La seule vraie limitation d'APCu est qu'il est lié au serveur où il est installé. Memcached, d'un autre 22 | côté, s'installe de façon séparé en tant que service et peut être accédé depuis le réseau ce qui signifie que vous 23 | pouvez stocker les objets dans un unique endroit même s'ils proviennent de systèmes différents. 24 | 25 | Notez que lorsque PHP s'exécute en tant qu'application (Fast)-CGI au sein de votre serveur, les processus PHP auront 26 | leur propre cache, c'est-à-dire que les données d'APCu ne seront pas partagées entre les différents processus. Dans ce 27 | cas, vous pourriez envisager d'utiliser memcached étant donné qu'il n'est pas lié aux processus PHP. 28 | 29 | Dans une configuration réseau, APCu va généralement surpasser memcached en terme de rapidité d'accès mais memcached sera 30 | capable d'être "scalable" plus rapidement et de façon plus poussée. Si vous ne vous attendez pas à avoir plusieurs serveurs 31 | pour gérer votre application, ou si vous ne souhaitez pas utiliser les fonctionnalités spécifiques de memcached alors 32 | APCu est probablement votre meilleur choix pour le cache d'objets. 33 | 34 | Exemple utilisant APCu: 35 | 36 | {% highlight php %} 37 | 19 | * @link http://www.phpdoc.org/docs/latest/index.html 20 | * @package helper 21 | */ 22 | class DateTimeHelper 23 | { 24 | /** 25 | * @param mixed $anything Tout ce qui peut être traduit en un objet \DateTime 26 | * 27 | * @return \DateTime 28 | * @throws \InvalidArgumentException 29 | */ 30 | public function dateTimeFromAnything($anything) 31 | { 32 | $type = gettype($anything); 33 | 34 | switch ($type) { 35 | // Ce bloc doit retourner un objet \DateTime 36 | } 37 | 38 | throw new \InvalidArgumentException( 39 | "Impossible de convertir '{$type}' en un objet DateTime" 40 | ); 41 | } 42 | 43 | /** 44 | * @param mixed $date Tout ce qui peut être traduit en un objet \DateTime 45 | * 46 | * @return void 47 | */ 48 | public function printISO8601Date($date) 49 | { 50 | echo $this->dateTimeFromAnything($date)->format('c'); 51 | } 52 | 53 | /** 54 | * @param mixed $date Tout ce qui peut être traduit en un objet \DateTime 55 | */ 56 | public function printRFC2822Date($date) 57 | { 58 | echo $this->dateTimeFromAnything($date)->format('r'); 59 | } 60 | } 61 | {% endhighlight %} 62 | 63 | La documentation d'une classe commence en premier lieu par l'introduction du nom de l'auteur avec le tag 64 | [@author](http://www.phpdoc.org/docs/latest/references/phpdoc/tags/author.html) qui peut être répété s'il y a plusieurs auteurs. 65 | En deuxième lieu, nous pouvons indiquer un lien vers un site web si jamais il existe une relation entre ce dernier et le code via 66 | le tag [@link](http://www.phpdoc.org/docs/latest/references/phpdoc/tags/link.html). Enfin, si jamais la classe fait parti 67 | d'un espace de noms, il faut l'indiquer avec le tag [@package](http://www.phpdoc.org/docs/latest/references/phpdoc/tags/package.html). 68 | 69 | À l'intérieur de cette classe, la première méthode a un paramètre indiqué par [@param](http://www.phpdoc.org/docs/latest/references/phpdoc/tags/param.html) 70 | qui nous renseigne sur son type, son nom et une brève description. Si jamais une méthode renvoit un résultat, il faut 71 | l'indiquer avec le tag [@return](http://www.phpdoc.org/docs/latest/references/phpdoc/tags/return.html) et utilisez 72 | [@throws](http://www.phpdoc.org/docs/latest/references/phpdoc/tags/throws.html) autant de fois qu'il y a d'exceptions levées. 73 | 74 | La seconde et la troisième méthodes sont très similaires et on un unique tag [@param](http://www.phpdoc.org/docs/latest/references/phpdoc/tags/param.html) 75 | comme la première méthode. La seule différence notable se trouvant dans la doc. est la présence d'un tag 76 | [@return](http://www.phpdoc.org/docs/latest/references/phpdoc/tags/return.html) sur la seconde méthode. La valeur 77 | `void` pour le tag [@return](http://www.phpdoc.org/docs/latest/references/phpdoc/tags/return.html) nous informe explicitement que la 78 | méthode ne renvoit rien (si vous omettez ce tag, c'est cette valeur qui sera indiqué par défaut). 79 | 80 | N.d.T.: À noter que `void` n'est pas un type valide pour PHP, c'est pourquoi je préconise de mettre plutôt la valeur 81 | `null` qui est celle retournée par défaut quand la fonction ne contient pas d'instruction `return`. 82 | -------------------------------------------------------------------------------- /_posts/16-01-01-Resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ressources 3 | anchor: resources 4 | --- 5 | 6 | # Ressources {#resources_title} 7 | 8 | ## Officielles 9 | 10 | * [Site web PHP](http://php.net/) 11 | * [Documentation PHP](http://php.net/docs.php) 12 | 13 | ## Personnes à suivre 14 | 15 | * [Rasmus Lerdorf](http://twitter.com/rasmus) 16 | * [Fabien Potencier](http://twitter.com/fabpot) 17 | * [Derick Rethans](http://twitter.com/derickr) 18 | * [Chris Shiflett](http://twitter.com/shiflett) 19 | * [Sebastian Bergmann](http://twitter.com/s_bergmann) 20 | * [Matthew Weier O'Phinney](http://twitter.com/mwop) 21 | * [Pádraic Brady](http://twitter.com/padraicb) 22 | * [Anthony Ferrara](http://twitter.com/ircmaxell) 23 | * [Nikita Popov](http://twitter.com/nikita_ppv) 24 | 25 | ## Mentorat 26 | 27 | * [phpmentoring.org](http://php-mentoring.org/) - Encadrement et montée en compétences par des membres de la communauté 28 | -------------------------------------------------------------------------------- /_posts/16-05-01-PHP-PaaS-Providers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fournisseurs PaaS pour PHP 3 | isChild: true 4 | anchor: php_paas_providers 5 | --- 6 | 7 | ## Fournisseurs PaaS pour PHP {#php_paas_providers_title} 8 | 9 | * [AppFog](https://www.ctl.io/appfog/) 10 | * [AWS Elastic Beanstalk](https://aws.amazon.com/elasticbeanstalk/) 11 | * [Cloudways](https://www.cloudways.com/) 12 | * [Divio](https://www.divio.com/php/) 13 | * [Engine Yard Cloud](https://www.engineyard.com/features) 14 | * [fortrabbit](https://www.fortrabbit.com/) 15 | * [Google App Engine](https://cloud.google.com/appengine/docs/php/) 16 | * [Heroku](https://devcenter.heroku.com/categories/php-support) 17 | * [IBM Cloud](https://console.bluemix.net/docs/runtimes/php/getting-started.html#getting_started) 18 | * [Jelastic](https://jelastic.com/) 19 | * [Microsoft Azure](https://azure.microsoft.com/) 20 | * [Nanobox](https://nanobox.io/) 21 | * [Pivotal Web Services](https://run.pivotal.io/) 22 | * [Platform.sh](https://platform.sh/) 23 | * [Red Hat OpenShift](https://www.openshift.com/) 24 | 25 | Pour savoir quelles versions tournent sur ces hébergeurs, dirigez-vous vers [PHP Versions](http://phpversions.info/paas-hosting/). 26 | -------------------------------------------------------------------------------- /_posts/16-06-01-Frameworks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Frameworks 3 | isChild: true 4 | anchor: frameworks 5 | --- 6 | 7 | ## Frameworks {#frameworks_title} 8 | 9 | Plutôt que de ré-inventer la roue, beaucoup de développeurs PHP utilisent des frameworks pour construire leur application 10 | web. Les frameworks permettent de s'abstraire des préoccupations de bas niveau et fournissent de précieuses interfaces 11 | pour remplir les tâches les plus communes. 12 | 13 | Vous n'avez pas besoin d'utiliser un framework pour chacun de vos projets. Parfois, du PHP brut est le meilleur choix 14 | mais si vous avez besoin d'un framework alors il en existe de 3 sortes : 15 | 16 | * Les micro-frameworks 17 | * Les frameworks complets ("full-stack" en anglais) 18 | * Les frameworks orienté composant 19 | 20 | Les micro-frameworks sont essentiellement des surcouches pour router une requête HTTP vers une fonction de rappel 21 | (callback en anglais), une méthode, etc de façon aussi rapide que possible et parfois sont accompagnés de quelques 22 | bibliothèques supplémentaires pour vous assister dans le développmeent tel qu'une surcouche pour la gestion d'une 23 | base de données, etc. Ils sont principalement utilisés pour construire des services HTTP distants. 24 | 25 | Beaucoup de frameworks ajoutent un nombre considérable de fonctionnalités au-dessus de ce qui est disponible dans un 26 | micro-framework et ceci sont appelés "framework full-stack". Ils sont souvent fourni avec des ORMs, des packages 27 | d'authentification, etc. 28 | 29 | Les frameworks orienté composant sont des collections de bibliothèques spécialisées. Plusieurs de ces frameworks 30 | peuvent être utilisés ensemble pour former un micro ou un framework complet. 31 | 32 | * [Frameworks PHP populaires](https://github.com/codeguy/php-the-right-way/wiki/Frameworks) 33 | -------------------------------------------------------------------------------- /_posts/16-07-01-Components.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Composants 3 | isChild: true 4 | anchor: components 5 | --- 6 | 7 | ## Composants {#components_title} 8 | 9 | Comme mentionné au dessus, les "composants" sont une autre approche pour atteindre l'objectif de créer, distribuer et 10 | implémenter du code partagé. Différents dépôts de composants existent, les 2 plus connus sont : 11 | 12 | * [Packagist](#composer_et_packagist) 13 | * [PEAR](#pear) 14 | 15 | Chacun de ces 2 dépôts possède des outils en ligne de commande qui lui sont associés afin d'installer et de mettre à 16 | jour les processus, ce qui est expliqué plus en détail dans la section [gestion des dépendances][dm]. 17 | 18 | Il existe aussi des frameworks basés sur les composants qui vous permettent d'utiliser leurs composants avec (ou sans) 19 | conditions requises. Par exemple, vous pouvez utiliser le package pour la [validation de FuelPHP][fuelval] sans 20 | l'obligation d'utiliser le framework tout entier. Ces projets sont essentiellement juste d'autres répertoires pour 21 | la réutilisation de composants : 22 | 23 | [dm]: #la_gestion_des_dépendances 24 | [fuelval]: https://github.com/fuelphp/validation 25 | 26 | * [Aura] 27 | * Composants CakePHP 28 | * [Collection] 29 | * [Database] 30 | * [Datasource] 31 | * [Event] 32 | * [I18n] 33 | * [ORM] 34 | * [FuelPHP] 35 | * [Hoa Project] 36 | * [Symfony Components] 37 | * [The League of Extraordinary Packages] 38 | * Les composants Illuminate de Laravel 39 | * [IoC Container] 40 | * [Eloquent ORM] 41 | * [Queue] 42 | 43 | _Les [composants Illuminate] de Laravel listés ci-dessus sont découplés du framework._ 44 | 45 | 46 | [Aura]: http://auraphp.com/framework/ 47 | [FuelPHP]: https://github.com/fuelphp 48 | [Hoa Project]: https://github.com/hoaproject 49 | [Symfony Components]: https://symfony.com/doc/current/components/index.html 50 | [The League of Extraordinary Packages]: https://thephpleague.com/ 51 | [IoC Container]: https://github.com/illuminate/container 52 | [Eloquent ORM]: https://github.com/illuminate/database 53 | [Queue]: https://github.com/illuminate/queue 54 | [composants Illuminate]: https://github.com/illuminate 55 | [Collection]: https://github.com/cakephp/collection 56 | [Database]: https://github.com/cakephp/database 57 | [Datasource]: https://github.com/cakephp/datasource 58 | [Event]: https://github.com/cakephp/event 59 | [I18n]: https://github.com/cakephp/i18n 60 | [ORM]: https://github.com/cakephp/orm 61 | -------------------------------------------------------------------------------- /_posts/16-10-01-Books.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Livres 3 | isChild: true 4 | anchor: books 5 | --- 6 | 7 | ## Livres {#books_title} 8 | 9 | Il existe un grand nombre de livres autour du PHP mais un certain nombre sont malheureusement obsolètes et ne 10 | contiennent plus d'informations à jour. Il existe même des livres publiés pour "PHP 6" qui n'a pas encore vu le jour 11 | (et qui ne le verra probablement jamais à cause de ces livres). 12 | 13 | Cette section se veut être un recueil vivant de l'ensemble des livres recommandés sur le développement PHP en général. 14 | Si vous souhaitez ajouter un livre, envoyez une "pull request" (sur github) et votre avis sera relu et ajouté ici si 15 | cela est pertinent. 16 | 17 | ### Livres gratuits 18 | 19 | * [PHP The Right Way](https://leanpub.com/phptherightway/)(en) - Ce site est aussi disponible au format ebook. 20 | 21 | ### Livres payants 22 | 23 | * [Modernizing Legacy Applications In PHP](https://leanpub.com/mlaphp)(en) - Gardez le contrôle de votre code PHP ancien via 24 | un ensemble d'étapes à appliquer pas à pas 25 | * [Building Secure PHP Apps](https://leanpub.com/buildingsecurephpapps)(en) - Pour apprendre les bases en matière de sécurité 26 | qu'un développeur expérimenté acquiert au fil des années, le tout condensé dans un livre facile à lire 27 | * [The Grumpy Programmer's Guide To Building Testable PHP Applications](https://leanpub.com/grumpy-testing)(en) - Apprendre à écrire du code testable n'est pas forcément ennuyant 28 | * [Securing PHP: Core Concepts](https://leanpub.com/securingphp-coreconcepts)(en) - Un guide sur les failles de sécurité les plus courantes 29 | * [Scaling PHP](https://leanpub.com/scalingphp)(en) - Ne jouez plus les sysadmins et retournez à votre code 30 | * [Signaling PHP](https://leanpub.com/signalingphp)(en) - Les signaux PCNLT sont d'une grande aide lorsqu'il s'agit d'écrire des scripts PHP en ligne de commande. 31 | -------------------------------------------------------------------------------- /_posts/17-01-01-Community.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Communauté 3 | anchor: community 4 | --- 5 | 6 | # Communauté {#ccommunity_title} 7 | 8 | La communauté PHP est aussi diverse que large et de nombreux membres sont prêts à porter secours aux nouveaux. 9 | N'hésitez pas à rejoindre un PHP User Group (PUG) ou à assister à des conférences sur PHP afin d'en apprendre plus sur 10 | les meilleures pratiques. Vous pouvez aussi aller sur IRC, canal #phpc du serveur Freenode ([irc.freenode.com][php-irc]) 11 | et suivre le compte twitter [@phpc][phpc-twitter]. Sortez, rencontrez d'autres développeurs PHP, apprenez de nouveaux 12 | sujets et par dessus tout, faites vous des amis ! Ils existent d'autres ressources en ligne comme la page [StackOverflow][php-so]. 13 | 14 | [Voir le calendrier officiel des évènements PHP][php-calendar] 15 | 16 | ## PHP User Groups 17 | 18 | Si vous vivez dans une grande ville, il y a de fortes chances pour qu'un groupe d'utilisateurs PHP existe. Bien qu'il 19 | n'y ait pas de listes officielles, vous pouvez facilement trouver un groupe proche de chez vous en allant sur 20 | [Google][google], [Meetup.com][meetup] ou [PHP.ug][php-ug]. Si vous vivez dans une ville plus petite, il se peut qu'il 21 | n'existe rien encore alors si vous avez suffisamment de motivation, créez-en une ! 22 | 23 | [Lire plus sur les PUGs dans le wiki PHP][php-wiki] 24 | 25 | ## Conférences PHP 26 | 27 | Des conférences PHP ont lieu dans beaucoup de pays de part le monde. Vous y trouverez des membres connus 28 | de la communauté PHP, c'est donc une excellente opportunité de rencontrer les leaders de l'industrie. 29 | 30 | [Trouver des conférences PHP][php-conf] 31 | 32 | [php-calendar]: http://www.php.net/cal.php 33 | [google]: https://www.google.com/search?q=php+user+group+proche+de+chez+moi 34 | [meetup]: http://www.meetup.com/find/ 35 | [php-ug]: http://php.ug 36 | [php-wiki]: https://wiki.php.net/usergroups 37 | [php-conf]: http://php.net/conferences/index.php 38 | [phpc-twitter]: https://twitter.com/phpc 39 | [php-irc]: http://webchat.freenode.net/?channels=phpc 40 | [php-so]: http://stackoverflow.com/questions/tagged/php 41 | -------------------------------------------------------------------------------- /banners.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Bannière du site 4 | description: "Montrez votre soutien! Utilisez ces bannières pour faire connaître aux nouveaux développeurs PHP ce site" 5 | --- 6 | 7 | # Bannière Web 8 | 9 | Faites passer le mot avec les images _PHP: La bonne manière_ ! Montrez aux développeurs PHP où trouver la bonne information. 10 | 11 | ## Bouton 1 (120x90) 12 | 13 |

    PHP: La bonne manière

    14 | 15 | {% highlight html %} 16 | 17 | PHP: The Right Way 18 | 19 | {% endhighlight %} 20 | 21 | ## Bouton 2 (120x60) 22 | 23 |

    PHP: La bonne manière

    24 | 25 | {% highlight html %} 26 | 27 | PHP: The Right Way 28 | 29 | {% endhighlight %} 30 | 31 | ## Bandeau (728x90) 32 | 33 |

    PHP: La bonne manière

    34 | 35 | {% highlight html %} 36 | 37 | PHP: The Right Way 38 | 39 | {% endhighlight %} 40 | 41 | ## Rectangle large (386x280) 42 | 43 |

    PHP: La bonne manière

    44 | 45 | {% highlight html %} 46 | 47 | PHP: The Right Way 48 | 49 | {% endhighlight %} 50 | 51 | ## Rectangle moyen (300x250) 52 | 53 |

    PHP: La bonne manière

    54 | 55 | {% highlight html %} 56 | 57 | PHP: The Right Way 58 | 59 | {% endhighlight %} 60 | 61 | ## Rectangle (180x150) 62 | 63 |

    PHP: La bonne manière

    64 | 65 | {% highlight html %} 66 | 67 | PHP: The Right Way 68 | 69 | {% endhighlight %} 70 | 71 | ## Bouton carré (125x125) 72 | 73 |

    PHP: La bonne manière

    74 | 75 | {% highlight html %} 76 | 77 | PHP: The Right Way 78 | 79 | {% endhighlight %} 80 | 81 | ## Rectangle vertical (240x400) 82 | 83 |

    PHP: La bonne manière

    84 | 85 | {% highlight html %} 86 | 87 | PHP: The Right Way 88 | 89 | {% endhighlight %} 90 | -------------------------------------------------------------------------------- /images/banners/btn1-120x90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/banners/btn1-120x90.png -------------------------------------------------------------------------------- /images/banners/btn2-120x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/banners/btn2-120x60.png -------------------------------------------------------------------------------- /images/banners/leaderboard-728x90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/banners/leaderboard-728x90.png -------------------------------------------------------------------------------- /images/banners/lg-rect-386x280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/banners/lg-rect-386x280.png -------------------------------------------------------------------------------- /images/banners/med-rect-300x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/banners/med-rect-300x250.png -------------------------------------------------------------------------------- /images/banners/rect-180x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/banners/rect-180x150.png -------------------------------------------------------------------------------- /images/banners/sq-btn-125x125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/banners/sq-btn-125x125.png -------------------------------------------------------------------------------- /images/banners/vert-rect-240x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/banners/vert-rect-240x400.png -------------------------------------------------------------------------------- /images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/favicon.png -------------------------------------------------------------------------------- /images/nmc-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/nmc-logo.gif -------------------------------------------------------------------------------- /images/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/og-image.png -------------------------------------------------------------------------------- /images/og-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eilgin/php-the-right-way/48f846a9d48e5015edc5c61e5c47194e03c9f8c8/images/og-logo.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | description: "Une référence rapide à lire pour apprendre les meilleurs pratiques PHP, les conventions d'écritures et les liens sur les tutoriaux faisant autorité sur le web" 4 | sitemap: true 5 | --- 6 | 7 | {% capture welcome_content %}{% include welcome.md %}{% endcapture %} 8 |
    9 | {{ welcome_content|markdownify }} 10 |
    11 | 12 | {% capture backtotop %}[Retour en haut](#top){:.top}{% endcapture %} 13 | {% for post in site.posts reversed %} 14 | {% if post.isChild != true and loop.first != true %}
    {{ backtotop|markdownify }}
    {% endif %} 15 |
    16 | {{ post.content }} 17 |
    18 | {% endfor %} 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "php-the-right-way", 3 | "version": "2.0.0", 4 | "devDependencies": { 5 | "grunt": "~0.4.5", 6 | "grunt-contrib-less": "~1.0.1", 7 | "grunt-contrib-watch": "~0.6.1", 8 | "grunt-postcss": "^0.6.0", 9 | "autoprefixer": "^6.0.3" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /pages/Functional-Programming.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Programmation fonctionnelle en PHP 4 | sitemap: true 5 | --- 6 | 7 | # La programmation fonctionnelle en PHP 8 | 9 | PHP supporte les fonctions d'ordre supérieur, c'est-à-dire les fonctions qui peuvent être définies en tant que variables. 10 | Les fonctions internes et définies par l'utilisateur peuvent être référencées par une variable et être ainsi 11 | invoquées dynamiquement. Les fonctions peuvent être passées en tant qu'argument à d'autres fonctions et une fonction 12 | peut retourner une autre fonction. 13 | 14 | La récursivité, qui est une démarche permettant à une fonction de s'appeler elle-même, est supportée par le language 15 | mais PHP s'attarde le plus souvent sur la partie itérative. 16 | 17 | Les fonctions anonymes avec le support des fermetures (closures en anglais) sont présentes dans PHP depuis la version 18 | 5.3 (2009). 19 | 20 | PHP 5.4 a ajouté la possibilité de lier les closures à la portée d'un objet et aussi d'améliorer le support pour les 21 | fonctions de rappel de façon à ce qu'elles puissent être utilisées de façon interchangeable avec les fonctions 22 | anonymes dans la plupart des cas. 23 | 24 | L'usage le plus courant des fonctions d'ordre supérieur est lors de l'implémentation du motif de conception "Strategy". 25 | La fonction interne `array_filter` demande en entrée à la fois un tableau de données et une fonction (la fonction de 26 | rappel) utilisée comme fonction de filtrage sur chacun des éléments du tableau. 27 | 28 | 29 | {% highlight php %} 30 | $min 61 | * 62 | * Retourne un ensemble de valeurs "plus grand que $min" 63 | */ 64 | function criteria_greater_than($min) 65 | { 66 | return function($item) use ($min) { 67 | return $item > $min; 68 | }; 69 | } 70 | 71 | $input = array(1, 2, 3, 4, 5, 6); 72 | 73 | // Utilisation d'array_filter sur une entrée associée à la fonction de filtrage 74 | $output = array_filter($input, criteria_greater_than(3)); 75 | 76 | print_r($output); // valeurs > 3 77 | {% endhighlight %} 78 | 79 | Chaque fonction de filtrage dans cet ensemble n'accepte que les éléments plus grands qu'une valeur minimum. Le filtre 80 | retourné par `criteria_greater_than` est une closure avec l'argument `$min` "capturé" dans sa portée (passé en argument 81 | lors de l'appel de `criteria_greater_than`). 82 | 83 | La liaison statique (`early binding` en anglais) est utilisée par défaut lors de l'import de `$min` dans la fonction 84 | créée. Les véritables closures avec la liaison dynamique (`late binding` en anglais) doivent utiliser une référence 85 | lors de l'import. Imaginez une bibliothèque de validation d'entrée ou de templating, où la fermeture est définie pour 86 | capturer les variables dans sa portée afin de pouvoir y accéder plus tard quand la fonction anonyme sera évaluée. 87 | 88 | * [Plus de détails sur les fonctions anonymes][anonymous-functions] 89 | * [Plus de détails sur les RFC "closures"][closures-rfc] (en) 90 | * [Plus de détails à propos des fonctions invoquées dynamiquement avec `call_user_func_array`][call-user-func-array] 91 | 92 | [anonymous-functions]: http://www.php.net/manual/fr/functions.anonymous.php 93 | [call-user-func-array]: http://php.net/manual/fr/function.call-user-func-array.php 94 | [closures-rfc]: https://wiki.php.net/rfc/closures 95 | -------------------------------------------------------------------------------- /pages/example.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Example Stand-Alone Page 4 | --- 5 | 6 | # Page Title 7 | 8 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 9 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 10 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 11 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 12 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 13 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 14 | 15 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 16 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 17 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 18 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 19 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 20 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 21 | 22 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 23 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 24 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 25 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 26 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 27 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 28 | -------------------------------------------------------------------------------- /scripts/fastclick.js: -------------------------------------------------------------------------------- 1 | /** Shrinkwrap URL: 2 | * /v2/bundles/js?modules=fastclick%401.0.6%2Co-autoinit%401.0.1&shrinkwrap= 3 | */ 4 | !function(t){function e(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return t[o].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";n(1),window.Origami={fastclick:n(2),"o-autoinit":n(4)}},function(t,e){t.exports={name:"__MAIN__",dependencies:{fastclick:"fastclick#*","o-autoinit":"o-autoinit#^1.0.0"}}},function(t,e,n){t.exports=n(3)},function(t,e){"use strict";var n=!1;!function(){function e(t,n){function o(t,e){return function(){return t.apply(e,arguments)}}var r;if(n=n||{},this.trackingClick=!1,this.trackingClickStart=0,this.targetElement=null,this.touchStartX=0,this.touchStartY=0,this.lastTouchIdentifier=0,this.touchBoundary=n.touchBoundary||10,this.layer=t,this.tapDelay=n.tapDelay||200,this.tapTimeout=n.tapTimeout||700,!e.notNeeded(t)){for(var a=["onMouse","onClick","onTouchStart","onTouchMove","onTouchEnd","onTouchCancel"],c=this,s=0,u=a.length;u>s;s++)c[a[s]]=o(c[a[s]],c);i&&(t.addEventListener("mouseover",this.onMouse,!0),t.addEventListener("mousedown",this.onMouse,!0),t.addEventListener("mouseup",this.onMouse,!0)),t.addEventListener("click",this.onClick,!0),t.addEventListener("touchstart",this.onTouchStart,!1),t.addEventListener("touchmove",this.onTouchMove,!1),t.addEventListener("touchend",this.onTouchEnd,!1),t.addEventListener("touchcancel",this.onTouchCancel,!1),Event.prototype.stopImmediatePropagation||(t.removeEventListener=function(e,n,o){var i=Node.prototype.removeEventListener;"click"===e?i.call(t,e,n.hijacked||n,o):i.call(t,e,n,o)},t.addEventListener=function(e,n,o){var i=Node.prototype.addEventListener;"click"===e?i.call(t,e,n.hijacked||(n.hijacked=function(t){t.propagationStopped||n(t)}),o):i.call(t,e,n,o)}),"function"==typeof t.onclick&&(r=t.onclick,t.addEventListener("click",function(t){r(t)},!1),t.onclick=null)}}var o=navigator.userAgent.indexOf("Windows Phone")>=0,i=navigator.userAgent.indexOf("Android")>0&&!o,r=/iP(ad|hone|od)/.test(navigator.userAgent)&&!o,a=r&&/OS 4_\d(_\d)?/.test(navigator.userAgent),c=r&&/OS [6-7]_\d/.test(navigator.userAgent),s=navigator.userAgent.indexOf("BB10")>0;e.prototype.needsClick=function(t){switch(t.nodeName.toLowerCase()){case"button":case"select":case"textarea":if(t.disabled)return!0;break;case"input":if(r&&"file"===t.type||t.disabled)return!0;break;case"label":case"iframe":case"video":return!0}return/\bneedsclick\b/.test(t.className)},e.prototype.needsFocus=function(t){switch(t.nodeName.toLowerCase()){case"textarea":return!0;case"select":return!i;case"input":switch(t.type){case"button":case"checkbox":case"file":case"image":case"radio":case"submit":return!1}return!t.disabled&&!t.readOnly;default:return/\bneedsfocus\b/.test(t.className)}},e.prototype.sendClick=function(t,e){var n,o;document.activeElement&&document.activeElement!==t&&document.activeElement.blur(),o=e.changedTouches[0],n=document.createEvent("MouseEvents"),n.initMouseEvent(this.determineEventType(t),!0,!0,window,1,o.screenX,o.screenY,o.clientX,o.clientY,!1,!1,!1,!1,0,null),n.forwardedTouchEvent=!0,t.dispatchEvent(n)},e.prototype.determineEventType=function(t){return i&&"select"===t.tagName.toLowerCase()?"mousedown":"click"},e.prototype.focus=function(t){var e;r&&t.setSelectionRange&&0!==t.type.indexOf("date")&&"time"!==t.type&&"month"!==t.type?(e=t.value.length,t.setSelectionRange(e,e)):t.focus()},e.prototype.updateScrollParent=function(t){var e,n;if(e=t.fastClickScrollParent,!e||!e.contains(t)){n=t;do{if(n.scrollHeight>n.offsetHeight){e=n,t.fastClickScrollParent=n;break}n=n.parentElement}while(n)}e&&(e.fastClickLastScrollTop=e.scrollTop)},e.prototype.getTargetElementFromEventTarget=function(t){return t.nodeType===Node.TEXT_NODE?t.parentNode:t},e.prototype.onTouchStart=function(t){var e,n,o;if(t.targetTouches.length>1)return!0;if(e=this.getTargetElementFromEventTarget(t.target),n=t.targetTouches[0],r){if(o=window.getSelection(),o.rangeCount&&!o.isCollapsed)return!0;if(!a){if(n.identifier&&n.identifier===this.lastTouchIdentifier)return t.preventDefault(),!1;this.lastTouchIdentifier=n.identifier,this.updateScrollParent(e)}}return this.trackingClick=!0,this.trackingClickStart=t.timeStamp,this.targetElement=e,this.touchStartX=n.pageX,this.touchStartY=n.pageY,t.timeStamp-this.lastClickTimen||Math.abs(e.pageY-this.touchStartY)>n?!0:!1},e.prototype.onTouchMove=function(t){return this.trackingClick?((this.targetElement!==this.getTargetElementFromEventTarget(t.target)||this.touchHasMoved(t))&&(this.trackingClick=!1,this.targetElement=null),!0):!0},e.prototype.findControl=function(t){return void 0!==t.control?t.control:t.htmlFor?document.getElementById(t.htmlFor):t.querySelector("button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea")},e.prototype.onTouchEnd=function(t){var e,n,o,s,u,l=this.targetElement;if(!this.trackingClick)return!0;if(t.timeStamp-this.lastClickTimethis.tapTimeout)return!0;if(this.cancelNextClick=!1,this.lastClickTime=t.timeStamp,n=this.trackingClickStart,this.trackingClick=!1,this.trackingClickStart=0,c&&(u=t.changedTouches[0],l=document.elementFromPoint(u.pageX-window.pageXOffset,u.pageY-window.pageYOffset)||l,l.fastClickScrollParent=this.targetElement.fastClickScrollParent),o=l.tagName.toLowerCase(),"label"===o){if(e=this.findControl(l)){if(this.focus(l),i)return!1;l=e}}else if(this.needsFocus(l))return t.timeStamp-n>100||r&&window.top!==window&&"input"===o?(this.targetElement=null,!1):(this.focus(l),this.sendClick(l,t),r&&"select"===o||(this.targetElement=null,t.preventDefault()),!1);return r&&!a&&(s=l.fastClickScrollParent,s&&s.fastClickLastScrollTop!==s.scrollTop)?!0:(this.needsClick(l)||(t.preventDefault(),this.sendClick(l,t)),!1)},e.prototype.onTouchCancel=function(){this.trackingClick=!1,this.targetElement=null},e.prototype.onMouse=function(t){return this.targetElement?t.forwardedTouchEvent?!0:t.cancelable&&(!this.needsClick(this.targetElement)||this.cancelNextClick)?(t.stopImmediatePropagation?t.stopImmediatePropagation():t.propagationStopped=!0,t.stopPropagation(),t.preventDefault(),!1):!0:!0},e.prototype.onClick=function(t){var e;return this.trackingClick?(this.targetElement=null,this.trackingClick=!1,!0):"submit"===t.target.type&&0===t.detail?!0:(e=this.onMouse(t),e||(this.targetElement=null),e)},e.prototype.destroy=function(){var t=this.layer;i&&(t.removeEventListener("mouseover",this.onMouse,!0),t.removeEventListener("mousedown",this.onMouse,!0),t.removeEventListener("mouseup",this.onMouse,!0)),t.removeEventListener("click",this.onClick,!0),t.removeEventListener("touchstart",this.onTouchStart,!1),t.removeEventListener("touchmove",this.onTouchMove,!1),t.removeEventListener("touchend",this.onTouchEnd,!1),t.removeEventListener("touchcancel",this.onTouchCancel,!1)},e.notNeeded=function(t){var e,n,o,r;if("undefined"==typeof window.ontouchstart)return!0;if(n=+(/Chrome\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1]){if(!i)return!0;if(e=document.querySelector("meta[name=viewport]")){if(-1!==e.content.indexOf("user-scalable=no"))return!0;if(n>31&&document.documentElement.scrollWidth<=window.outerWidth)return!0}}if(s&&(o=navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/),o[1]>=10&&o[2]>=3&&(e=document.querySelector("meta[name=viewport]")))){if(-1!==e.content.indexOf("user-scalable=no"))return!0;if(document.documentElement.scrollWidth<=window.outerWidth)return!0}return"none"===t.style.msTouchAction||"manipulation"===t.style.touchAction?!0:(r=+(/Firefox\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1],r>=27&&(e=document.querySelector("meta[name=viewport]"),e&&(-1!==e.content.indexOf("user-scalable=no")||document.documentElement.scrollWidth<=window.outerWidth))?!0:"none"===t.style.touchAction||"manipulation"===t.style.touchAction?!0:!1)},e.attach=function(t,n){return new e(t,n)},"function"==typeof n&&"object"==typeof n.amd&&n.amd?n(function(){return e}):"undefined"!=typeof t&&t.exports?(t.exports=e.attach,t.exports.FastClick=e):window.FastClick=e}()},function(t,e,n){t.exports=n(5)},function(t,e){"use strict";function n(t){t in o||(o[t]=!0,document.dispatchEvent(new CustomEvent("o."+t)))}var o={};window.addEventListener("load",n.bind(null,"load")),window.addEventListener("load",n.bind(null,"DOMContentLoaded")),document.addEventListener("DOMContentLoaded",n.bind(null,"DOMContentLoaded")),"complete"===document.readyState?(n("load"),n("DOMContentLoaded")):"interactive"===document.readyState&&n("DOMContentLoaded")}]); 5 | -------------------------------------------------------------------------------- /scripts/setup.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | // Attach FastClick 3 | var attachFastClick = Origami.fastclick; 4 | attachFastClick(document.body); 5 | 6 | // Mobile TOC menu 7 | var $window = $(window), 8 | $nav = $('.site-navigation'); 9 | $nav.click(function (e) { 10 | var $target = $(e.target); 11 | if ($target.is($nav) && $window.width() <= 375) { 12 | $nav.toggleClass('open'); 13 | } 14 | if ($target.is('a')) { 15 | $nav.removeClass('open'); 16 | } 17 | }); 18 | })(jQuery); 19 | -------------------------------------------------------------------------------- /styles/all.less: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | NMC Bootstrap 3 | 4 | This LESS file imports all other LESS files. You should compile 5 | and minify this file before site launch. 6 | ========================================================================== */ 7 | 8 | /* Import NMC bootstrap */ 9 | 10 | @import "base/all"; 11 | 12 | /* Import site-specific styles */ 13 | 14 | @import "site/site-header.less"; 15 | @import "site/site-navigation.less"; 16 | @import "site/site-content.less"; 17 | @import "site/site-footer.less"; 18 | 19 | /* Tablets and Smartphones */ 20 | 21 | @media only screen and (max-width : 1024px) { 22 | .build-date{ 23 | text-align: center; 24 | } 25 | .site-header{ 26 | height: 220px; 27 | position: absolute; 28 | top: 20px; 29 | left: 0; 30 | width: 100%; 31 | } 32 | .fork-me img{ 33 | height: 110px; 34 | width: 110px; 35 | } 36 | .site-navigation{ 37 | margin-top: 240px; 38 | padding: 20px; 39 | position: relative; 40 | width: auto; 41 | 42 | ul{ 43 | border: 1px solid #999; 44 | border-bottom: none; 45 | } 46 | li{ 47 | .man; 48 | .pan; 49 | } 50 | a{ 51 | background: #CCC; 52 | display: block; 53 | border-bottom: 1px solid #999; 54 | padding: 10px; 55 | text-decoration: none; 56 | } 57 | ul ul{ 58 | border: none; 59 | .man; 60 | .pan; 61 | } 62 | ul ul a{ 63 | background: transparent; 64 | } 65 | } 66 | .site-content{ 67 | padding: 20px; 68 | } 69 | .top{ 70 | display: inline-block; 71 | float: none; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /styles/base/all.less: -------------------------------------------------------------------------------- 1 | @import "reset"; 2 | @import "prefixer"; 3 | @import "spacing"; 4 | @import "typography"; 5 | @import "idioms"; 6 | @import "grid"; 7 | @import "bars-buttons"; 8 | @import "buttons"; 9 | -------------------------------------------------------------------------------- /styles/base/bars-buttons.less: -------------------------------------------------------------------------------- 1 | .button() { 2 | .border-box; 3 | cursor: pointer; 4 | display: inline-block; 5 | .phh; 6 | text-align: center; 7 | font-weight: bold; 8 | } 9 | .button-hover(){ 10 | text-decoration: none; 11 | } 12 | .bar() { 13 | display: block; 14 | .pah; 15 | text-align: center; 16 | font-weight: bold; 17 | } 18 | 19 | /* Sizes */ 20 | 21 | .btn-size(@scale){ 22 | height: @baseline * @scale !important; 23 | padding-bottom: 0 !important; 24 | padding-top: 0 !important; 25 | line-height: @baseline * (@scale * 0.9); 26 | } 27 | .btn-half{ 28 | .btn-size(1); 29 | font-size: 0.8em; 30 | } 31 | .btn-single{ 32 | .btn-size(1.5); 33 | font-size: 1em; 34 | } 35 | .btn-double{ 36 | .btn-size(2); 37 | font-size: 1.1em; 38 | } 39 | 40 | /* Shapes */ 41 | 42 | .bb-shape-square() { 43 | .border-radius(0); 44 | } 45 | .bb-shape-rounded(@rad:3px) { 46 | .border-radius(@rad); 47 | } 48 | .bb-shape-round() { 49 | .border-radius(@baseline); 50 | } 51 | 52 | /* Text */ 53 | 54 | .bb-text-dark(){ 55 | color: #333; 56 | text-shadow: 0 1px 0 #fff; 57 | } 58 | .bb-text-light(){ 59 | color: #fff; 60 | text-shadow: 0 -1px 0 rgba(0,0,0,.3); 61 | } 62 | .bb-text-color(@color){ 63 | 64 | } 65 | 66 | /* Color */ 67 | 68 | .bb-color-plain(@color){ 69 | background: @color; 70 | } 71 | .bb-color-gradient(@color){ 72 | .gradient(@color,lighten(@color,10%),darken(@color,10%)); 73 | } 74 | .bb-color-soft(@color){ 75 | .gradient(@color,lighten(@color,5%),darken(@color,5%)); 76 | } 77 | .bb-color-gloss(@color){ 78 | @topStart: desaturate(lighten(@color,40%),20%); 79 | @topStop: desaturate(lighten(@color,20%),40%); 80 | @bottomStart: desaturate(lighten(@color,10%),30%); 81 | @bottomStop: desaturate(lighten(@color,15%),30%); 82 | .linear-gradient-top(@color,@topStart,0%,@topStop,50%,@bottomStart,50%,@bottomStop,100%); 83 | } 84 | 85 | /* Border */ 86 | 87 | .bb-border-noborder(){ 88 | border: none; 89 | } 90 | .bb-border-plain(@color){ 91 | border: 1px solid darken(@color,10%); 92 | } 93 | .bb-border-contrast(@color){ 94 | border: 1px solid darken(@color,15%); 95 | .box-shadow(inset 0 0 1px 1px lighten(@color,15%)); 96 | } 97 | .bb-border-meta(@color){ 98 | border: 1px solid darken(@color,15%); 99 | .box-shadow(inset 0 2px 1px -1px lighten(@color,20%)); 100 | } 101 | 102 | /* Minimal */ 103 | 104 | .button-minimal(@color) { 105 | .button(); 106 | .bb-shape-rounded(); 107 | .bb-color-plain(@color); 108 | .bb-border-contrast(@color); 109 | .bb-text-dark(); 110 | } 111 | .button-minimal-hover(@color){ 112 | .button-minimal(darken(@color,5%)); 113 | .button-hover(); 114 | } 115 | .button-minimal-active(@color){ 116 | .button-minimal-hover(darken(@color,5%)); 117 | } 118 | .bar-minimal(@color) { 119 | .button-minimal(@color); 120 | .bar(); 121 | } 122 | 123 | /* Clean */ 124 | 125 | .button-clean(@color) { 126 | .button(); 127 | .bb-shape-rounded(); 128 | .bb-color-gradient(@color); 129 | .bb-border-plain(darken(@color,5%)); 130 | .bb-text-dark(); 131 | } 132 | .button-clean-hover(@color){ 133 | .button-clean(darken(@color,5%)); 134 | .button-hover(); 135 | } 136 | .button-clean-active(@color){ 137 | .button-clean-hover(darken(@color,5%)); 138 | } 139 | .bar-clean(@color){ 140 | .button-clean(@color); 141 | .bar(); 142 | } 143 | 144 | /* Soft */ 145 | 146 | .button-soft(@color) { 147 | .button(); 148 | .bb-shape-rounded(); 149 | .bb-color-soft(@color); 150 | .bb-border-meta(darken(@color,5%)); 151 | .bb-text-light(); 152 | } 153 | .button-soft-hover(@color){ 154 | .button-soft(darken(@color,5%)); 155 | .button-hover(); 156 | } 157 | .button-soft-active(@color){ 158 | .button-soft-hover(darken(@color,5%)); 159 | } 160 | .bar-soft(@color){ 161 | .button-soft(@color); 162 | .bar(); 163 | } 164 | 165 | /* Pill */ 166 | 167 | .button-pill(@color) { 168 | .button(); 169 | .bb-shape-round(); 170 | .bb-color-soft(@color); 171 | .bb-border-meta(darken(@color,5%)); 172 | .bb-text-light(); 173 | } 174 | .button-pill-hover(@color){ 175 | .button-pill(darken(@color,5%)); 176 | .button-hover(); 177 | } 178 | .button-pill-active(@color){ 179 | .button-pill-hover(darken(@color,5%)); 180 | } 181 | .bar-pill(@color){ 182 | .button-pill(@color); 183 | .bar(); 184 | } 185 | 186 | /* Gloss */ 187 | 188 | .button-gloss(@color) { 189 | .button(); 190 | .bb-shape-rounded(5px); 191 | .bb-color-gloss(@color); 192 | .bb-border-plain(darken(@color,5%)); 193 | .box-shadow(inset 0 1px 0 0 rgba(255,255,255,.5)); 194 | .bb-text-light(); 195 | } 196 | .button-gloss-hover(@color){ 197 | .button-gloss(darken(@color,5%)); 198 | .box-shadow(inset 0 1px 0 0 rgba(255,255,255,.3)); 199 | .button-hover(); 200 | } 201 | .button-gloss-active(@color){ 202 | .button-gloss-hover(darken(@color,5%)); 203 | .box-shadow(inset 0 0 5px 0 rgba(0,0,0,.3)); 204 | } 205 | .bar-gloss(@color){ 206 | .button-gloss(@color); 207 | .bar(); 208 | } 209 | 210 | @btn-minimal-color: #eee; 211 | .btn-minimal { .button-minimal(@btn-minimal-color); } 212 | .btn-minimal:hover { .button-minimal-hover(@btn-minimal-color); } 213 | .btn-minimal:active { .button-minimal-active(@btn-minimal-color); } 214 | 215 | @btn-clean-color: #eee; 216 | .btn-clean { .button-clean(@btn-clean-color); } 217 | .btn-clean:hover { .button-clean-hover(@btn-clean-color); } 218 | .btn-clean:active { .button-clean-active(@btn-clean-color); } 219 | 220 | @btn-soft-color: #6C84AB; 221 | .btn-soft { .button-soft(@btn-soft-color); } 222 | .btn-soft:hover { .button-soft-hover(@btn-soft-color); } 223 | .btn-soft:active { .button-soft-active(@btn-soft-color); } 224 | 225 | @btn-pill-color: #6C84AB; 226 | .btn-pill { .button-pill(@btn-pill-color); } 227 | .btn-pill:hover { .button-pill-hover(@btn-pill-color); } 228 | .btn-pill:active { .button-pill-active(@btn-pill-color); } 229 | 230 | @btn-gloss-color: #172D6E; 231 | .btn-gloss { .button-gloss(@btn-gloss-color); } 232 | .btn-gloss:hover { .button-gloss-hover(@btn-gloss-color); } 233 | .btn-gloss:active { .button-gloss-active(@btn-gloss-color); } 234 | 235 | 236 | .bar-minimal { .bar-minimal(@btn-minimal-color); } 237 | .bar-clean { .bar-clean(@btn-clean-color); } 238 | .bar-soft { .bar-soft(@btn-soft-color); } 239 | .bar-pill { .bar-pill(@btn-pill-color); } 240 | .bar-gloss { .bar-gloss(@btn-gloss-color); } 241 | -------------------------------------------------------------------------------- /styles/base/buttons.less: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Settings 3 | ========================================================================== */ 4 | 5 | @import 'variables.less'; 6 | 7 | /* 8 | @baseline: @baseline; 9 | @button-color: @button-color; 10 | @button-primary-color: @button-primary-color; 11 | @button-info-color: @button-info-color; 12 | @button-success-color: @button-success-color; 13 | @button-warning-color: @button-warning-color; 14 | @button-danger-color: @button-danger-color; 15 | */ 16 | 17 | /* ========================================================================== 18 | Default 19 | ========================================================================== */ 20 | 21 | .btn{ 22 | .btn-s; 23 | background-clip: border-box !important; 24 | background-repeat: repeat-x; 25 | border: 1px solid rgba(0, 0, 0, 0.25); 26 | .border-box; 27 | .border-radius(4px); 28 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 29 | cursor: pointer; 30 | display: inline-block; 31 | .gradient(@button-color, lighten(@button-color, 10%), @button-color); 32 | .phh; 33 | .pvn; 34 | .transition(background-position linear 0.1s); 35 | vertical-align: middle; 36 | color: #333; 37 | font-family: @body-font-family; 38 | text-decoration: none !important; 39 | text-shadow: rgba(255,255,255,0.75) 0 1px 0; 40 | 41 | &:hover{ 42 | background-position: 0 -15px; 43 | } 44 | } 45 | 46 | /* ========================================================================== 47 | Styles 48 | ========================================================================== */ 49 | 50 | .btn-primary, 51 | .btn-info, 52 | .btn-success, 53 | .btn-warning, 54 | .btn-danger{ 55 | color: #FFF !important; 56 | text-shadow: rgba(0,0,0,0.25) 0 -1px 0 !important; 57 | } 58 | .btn-primary{ 59 | .btn; 60 | .gradient(@button-primary-color, lighten(@button-primary-color, 10%), @button-primary-color); 61 | } 62 | .btn-info{ 63 | .btn; 64 | .gradient(@button-info-color, lighten(@button-info-color, 10%), @button-info-color); 65 | } 66 | .btn-success{ 67 | .btn; 68 | .gradient(@button-success-color, lighten(@button-success-color, 10%), @button-success-color); 69 | } 70 | .btn-warning{ 71 | .btn; 72 | .gradient(@button-warning-color, lighten(@button-warning-color, 10%), @button-warning-color); 73 | } 74 | .btn-danger{ 75 | .btn; 76 | .gradient(@button-danger-color, lighten(@button-danger-color, 10%), @button-danger-color); 77 | } 78 | 79 | /* ========================================================================== 80 | Sizes (Half = h, Single = s, Double = d) 81 | ========================================================================== */ 82 | 83 | .btn-h, .btn-half{ 84 | height: @baseline; 85 | font-size: @baseline * 0.6; 86 | line-height: @baseline; 87 | } 88 | .btn-s, .btn-single{ 89 | height: @baseline * 1.5; 90 | font-size: @baseline * 0.75; 91 | line-height: @baseline * 1.5; 92 | } 93 | .btn-d, .btn-double{ 94 | height: @baseline * 2; 95 | font-size: @baseline; 96 | line-height: @baseline * 2; 97 | } 98 | -------------------------------------------------------------------------------- /styles/base/grid.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Hybrid Grid Sytem 3 | * 4 | * Blend of the Semantic Grid System and Zurb Foundation with a little Twitter Bootstrap 5 | */ 6 | 7 | /* Settings */ 8 | 9 | @import 'variables.less'; 10 | 11 | /* 12 | @fixed-column-width: 40px; 13 | @fixed-gutter-width: 20px; 14 | @fixed-columns: 12; 15 | 16 | @fluid-column-width: 4.3%; 17 | @fluid-gutter-width: 4.4%; 18 | @fluid-columns: 12; 19 | 20 | @mobile-break-width: 480px; 21 | @mobile-column-width: 8.6%; 22 | @mobile-gutter-width: 8.8%; 23 | @mobile-columns: 6; 24 | */ 25 | 26 | /* Grid */ 27 | 28 | #grid { 29 | 30 | .cols(@cols,@width,@gutter){ 31 | .border-box(); 32 | width: ((@cols * @width) + ((@cols - 1) * @gutter)); 33 | margin-left: @gutter; 34 | position: relative; 35 | display: inline; 36 | float: left; 37 | min-height: 1px; 38 | &:first-child { 39 | margin-left: 0; 40 | } 41 | &:last-child { 42 | float: right; 43 | } 44 | } 45 | 46 | } 47 | 48 | .grid-fixed,.grid-fluid { 49 | .clearfix; 50 | .row { 51 | .border-box(); 52 | display: block; 53 | width: 100%; 54 | margin: 0 auto; 55 | .clearfix; 56 | 57 | .center,.center:last-child { 58 | float: none; 59 | display: block; 60 | margin: 0 auto; 61 | } 62 | } 63 | } 64 | 65 | .grid-fixed { 66 | @total-width: (@fixed-column-width*@fixed-columns) + (@fixed-gutter-width*(@fixed-columns - 1)); 67 | @column-width: @fixed-column-width; 68 | @gutter-width: @fixed-gutter-width; 69 | @columns: @fixed-columns; 70 | width: @total-width; 71 | 72 | /* This is duplicated in both classes. Unavoidable. */ 73 | .colX (@index) when (@index > 0) { 74 | (~".col@{index}") { 75 | #grid > .cols(@index,@column-width,@gutter-width); 76 | } 77 | .colX(@index - 1); 78 | } 79 | .colX (0) {} 80 | .colX(@columns); 81 | 82 | .offsetX (@index) when (@index > 0) { 83 | (~".offset@{index}") { 84 | margin-left: (@index * @column-width) + ((@index + 1) * @gutter-width); 85 | } 86 | .offsetX(@index - 1); 87 | } 88 | .offsetX (0) {} 89 | .offsetX(@columns - 1); 90 | 91 | .pushX (@index) when (@index > 0) { 92 | (~".push@{index}") { 93 | left: @index * (@column-width + @gutter-width); 94 | } 95 | .pushX(@index - 1); 96 | } 97 | .pushX (0) {} 98 | .pushX(@columns - 1); 99 | 100 | .pullX (@index) when (@index > 0) { 101 | (~".pull@{index}") { 102 | right: @index * (@column-width + @gutter-width); 103 | } 104 | .pullX(@index - 1); 105 | } 106 | .pullX (0) {} 107 | .pullX(@columns - 1); 108 | } 109 | 110 | 111 | .grid-fluid { 112 | @total-width: 100%; 113 | @column-width: @fluid-column-width; 114 | @gutter-width: @fluid-gutter-width; 115 | @columns: @fluid-columns; 116 | width: @total-width; 117 | 118 | /* This is duplicated in both classes. Unavoidable. */ 119 | .colX (@index) when (@index > 0) { 120 | (~".col@{index}") { 121 | #grid > .cols(@index,@column-width,@gutter-width); 122 | } 123 | .colX(@index - 1); 124 | } 125 | .colX (0) {} 126 | .colX(@columns); 127 | 128 | .offsetX (@index) when (@index > 0) { 129 | (~".offset@{index}") { 130 | margin-left: (@index * @column-width) + ((@index + 1) * @gutter-width); 131 | } 132 | .offsetX(@index - 1); 133 | } 134 | .offsetX (0) {} 135 | .offsetX(@columns - 1); 136 | 137 | .pushX (@index) when (@index > 0) { 138 | (~".push@{index}") { 139 | left: @index * (@column-width + @gutter-width); 140 | } 141 | .pushX(@index - 1); 142 | } 143 | .pushX (0) {} 144 | .pushX(@columns - 1); 145 | 146 | .pullX (@index) when (@index > 0) { 147 | (~".pull@{index}") { 148 | right: @index * (@column-width + @gutter-width); 149 | } 150 | .pullX(@index - 1); 151 | } 152 | .pullX (0) {} 153 | .pullX(@columns - 1); 154 | } 155 | 156 | 157 | @media all and (max-width: @mobile-break-width) { 158 | 159 | // Reset all columns to full width 160 | .grid-fixed { 161 | .colX (@index) when (@index > 0) { 162 | (~".col@{index}") { 163 | width: 100%; 164 | margin: 0; 165 | left: 0; 166 | right: 0; 167 | } 168 | .colX(@index - 1); 169 | } 170 | .colX (0) {} 171 | .colX(@fixed-columns); 172 | } 173 | .grid-fluid { 174 | .colX (@index) when (@index > 0) { 175 | (~".col@{index}") { 176 | width: 100%; 177 | margin: 0; 178 | left: 0; 179 | right: 0; 180 | } 181 | .colX(@index - 1); 182 | } 183 | .colX (0) {} 184 | .colX(@fluid-columns); 185 | } 186 | 187 | .grid-fixed, .grid-fluid { 188 | @total-width: 100%; 189 | @column-width: @mobile-column-width; 190 | @gutter-width: @mobile-gutter-width; 191 | @columns: @mobile-columns; 192 | width: @total-width; 193 | 194 | .m-colX (@index) when (@index > 0) { 195 | (~".m-col@{index}") { 196 | #grid > .cols(@index,@column-width,@gutter-width); 197 | } 198 | .m-colX(@index - 1); 199 | } 200 | .m-colX (0) {} 201 | .m-colX(@mobile-columns); 202 | 203 | .m-offsetX (@index) when (@index > 0) { 204 | (~".m-offset@{index}") { 205 | margin-left: (@index * @column-width) + ((@index + 1) * @gutter-width); 206 | } 207 | .m-offsetX(@index - 1); 208 | } 209 | .m-offsetX (0) {} 210 | .m-offsetX(@columns - 1); 211 | 212 | .m-pushX (@index) when (@index > 0) { 213 | (~".m-push@{index}") { 214 | left: @index * (@column-width + @gutter-width); 215 | } 216 | .m-pushX(@index - 1); 217 | } 218 | .m-pushX (0) {} 219 | .m-pushX(@columns - 1); 220 | 221 | .m-pullX (@index) when (@index > 0) { 222 | (~".m-pull@{index}") { 223 | right: @index * (@column-width + @gutter-width); 224 | } 225 | .m-pullX(@index - 1); 226 | } 227 | .m-pullX (0) {} 228 | .m-pullX(@columns - 1); 229 | } 230 | 231 | } 232 | -------------------------------------------------------------------------------- /styles/base/idioms.less: -------------------------------------------------------------------------------- 1 | /** 2 | * New Media Campaigns Idioms 3 | * 4 | * These are common patterns we use in all of our 5 | * projects. They are consolidated here to keep code DRY. 6 | * 7 | * Listing 8 | * * .no-text, .text-replace 9 | * * .no-list 10 | * * .no-form 11 | * * .fixed-width(@width) 12 | * * .column-width(@width) 13 | * * .column-left(@width) 14 | * * .column-right(@width) 15 | * * .full-size 16 | * * .absolute-default 17 | * * .absolute-fullsize 18 | * * .clearfix 19 | */ 20 | 21 | /* Hides text when using image replacement */ 22 | .no-text, .text-replace{ 23 | overflow: hidden; 24 | text-indent: 100%; 25 | white-space: nowrap; 26 | } 27 | 28 | /* Removes bullets, margin, and padding from list */ 29 | .no-list{ 30 | list-style: none; 31 | margin: 0; 32 | padding: 0; 33 | } 34 | 35 | /* Removes webkit styling from form element */ 36 | .no-form{ 37 | border: none; 38 | margin: 0; 39 | padding: 0; 40 | -webkit-appearance: none; 41 | } 42 | 43 | /* Center a fixed width container */ 44 | .fixed-width(@width) { 45 | margin: 0 auto; 46 | width: @width; 47 | } 48 | 49 | /* Adds left or right columns (e.g. content and sidebar) */ 50 | .column-width(@width){ 51 | display: inline; 52 | width: @width; 53 | } 54 | .column-left(@width){ 55 | .column-width(@width); 56 | float: left; 57 | } 58 | .column-right(@width){ 59 | .column-width(@width); 60 | float: right; 61 | } 62 | 63 | /* Set width and height of element to that of its parent */ 64 | .full-size{ 65 | height: 100%; 66 | width: 100%; 67 | } 68 | 69 | /* Position element absolutely to 0,0 */ 70 | .absolute-default{ 71 | position: absolute; 72 | left: 0; 73 | top: 0; 74 | } 75 | 76 | /* Position element absolutely and set its width and height to that of its parent (useful for slideshows) */ 77 | .absolute-fullsize{ 78 | .absolute-default; 79 | .full-size; 80 | } 81 | 82 | /* The micro clearfix http://nicolasgallagher.com/micro-clearfix-hack/ */ 83 | .clearfix { 84 | *zoom:1; 85 | 86 | &:before, 87 | &:after { 88 | content:""; 89 | display:table; 90 | } 91 | &:after { 92 | clear:both; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /styles/base/reset.less: -------------------------------------------------------------------------------- 1 | /** 2 | * html5doctor.com Reset Stylesheet 3 | * v1.6.1 4 | * Last Updated: 2010-09-17 5 | * Author: Richard Clark - http://richclarkdesign.com 6 | * Twitter: @rich_clark 7 | */ 8 | 9 | html, body, div, span, object, iframe, 10 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 11 | abbr, address, cite, code, 12 | del, dfn, em, img, ins, kbd, q, samp, 13 | small, strong, sub, sup, var, 14 | b, i, 15 | dl, dt, dd, ol, ul, li, 16 | fieldset, form, label, legend, 17 | table, caption, tbody, tfoot, thead, tr, th, td, 18 | article, aside, canvas, details, figcaption, figure, 19 | footer, header, hgroup, menu, nav, section, summary, 20 | time, mark, audio, video { 21 | margin:0; 22 | padding:0; 23 | border:0; 24 | outline:0; 25 | font-size:100%; 26 | vertical-align:baseline; 27 | background:transparent; 28 | } 29 | 30 | body { 31 | line-height:1; 32 | } 33 | 34 | article,aside,details,figcaption,figure, 35 | footer,header,hgroup,menu,nav,section { 36 | display:block; 37 | } 38 | 39 | nav ul { 40 | list-style:none; 41 | } 42 | 43 | blockquote, q { 44 | quotes:none; 45 | } 46 | 47 | blockquote:before, blockquote:after, 48 | q:before, q:after { 49 | content:''; 50 | content:none; 51 | } 52 | 53 | a { 54 | margin:0; 55 | padding:0; 56 | font-size:100%; 57 | vertical-align:baseline; 58 | background:transparent; 59 | } 60 | 61 | /* change colours to suit your needs */ 62 | ins { 63 | background-color:#ff9; 64 | color:#000; 65 | text-decoration:none; 66 | } 67 | 68 | /* change colours to suit your needs */ 69 | mark { 70 | background-color:#ff9; 71 | color:#000; 72 | font-style:italic; 73 | font-weight:bold; 74 | } 75 | 76 | del { 77 | text-decoration: line-through; 78 | } 79 | 80 | abbr[title], dfn[title] { 81 | border-bottom:1px dotted; 82 | cursor:help; 83 | } 84 | 85 | table { 86 | border-collapse:collapse; 87 | border-spacing:0; 88 | } 89 | 90 | /* change border colour to suit your needs */ 91 | hr { 92 | display:block; 93 | height:1px; 94 | border:0; 95 | border-top:1px solid #cccccc; 96 | margin:1em 0; 97 | padding:0; 98 | } 99 | 100 | input, select { 101 | vertical-align:middle; 102 | } 103 | -------------------------------------------------------------------------------- /styles/base/spacing.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Spacing 3 | * 4 | * This LESS file defines margins and paddings for block-level 5 | * elements. Helper classes are included for use elsewhere 6 | * in site styles. 7 | */ 8 | 9 | /* Settings */ 10 | 11 | @import 'variables.less'; 12 | 13 | /* 14 | @baseline: @baseline; 15 | */ 16 | 17 | /** 18 | * Spacing 19 | * p, m, lh = padding, margin, line-height 20 | * a, t, r, b, l, h, v = all, top, right, bottom, left, horizontal, vertical 21 | * n, h, s, d = none(0px), half(@baseline / 2), single(@baseline), double(@baseline * 2), none(0px) 22 | */ 23 | 24 | .ptn, .pvn, .pan{ 25 | padding-top: 0 !important 26 | } 27 | .pth, .pvh, .pah{ 28 | padding-top: @baseline / 2 !important 29 | } 30 | .pts, .pvs, .pas{ 31 | padding-top: @baseline !important 32 | } 33 | .ptd, .pvd, .pad{ 34 | padding-top: @baseline * 2 !important 35 | } 36 | .prn, .phn, .pan{ 37 | padding-right: 0 !important 38 | } 39 | .prh, .phh, .pah{ 40 | padding-right: @baseline / 2 !important 41 | } 42 | .prs, .phs, .pas{ 43 | padding-right: @baseline !important 44 | } 45 | .prd, .phd, .pad{ 46 | padding-right: @baseline * 2 !important 47 | } 48 | .pbn, .pvn, .pan{ 49 | padding-bottom: 0 !important 50 | } 51 | .pbh, .pvh, .pah{ 52 | padding-bottom: @baseline / 2 !important 53 | } 54 | .pbs, .pvs, .pas{ 55 | padding-bottom: @baseline !important 56 | } 57 | .pbd, .pvd, .pad{ 58 | padding-bottom: @baseline * 2 !important 59 | } 60 | .pln, .phn, .pan{ 61 | padding-left: 0 !important 62 | } 63 | .plh, .phh, .pah{ 64 | padding-left: @baseline / 2 !important 65 | } 66 | .pls, .phs, .pas{ 67 | padding-left: @baseline !important 68 | } 69 | .pld, .phd, .pad{ 70 | padding-left: @baseline * 2 !important 71 | } 72 | .mtn, .mvn, .man{ 73 | margin-top: 0 !important 74 | } 75 | .mth, .mvh, .mah{ 76 | margin-top: @baseline / 2 !important 77 | } 78 | .mts, .mvs, .mas{ 79 | margin-top: @baseline !important 80 | } 81 | .mtd, .mvd, .mad{ 82 | margin-top: @baseline * 2 !important 83 | } 84 | .mrn, .mhn, .man{ 85 | margin-right: 0 !important 86 | } 87 | .mrh, .mhh, .mah{ 88 | margin-right: @baseline / 2 !important 89 | } 90 | .mrs, .mhs, .mas{ 91 | margin-right: @baseline !important 92 | } 93 | .mrd, .mhd, .mad{ 94 | margin-right: @baseline * 2 !important 95 | } 96 | .mbn, .mvn, .man{ 97 | margin-bottom: 0 !important 98 | } 99 | .mbh, .mvh, .mah{ 100 | margin-bottom: @baseline / 2 !important 101 | } 102 | .mbs, .mvs, .mas{ 103 | margin-bottom: @baseline !important 104 | } 105 | .mbd, .mvd, .mad{ 106 | margin-bottom: @baseline * 2 !important 107 | } 108 | .mln, .mhn, .man{ 109 | margin-left: 0 !important 110 | } 111 | .mlh, .mhh, .mah{ 112 | margin-left: @baseline / 2 !important 113 | } 114 | .mls, .mhs, .mas{ 115 | margin-left: @baseline !important 116 | } 117 | .mld, .mhd, .mad{ 118 | margin-left: @baseline * 2 !important 119 | } 120 | .lhh { 121 | line-height: @baseline / 2 !important; 122 | } 123 | .lhs { 124 | line-height: @baseline !important; 125 | } 126 | .lhd { 127 | line-height: @baseline * 2 !important; 128 | } 129 | .lhn { 130 | line-height: 0 !important; 131 | } 132 | -------------------------------------------------------------------------------- /styles/base/typography.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Name Here 3 | * 4 | * @version 1.0 5 | * @package Name Here 6 | * @author New Media Campaigns 7 | * @copyright 2012 New Media Campaigns 8 | * @link http://www.newmediacampaigns.com 9 | * 10 | * Copyright (c) 2012 New Media Campaigns 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is furnished 17 | * to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in all 20 | * copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | */ 30 | 31 | /** 32 | * Typography 33 | * 34 | * This LESS file defines the baseline, color, font-size, and other typographical 35 | * styles for text elements. 36 | */ 37 | 38 | /* Settings */ 39 | 40 | @import 'variables.less'; 41 | 42 | /* 43 | @baseline: @baseline; 44 | 45 | @body-color: @body-color; 46 | @body-font-family: @body-font-family; 47 | @body-font-size: @body-font-size; 48 | @body-accent-color: @body-accent-color; 49 | 50 | @header-color: @header-clor; 51 | @header-font-family: @header-font-family; 52 | @header-font-weight: @header-font-weight; 53 | */ 54 | 55 | /* Base */ 56 | 57 | html, body { 58 | font-family: @body-font-family; 59 | color: @body-color; 60 | font-size: @body-font-size; 61 | .lhs; 62 | } 63 | 64 | /* Block-level */ 65 | 66 | h1, h2, h3, h4, h5, h6, ul, ol, dl, p, blockquote, table, form, pre{ 67 | .mbs; 68 | } 69 | 70 | /* Headers */ 71 | 72 | .all-headers{ 73 | color: @header-color; 74 | font-family: @header-font-family; 75 | font-weight: @header-font-weight; 76 | } 77 | h1, .alpha{ 78 | .all-headers; 79 | font-size: @body-font-size * 2.5; 80 | .lhd; 81 | } 82 | h2, .beta{ 83 | .all-headers; 84 | font-size: @body-font-size * 1.75; 85 | .lhd; 86 | } 87 | h3, .gamma{ 88 | .all-headers; 89 | font-size: @body-font-size * 1.2; 90 | .lhd; 91 | .mbn; 92 | } 93 | h4, .delta{ 94 | .all-headers; 95 | font-size: @body-font-size * 1; 96 | .lhd; 97 | .mbn; 98 | } 99 | h5, .epsilon{ 100 | .all-headers; 101 | font-size: @body-font-size * 1; 102 | .lhs; 103 | .mbn 104 | } 105 | h6, .zeta{ 106 | .all-headers; 107 | font-size: @body-font-size * 1; 108 | .lhs; 109 | .mbn; 110 | } 111 | 112 | /* Headers (above scale) */ 113 | 114 | .giga{ 115 | .all-headers; 116 | font-size: @body-font-size * 6; 117 | line-height: @baseline * 4; 118 | } 119 | .mega{ 120 | .all-headers; 121 | font-size: @body-font-size * 5; 122 | line-height: @baseline * 3; 123 | } 124 | .kilo{ 125 | .all-headers; 126 | font-size: @body-font-size * 4; 127 | line-height: @baseline * 3; 128 | } 129 | 130 | /* Headers (below scale) */ 131 | 132 | .milli{ 133 | .all-headers; 134 | font-size: @body-font-size * 0.8; 135 | } 136 | 137 | /* Text */ 138 | 139 | a{ 140 | color: @body-accent-color; 141 | } 142 | a:link{ 143 | text-decoration: underline; 144 | } 145 | a:visited{ 146 | 147 | } 148 | a:hover{ 149 | text-decoration: none; 150 | } 151 | a:active{ 152 | 153 | } 154 | a:focus{ 155 | 156 | } 157 | small { 158 | font-size: 80%; 159 | } 160 | sup, sub { 161 | font-size: 80%; 162 | .lhn; 163 | } 164 | sup { 165 | vertical-align: super; 166 | } 167 | sub { 168 | vertical-align: sub; 169 | } 170 | 171 | .lead{ 172 | color: darken(@body-color, 20%); 173 | font-size: @baseline * 0.8; 174 | } 175 | 176 | blockquote{ 177 | border-left: 5px solid fade(#000, 10%); 178 | .mhs; 179 | .pls; 180 | color: lighten(@body-color, 20%); 181 | font-size: @baseline * 0.8; 182 | font-style: italic; 183 | 184 | :last-child{ 185 | .mbn; 186 | } 187 | small{ 188 | color: fade(#000, 50%); 189 | font-size: @baseline * 0.7; 190 | font-style: normal; 191 | } 192 | } 193 | pre, code, kbd{ 194 | background: #F8F8F8; 195 | border: 1px solid #EAEAEA; 196 | .border-radius(3px); 197 | margin: 0 2px; 198 | padding: 0 5px; 199 | font-family: Consolas, "Courier New", Courier, mono; 200 | font-size: @body-font-size * 0.9; 201 | color: @body-color; 202 | word-wrap: break-word; 203 | } 204 | pre{ 205 | .mhs; 206 | .pah; 207 | 208 | code{ 209 | border: none; 210 | .man; 211 | .pan; 212 | } 213 | } 214 | a code{ 215 | background: none; 216 | border: none; 217 | .pan; 218 | .man; 219 | } 220 | strong{ 221 | font-weight: bold; 222 | } 223 | em{ 224 | font-style: italic; 225 | } 226 | ol, ul, dl{ 227 | .mls; 228 | .pls; 229 | ol,ul { 230 | .mbn; 231 | } 232 | } 233 | dt{ 234 | font-weight: bold; 235 | } 236 | dd{ 237 | .mls; 238 | } 239 | 240 | .table{ 241 | border-collapse: collapse; 242 | border-spacing: 0; 243 | width: 100%; 244 | } 245 | .table th, .table td{ 246 | border-top: 1px solid fade(#000, 10%); 247 | padding: 8px; 248 | text-align: left; 249 | } 250 | .table thead th{ 251 | vertical-align: bottom; 252 | font-weight: bold; 253 | } 254 | .table thead tr:first-child th{ 255 | border-top: none; 256 | } 257 | .table-bordered{ 258 | border: 1px solid fade(#000, 10%); 259 | border-collapse: separate; 260 | border-left: none; 261 | .border-radius(4px); 262 | 263 | th, td{ 264 | border-left: 1px solid fade(#000, 10%); 265 | } 266 | thead:last-child tr:last-child th:first-child, 267 | tbody:last-child tr:last-child td:first-child{ 268 | .border-radius(0 0 0 4px); 269 | } 270 | } 271 | .table-striped{ 272 | tbody tr:nth-child(odd) td{ 273 | background: fade(@body-accent-color, 4%); 274 | } 275 | } 276 | 277 | /* ========================================================================== 278 | Alerts 279 | ========================================================================== */ 280 | 281 | .alert{ 282 | background: #FCF8E3; 283 | border: 1px solid #FBEED5; 284 | .border-radius(4px); 285 | .mbs; 286 | .pah; 287 | color: #C09853; 288 | } 289 | .alert-success{ 290 | .alert; 291 | background-color: #DFF0D8; 292 | border-color: #D6E9C6; 293 | color: #468847; 294 | } 295 | .alert-error{ 296 | .alert; 297 | background-color: #F2DEDE; 298 | border-color: #EED3D7; 299 | color: #B94A48; 300 | } 301 | .alert-info{ 302 | .alert; 303 | background-color: #D9EDF7; 304 | border-color: #BCE8F1; 305 | color: #3A87AD; 306 | } 307 | 308 | /* ========================================================================== 309 | Forms 310 | ========================================================================== */ 311 | 312 | label{ 313 | display: block; 314 | font-weight: bold; 315 | 316 | .req{ 317 | color: @body-accent-color; 318 | font-weight: bold; 319 | } 320 | } 321 | input.text, 322 | textarea, 323 | select, 324 | .radio-group, 325 | .checkbox-group{ 326 | .mbs; 327 | } 328 | input.text, textarea{ 329 | .no-form; 330 | background: #EEE; 331 | border: 1px solid #CCC; 332 | .border-box; 333 | .border-radius(4px); 334 | .inner-shadow(fade(#000, 10%) 0 1px 3px); 335 | height: @baseline * 1.5; 336 | .pah; 337 | width: 100%; 338 | } 339 | textarea{ 340 | height: @baseline * 6; 341 | } 342 | select{ 343 | min-width: 30%; 344 | } 345 | .checkbox-group label, 346 | .radio-group label{ 347 | font-weight: normal; 348 | } 349 | .error{ 350 | background-color: #F2DEDE !important; 351 | border-color: red !important; 352 | outline-color: red !important; 353 | color: red !important; 354 | } 355 | -------------------------------------------------------------------------------- /styles/base/variables.less: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Spacing 3 | ========================================================================== */ 4 | 5 | @baseline: 20px; 6 | 7 | /* ========================================================================== 8 | Typography 9 | ========================================================================== */ 10 | 11 | @body-color: #555; 12 | @body-font-family: "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, "Lucida Grande", sans-serif; 13 | @body-font-size: 14px; 14 | @body-accent-color: #f00; 15 | 16 | @header-color: #000; 17 | @header-font-family: "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, "Lucida Grande", sans-serif; 18 | @header-font-weight: bold; 19 | 20 | /* ========================================================================== 21 | Grid 22 | ========================================================================== */ 23 | 24 | @fixed-column-width: 40px; 25 | @fixed-gutter-width: 20px; 26 | @fixed-columns: 12; 27 | 28 | @fluid-column-width: 4.3%; 29 | @fluid-gutter-width: 4.4%; 30 | @fluid-columns: 12; 31 | 32 | @mobile-break-width: 480px; 33 | @mobile-column-width: 20%; 34 | @mobile-gutter-width: 6.6666%; 35 | @mobile-columns: 4; 36 | 37 | /* ========================================================================== 38 | Buttons 39 | ========================================================================== */ 40 | 41 | @button-color: #DDD; 42 | @button-primary-color: #0055CC; 43 | @button-info-color: #2F96B4; 44 | @button-success-color: #51A351; 45 | @button-warning-color: #FAA732; 46 | @button-danger-color: #BD362F; 47 | 48 | /* ========================================================================== 49 | Site Variables 50 | ========================================================================== */ 51 | 52 | @import "../site/variables"; 53 | -------------------------------------------------------------------------------- /styles/print.css: -------------------------------------------------------------------------------- 1 | body, .site-title, h1, h2, h3{ 2 | font-family: 'Georgia' !important; 3 | } 4 | 5 | 6 | nav.site-navigation, a.fork-me, a.top{ 7 | display:none; 8 | } 9 | 10 | div.site-content{ 11 | padding: 20px 40px 40px 20px; 12 | } 13 | -------------------------------------------------------------------------------- /styles/site/site-content.less: -------------------------------------------------------------------------------- 1 | .site-content{ 2 | padding: 20px 40px 40px 320px; 3 | 4 | h1{ 5 | clear: both; 6 | } 7 | } 8 | .interior-site-content{ 9 | .pad; 10 | } 11 | .top{ 12 | background: #333; 13 | display: inline-block; 14 | float: right; 15 | margin-right: -40px; 16 | padding: 4px 8px; 17 | color: #FFF; 18 | font-size: 12px; 19 | text-decoration: none !important; 20 | } 21 | -------------------------------------------------------------------------------- /styles/site/site-footer.less: -------------------------------------------------------------------------------- 1 | .site-footer{ 2 | clear: both; 3 | .ptd; 4 | font-size: 13px; 5 | text-align: center; 6 | } 7 | .site-footer img{ 8 | margin-left: 2px; 9 | position: relative; 10 | top: -2px; 11 | vertical-align: middle; 12 | } 13 | .site-footer ul{ 14 | list-style: none; 15 | .mhn; 16 | .phn; 17 | } 18 | -------------------------------------------------------------------------------- /styles/site/site-header.less: -------------------------------------------------------------------------------- 1 | .site-header{ 2 | position: relative; 3 | z-index: 1; 4 | text-align: center; 5 | } 6 | .site-title{ 7 | .mbn; 8 | font-family: 'Alfa Slab One'; 9 | font-size: @baseline * 4; 10 | font-weight: normal !important; 11 | line-height: @baseline * 5 !important; 12 | 13 | a{ 14 | text-decoration: none; 15 | } 16 | } 17 | .site-slogan{ 18 | font-weight: normal; 19 | } 20 | .fork-me, .fork-me img{ 21 | position: absolute; 22 | top: 0; 23 | right: 0; 24 | } 25 | .fork-me{ 26 | z-index: 2; 27 | } 28 | 29 | .interior-site-header{ 30 | background: #EEE; 31 | .inner-shadow(fade(#000, 7%) 0 0 40px); 32 | .pas; 33 | text-align: center; 34 | 35 | .site-title{ 36 | font-size: @baseline * 2; 37 | line-height: @baseline * 2 !important; 38 | } 39 | .site-slogan{ 40 | .mbs; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /styles/site/site-navigation.less: -------------------------------------------------------------------------------- 1 | .site-navigation{ 2 | background: #EEE; 3 | .inner-shadow(fade(#000, 7%) 0 0 40px); 4 | .pas; 5 | position: fixed; 6 | top: 0; 7 | bottom: 0; 8 | overflow: auto; 9 | width: 240px; 10 | } 11 | .build-date{ 12 | .mbs; 13 | color: #AAA; 14 | font-family: Helvetica, Arial, sans-serif; 15 | font-size: 11px; 16 | } 17 | .site-navigation ul{ 18 | .man; 19 | .pan; 20 | .no-list; 21 | font-size: 16px; 22 | margin-bottom: 10px; 23 | } 24 | .site-navigation > ul > li{ 25 | margin-bottom: 10px; 26 | } 27 | .site-navigation a{ 28 | text-decoration: underline; 29 | 30 | &:hover{ 31 | text-decoration: none; 32 | } 33 | } 34 | .site-navigation a.active{ 35 | background-color: #ff9; 36 | } 37 | .site-navigation ul ul{ 38 | .mls; 39 | .pth; 40 | font-size: 12px; 41 | 42 | a{ 43 | text-decoration: none; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /styles/site/variables.less: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Spacing 3 | ========================================================================== */ 4 | 5 | @baseline: 20px; 6 | 7 | /* ========================================================================== 8 | Typography 9 | ========================================================================== */ 10 | 11 | @body-color: #666; 12 | @body-font-family: "Droid Serif", Georgia, "Times New Roman", Times, serif; 13 | @body-font-size: 14px; 14 | @body-accent-color: #000; 15 | 16 | @header-color: #111; 17 | @header-font-family: "Droid Serif", Georgia, "Times New Roman", Times, serif; 18 | @header-font-weight: 700; 19 | 20 | /* ========================================================================== 21 | Grid 22 | ========================================================================== */ 23 | 24 | @fixed-column-width: 60px; 25 | @fixed-gutter-width: 20px; 26 | @fixed-columns: 12; 27 | 28 | @fluid-column-width: 4.3%; 29 | @fluid-gutter-width: 4.4%; 30 | @fluid-columns: 12; 31 | 32 | @mobile-break-width: 480px; 33 | @mobile-column-width: 20%; 34 | @mobile-gutter-width: 6.6666%; 35 | @mobile-columns: 4; 36 | 37 | /* ========================================================================== 38 | Buttons 39 | ========================================================================== */ 40 | 41 | @button-color: #DDD; 42 | @button-primary-color: #0055CC; 43 | @button-info-color: #2F96B4; 44 | @button-success-color: #51A351; 45 | @button-warning-color: #FAA732; 46 | @button-danger-color: #BD362F; 47 | -------------------------------------------------------------------------------- /styles/syntax.css: -------------------------------------------------------------------------------- 1 | .highlight { background: #ffffff; margin: 0 4px; font-size: 0.8em; } 2 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 3 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 4 | .highlight .k { font-weight: bold } /* Keyword */ 5 | .highlight .o { font-weight: bold } /* Operator */ 6 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 7 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 8 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 9 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 10 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 11 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 14 | .highlight .gh { color: #999999 } /* Generic.Heading */ 15 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 16 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 17 | .highlight .go { color: #888888 } /* Generic.Output */ 18 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 19 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 20 | .highlight .gu { color: #aaaaaa } /* Generic.Subheading */ 21 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 22 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 23 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 24 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 25 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 26 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 27 | .highlight .m { color: #009999 } /* Literal.Number */ 28 | .highlight .s { color: #d14 } /* Literal.String */ 29 | .highlight .na { color: #008080 } /* Name.Attribute */ 30 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 31 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 32 | .highlight .no { color: #008080 } /* Name.Constant */ 33 | .highlight .ni { color: #800080 } /* Name.Entity */ 34 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 35 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 36 | .highlight .nn { color: #555555 } /* Name.Namespace */ 37 | .highlight .nt { color: #000080 } /* Name.Tag */ 38 | .highlight .nv { color: #008080 } /* Name.Variable */ 39 | .highlight .ow { font-weight: bold } /* Operator.Word */ 40 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 41 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 42 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 43 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 44 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 45 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 46 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 47 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 48 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 49 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 50 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 51 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 52 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 53 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 54 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 55 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 56 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 57 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 58 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 59 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 60 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ 61 | --------------------------------------------------------------------------------