Injustice - Developers Among Us (SciFiDevCon 2024)
PM : code faster
1. PM* : « code faster »
PHP User Group – Bordeaux, France
2011-04-13
Olivier HOAREAU, PHPPRO
* = « Project Manager » or « PHP Metaframework »
PM v0.1.0
2. What is PM ?
# PM seems to be a basic command line tool …
$ pm <command>
ok, but, it’s also …
• … a generic command line “shortcuts / aliases” maker / runner
• … a generic packager (.tgz / .zip / .phar / pear) for your app
• … a generic custom code generator using your templates
• … a set of predefined popular commands based on project type detection
• … an external dependencies loader (.tgz / .phar / .zip)
• … a “use it in your language” tool (at least, not only English ;) )
• … an extensible tool based on PHP 5.3+
• … the best friend of Hudson/Jenkins and others for PHP Projects ;)
• … and a lot more (i.e. use it for your custom needs) !
3. OK, but I am already using <whatever>
framework, so why switch to PM ?
• PM is not a conventional framework, you don’t need to switch :
– Designed to work with all kind of projects :
• No framework projects
• Zend Framework projects
• Symfony projects
• CakePHP, and others !
– Designed to « alias » your framework’s commands for you to keep your
popular « commands » from one framework to an other (ex: from ZF to
SF !) and to « map » your source tree layout
– Designed to work out of the box (almost !) on any PHP project, even PHP
projects not using PHP 5.3+ !*
* = you will need to have the PHP 5.3+ cli available on your system at least
4. Interested ? Start using PM !
# go to your existing project directory or create one
$ cd my-existing-project
# download pm.phar file at (or github.com/phppro/pm and’ download’)
https://github.com/downloads/phppro/pm/pm.phar
# enable pm support on your project
$ php pm.phar enable
# execute pm for the first time on your project !
$ pm
# begin customizing with your needs !
$ vi project.php
5. Not using PHP 5.3+ on your app ?
# install PHP 5.3+ as an extra version (recompile on linux)
# enable pm support on your project
$ <path/to/php/5.3>php pm.phar enable
# edit ‘pm’ or ‘pm.bat’ shell script to replace full path for php
# use pm !
$ pm
6. Linux users or others, install system-wide
to avoid ./pm instead of pm
# put ‘pm’ (or pm.bat on windows) in some central directory
$ sudo mkdir /opt/pm
$ sudo cp pm /opt/pm/
$ sudo chmod +x /opt/pm/pm
# optional: put pm.phar in some central directory
$ sudo cp pm.phar /opt/pm/
# then replace pm.phar in ‘pm’ or ‘pm.bat’ by ‘/opt/pm/pm.phar’
# update your $PATH system variable to add /opt/pm directory
# use pm !
$ pm
7. List available commands
# list your bookmarked commands
$ pm
# list all available commands
$ pm -h
# get help on how to use command « tpl »
$ pm -h tpl
# list all available commands that are prefixed with « t »
$ pm -h t
8. Execute an existing command / alias
# Syntax: pm [common-options] <action> [action-options]
$ pm pkg
$ pm -d display_errors=On audit:cpd
$ pm tu MyClass
$ pm tpl mytemplate --my.variable=theValue
$ pm -o new
9. Use interactive mode (aka « pm shell »)
# open PM in interactive mode
$ pm -i
PM> -h
PM> tu
…
# quit PM in interactive mode
PM> quit
10. Add a custom command alias
# edit your configuration file
$ vi project.php
---
<?php
return array(
‘aliases.list’ => array(
‘co’ => ‘!svn commit’,
),
);
# use your new alias now !
$ pm co
11. Create a new custom command
# create an new command called ‘my:personal-action’ with some example of primitive you can use inside
$ pm new my:personal-action --example
#read the example provided in the generated class and customize your logic
$ vi _pm/actions/My/PersonalAction.php
---
<?php
…
class PersonalAction extends PMAction {
public function run() {
if (false === $this->confirm(‘Are your sure’) ) return;
$feature = new MyClass($this->cfg (‘some.config.key’));
$feature->doSomething($this->arg());
}
}
# use your new command now !
$ pm my:personal-action
$ pm -o my:personal-action
12. Create a new inline (closure) command
# add directly your inline command to your project.php
$ vi project.php
---
<?php
return array(
‘aliases.list’ => array(
‘replace’ => function ($args) {
echo str_replace($args[0], $args[1], $args[2]);
},
),
);
# use your new command now !
$ pm replace ab cd abcdef
13. Bookmark popular project commands
# add your popular project commands to the list
$ vi project.php
---
<?php
return array(
‘bookmarks.list’ => array(
‘unit tests’ => ‘pm tu’,
‘commit’ => ‘pm co’,
‘the very important command to keep in mind’ => ‘do-something’,
…
),
);
# at anytime, list your bookmarked commands easily !
$ pm
14. Create a new code template
# create an new empty template called ‘my-tpl’ using example
$ pm tpl:new my-tpl --example
# … read generated example in _pm/templates/my-tpl
# … customize your template content
$ mkdir _pm/templates/my-tpl/sources
$ vi _pm/templates/my-tpl/sources/%{pm.ucfirst@class.name}.php
---
<?php
class %{pm.ucfirst@class.name} { … }
# use your new template now ! (--class.name=… is optional)
$ pm tpl my-tpl --class.name=MyClass
15. Executing unit tests
(using installed PHPUnit tool)
# customizing the location of your unit tests (PHPUnit)
$ vi project.php
---
<?php
return array(
…
‘paths.list’ => array(
‘tests/unit/php’ => ‘test/library’,
…
),
);
# execute unit tests in test/library/MyClassTest.php now !
$ pm tu
$ pm tu MyClass
16. Customizing an existing command
# replace existing command by yours
$ vi project.php
---
<?php
return array(
‘aliases.list’ => array(
‘tu’ => ‘atoum %{0|.}’,
…
),
);
# execute your customized command now ! (« atoum MyClass »)
$ pm tu MyClass
17. Enabling logging/trace for a command
# execute your command with debug log enabled
$ pm -o tu
# execute your command with hard-core log enabled
$ pm -e tu
# execute your command by tracing all io.* as info
$ pm -t io=info tu
# execute your command by logging all notice (and above)
$ pm --verbose=notice tu
18. Use PM in your language (if exists ;))
# execute your command in french (if translated…)
$ pm -l=fr-fr tu
# force using french for all team member of the project
$ vi project.php
---
<?php
return array(
…
‘lang’ => ‘fr-fr’,
…
);
$ pm tu
19. Upgrade your database using scripts
# create repository for your differentials scripts
$ pm db:repo:create configs/mysql
# creates differentials scripts for your database
$ vi configs/mysql/2/01_all_schema_create_products_table.sql
---
-- dump the content of your differential script here
# set your database credentials and location in your configuration
$ vi project.php
---
<?php
return array(
‘databases.list’ => …
…
Soon available …
);
# upgrade your database using differential scripts
$ pm db:up
20. Audit your code
# first, index your source code
$ pm source:index
Soon available …
# then, request the index …
# … to list biggest method (in lines) using predefined queries …
$ pm source:query methods.biggest
# … or using pure sql
$ pm source:query "SELECT name FROM methods ORDER BY DESC lines LIMIT 0,10"
# … to get the size per file extension
$ pm source:query "SELECT size FROM files GROUP BY extension"
# … same but exported in CSV
$ pm source:query "SELECT size FROM files GROUP BY extension" --format=csv
21. Adds conditional features
# example: add ‘co’ alias to commit only if svn client available
$ vi project.php
---
…
‘conditional.sets.list’ => array( assertTreeContains
… assertTreeNotContains
'svn' => 'assertTreeContains:.svn', assertSystemPathContainsOne
… assertContextFlagExists
), assertContextContains
‘svn.sets.list’ => array( …
‘aliases.list’ => array(
‘co’ => ‘!svn commit’,
),
),
…
# if your project is « subversionned » (i.e. you have a .svn directory), use :
$ pm co
22. Adds environment specific features
# example: add ‘cache:clean’ alias only on your integration server
$ vi project.php
---
…
‘environments.list’ => array(
…
‘integ-01‘ => array(
‘aliases.list’ => array(
‘cache:clean’ => ‘!rm –rf /tmp/myapp/cache’,
),
),
…
),
# on your integration server ‘integ-01’, you can now use your command:
$ pm --env=integ-01 cache:clean
# to autodetect the environment, use the ‘COMPUTERNAME’ environment variable
$ export COMPUTERNAME=integ-01
$ pm cache:clean
23. Adds user specific features
# example: replaces an existing ‘co’ alias by yours only for the user ‘ohoareau‘:
$ vi project.php
---
‘users.list’ => array(
‘ohoareau‘ => array(
‘aliases.list’ => array(
‘co’ => ‘!my-specific-co-command’,
),
‘user.name’ => ‘Olivier Hoareau’,
‘user.email’ => ‘something@example.com’,
‘company.name’ => ‘PHPPRO’,
‘company.website’ => ‘http://www.phppro.fr’,
‘lang’ => ‘fr-fr’,
),
),
# you can now use your command:
$ pm --user=ohoareau co
# to autodetect the current user, use the ‘USERNAME’ environment variable
$ export USERNAME=ohoareau
$ pm co
24. Translates (pm) messages
in your language
# generates a stub for your translation file
$ pm :i18n:new de-de --from=fr-fr
# edit your locale file and translate messages
$ vi _pm/i18n/de-de.php
# send us your locale file _pm/i18n/de-de.php !
26. As a developer, I want to maintain « textual »
specification of my application and distribute
it in PDF
# example: using latex (or markdown, or some other transformable text format) :
$ vi project.php
---
‘aliases.list’ => array(
‘spec:gen‘ => ‘!pdflatex %{/docs/latex}/%{0}.tex --output-
directory=%{/docs/generated}’,
),
),
# then, edit your latex files…
# then « generate » pdf from your latex file
$ pm spec:gen feature-xyz
# then send it by mail !
$ pm email:file docs/generated/feature-xyz.pdf boss@mycompany.com
27. As a developer, I want to svn update, execute
unit tests before committing in one single
command
# add your custom « sequence » command to your project
$ vi project.php
---
‘aliases.list’ => array(
‘c‘ => array(‘up’, ‘tu’, ‘co’),
),
# then use your alias to code faster !
$ pm c
28. As an open source project lead developer, I
want to package my development into a PEAR-
compatible package in one single command
# specify the list of directories to include
$ vi project.php
---
‘includepaths.list’ => array(
Beta
‘library’,
),
# then package !
$ pm pkg --format=pear --version=1.12.3-RC3
# then install / distribute your PEAR compatible package
$ pear install builds/zend-framework-1.12.3-RC3.tgz
29. Other real life examples …
• Generate empty controller / model using default comments
and current user info
• Generate model classes using an existing database (tables)
using custom tree template
• Update local database directly after a svn update (post-
update script)
• List all available useful commands on the project for new
incoming developers
• Use same commands on local desktop and on integration
server (maintenance purpose)
• …
31. Todo
• Full support for popular frameworks (ZF, Symfony, CakePHP…)
• Standalone pm.exe containing PHP 5.3 (+dlls) !
• Hard core unit test coverage (code is designed for that)
• Debian package + repository for PM
• PEAR package for PM (80% done)
• Plugin support + Plugin development kit
• Ability to share your alias / command with others
• Windows installer optionally installing PHP 5.3
• PM documentation online
• PM web hub
• XML / Ini configuration file format (project.xml / project.ini)
• Ability to manage project using other technology than PHP
• Non regression tests on PM core features
• Provide Jenkins (Hudson) plugin for PM