I'm deploying a PHP app to Heroku using Composer. Currently I'm using Gulp to compress CSS/JS and commit it to the Git repository. I was wondering if it makes more sense to run the Gulp tasks using Composer's post-install-cmd. What is the best practice for that?
You use the so-called "multi-buildpack" to perform both a Node.js (to install Gulp) and PHP build upon deploy.
Here's an example I built a while ago that uses Bower to install Bootstrap in a Composer post-install-cmd, but the principle is going to be the same:
http://heroku-multipack-nodejs-php-ex.herokuapp.com
Sources with README that explains the process: https://github.com/dzuelke/heroku-multipack-nodejs-php-example
You can also use the composer compile step if you prefer the Gulp install not to run on each composer install: https://devcenter.heroku.com/articles/php-support#custom-compile-step
Think of Gulp as an all-purpose task-runner, rather than using Composer's post-install-cmd (or similar) to bolt on additional tasks. A PHP package manager shouldn't be responsible for fetching or compressing front-end assets, that's not its job. Gulp isn't just for front-end-related tasks.
To me, using gulp-composer makes the most sense.
gulp provides flexible tools for command tasks, so perhaps, the best practice is to use gulp for update or install composer dependencies?
Take a look at this gulp-composer package
Example:
composer = require('gulp-composer');
gulp.task('composer', function () {
composer({ cwd: './php-stuff', bin: 'composer' });
});
I'd recommend using Symfony's Process Component for that inside some script handler and then run that as post-install-cmd as you said.
scripts/composer/ScriptHandler.php
use Composer\Script\Event;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class ScriptHandler {
public static function gulpBuild(Event $event) {
$process = new Process('cd /path/to/my/theme && gulp build');
$process->run();
// executes after the command finishes
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
$event->getIO()->write($process->getOutput());
}
else {
$event->getIO()->write("Recompiled and compressed CSS/JS");
}
}
}
composer.json
"autoload": {
"classmap": [
"scripts/composer/ScriptHandler.php"
]
},
"scripts": {
"post-update-cmd": [
"DrupalProject\\composer\\ScriptHandler::gulpBuild"
]
},
Check Composer template for Drupal projects for some more inspiration. (For example getting the path to your theme dynamically to have that command run successfully in every environment.)
Related
We are currently using phing on deployment from jenkins to our different environments. We use it to do some cleanup. We would like to remove phing from our source/vendor folder after the build is completed.
Can phing remove itself as a final build step?
Or should i just be doing an rm -rf phing/?
There are two parts to this answer:
Solution for Question
Your Phing installation should be done with composer. Do composer require phing/phing - and then you can use vendor/bin/phing to run your build.xml file (instead of say using a global install).
Then, when you're done, your last step to run could be composer remove phing/phing
Suggested Workflow
So, the idea with something like Jenkins is that you should be using it to do all of your build and processing on a build system. Then, it (Jenkins) is the tool that can do anything else on the remote systems for you. So, instead of having phing on the deployed server and then have it doing tasks, you'd tell Jenkins to do those tasks remotely. (This might be accomplished by each step having to re-ssh into that server to execute a new step). As these steps are part of the deploy process too, if any of them fail, the build will be considered failed and you'll have that insight. So, that being said, the solution I suggest is above, but I'd recommend changing everything else up.
Imagine your project needs many dependencies, for example ramsey/uuid, phing/phing and pds/skeleton. Use composer require to add dependencies, but use --dev option when adding development depdendencies:
composer require ramsey/uuid
composer require --dev phing/phing
composer require --dev pds/skeleton
The content of your composer.json should be the following:
{
"require": {
"ramsey/uuid": "^3.8"
},
"require-dev": {
"pds/skeleton": "^1.0",
"phing/phing": "^2.16"
}
}
To install all your dependencies use the following command:
composer install
Now, if you want to remove your development dependencies type:
composer install --no-dev
The last command will only install your production dependencies and remove your development dependencies from vendor directory at once.
In my symfony project i would like to trigger the
php app/console doctrine:migration:migrate
on every
composer install --no-dev
I have read that it should be possible to place such a command in the post-install-cmd Section of my composer file but can not figure out how to use it properly.
You have to create a Composer Script:
A script, in Composer's terms, can either be a PHP callback (defined as a static method) or any command-line executable command.
Just like they do in the example:
{
"scripts": {
"post-install-cmd": ["phpunit -c app/"],
}
}
Every time I create a new PHP project I basically use the same MVC folder structure that I adopted and like, I use the same base classes, interfaces, and the same PDO DAL implementation.
When I'm creating a new project I copy&paste all the needed files to the new project in addition to few changes, like changes to namespaces (to match the new project name) etc.
I thought, why not creating a simple script to copy those files and folders, and make the additional changes.
So now, when I create a new project I just run the script and the code is generated automatically, which is much nicer.
And then I thought, I want it to be even simpler. I don't want to save the code in my computer, I want to save it on Github, and since I use and love composer, I thought I will make the Github project a composer package.
But when trying to implement it I realized that I can't make the new composer package auto generate the code that I want, or at least I don't know how to make it do that.
I tried googling it with no success.
Does anyone knows how to achieve this?
I don't see any need to generate code here. Simply add your skeleton files to your Git repository and use Composer's create-project feature. See the third point:
You can use Composer to create new projects from an existing package. This is the equivalent of doing a git clone/svn checkout followed by a composer install of the vendors.
There are several applications for this:
You can deploy application packages.
You can check out any package and start developing on patches for example.
Projects with multiple developers can use this feature to bootstrap the initial application for development.
An example of a major PHP project that supports this approach is Laravel. From its installation instructions:
Via Composer
The Laravel framework utilizes Composer for installation and dependency management. If you haven't already, start by installing Composer.
Now you can install Laravel by issuing the following command from your terminal:
composer create-project laravel/laravel your-project-name --prefer-dist
This command will download and install a fresh copy of Laravel in a new your-project-name folder within your current directory.
If you prefer, you can alternatively download a copy of the Laravel repository from Github manually. Next run the composer install command in the root of your manually created project directory. This command will download and install the framework's dependencies.
Edit:
To have a script run after composer create-project completes you should be able to use a Composer script:
A script, in Composer's terms, can either be a PHP callback (defined as a static method) or any command-line executable command. Scripts are useful for executing a package's custom code or package-specific commands during the Composer execution process.
You are probably looking for the post-create-project-cmd event:
occurs after the create-project command is executed
Depending on whether your script is a static PHP method or a shell executable, you should define it as follows (modified from Composer documentation):
{
"scripts": {
"post-create-project-cmd": "MyVendor\\MyClass::postUpdate"
}
}
or
{
"scripts": {
"post-create-project-cmd": "my-shell-script arg1 arg2"
}
}
I juste want to have the possibility to use the class of this library but after 2 hours impossible :
So how to use the Zend Framework 2.1 with his autoloader to just use class of this library and not create a ZF project?
I have try everything with the classmap_generator, inlude_path... i haven't any error but it still return me :
Could not find action class? Could not find version class!
Thanks you.
You can install individual Zend Framework modules via composer, which will take care of most of this for you:
composer.json
{
"require": {
"zendframework/zend-http": "2.*"
},
"repositories": [
{
"type": "composer",
"url": "http://packages.zendframework.com/"
}
],
"minimum-stability": "dev"
}
this should take care of any autlloading for you. Composer would generate an autoloader which you would just include in your app:
require 'vendor/autoload.php';
there's a load of composer examples out there:
https://packages.zendframework.com/#composer
http://net.tutsplus.com/tutorials/php/easy-package-management-with-composer/
Since ZF2 components are decoupled and focused on a specific task, one class often uses another to do its business. Simply including a single class file is usually not sufficient.
As a result, ZF2 definitely requires some autoloading. But you don't have to use the ZF2 autoloader.
If you have no autoloading already in place in your app, then it's actually pretty easy to add:
Make sure the path to the Zend library is on your include_path.
Register a standard PSR-0-compliant autoloader using spl_autoload_register()
Something like:
spl_autoload_register(function($class)){
$file = str_replace('\\', '/', $class) . '.php';
$resolvedFile = stream_resolve_include_path($file);
if (file_exists($resolvedFile)) {
include $resolvedFile;
return $class;
}
});
If you already have an autoloader for your application, then I'd be quite surprised if it was not PSR-0-compliant. As before, make sure that the Zend library is on the include_path.
Even if the Zend library is not on your include path, you can create a custom autoloader that is aware of where in your filesystem the library is based.
In all cases, usage of the desired class is then:
$myinstance = new \Zend\Component\Class();
With the correct autoloading in place - however you choose to go about it - this class can use any other Zend classes that it needs to go about its business.
After many search, i have install composer. But i'm not very happy of this solution cause it touch my system.
Here is my procedure, i still say that ZF documentation is very poor.
Install ZEND FRAMEWORK WITH COMPOSER
1) Allow whitelist
suhosin.executor.include.whitelist = phar
In file : nano /etc/php5/cli/conf.d/suhosin.ini
2) Download of composer
Apt-get install curl
curl -sS https://getcomposer.org/installer | php
3) Move composer
mv composer.phar /usr/local/bin/composer
4) Copy the composer.json
Copy composer.json (From zend framework archive) a my root folder application
5) Composer install
Execute where the composer.json is
Now you will have a folder named "vendor" in your app folder, to use in your php code :
include("vendor/autoload.php");
new Zend\Mail\Storage\Pop3(...);
And now it work for me.
Bug allowed memory size :
php -r "echo ini_get('memory_limit').PHP_EOL;"
change to 1024M
nano /etc/php5/cli/php.ini
/etc/init.d/apache2 restart
Failed to clone http://github.com/zendframework/Component_ZendStdlib.git, git was not found,
Install GIT
Apt-get install git
Just register the namespace in your autoloader.
if you are using composer then add include_once '<path to vendor dir>/autoload.php'; on top of your php file
This is my composer.json file:
"require": {
"php": ">=5.4",
"zendframework/zendframework": "2.*",
"doctrine/doctrine-module": "dev-master",
"doctrine/doctrine-orm-module": "0.*",
"gedmo/doctrine-extensions": "dev-master"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"scripts": {
"post-update-cmd": [
"rm -rf vendor/Behat",
"git clone git://github.com/Behat/Behat.git",
"cp composer.phar Behat/composer.phar",
"cd Behat && git submodule update --init",
"cd Behat && php composer.phar install",
"cd Behat && php composer.phar require guzzle/guzzle:3.0.*",
"mv Behat vendor/Behat",
"ln -sf ../Behat/bin/behat vendor/bin/"
]
}
How can I make it so the scripts are only run in the dev environment?
Basically I want the scripts to run only when I call:
php composer.phar update --dev
To do the non-development environment update without triggering any scripts, use the --no-scripts command line switch for the update command:
php composer.phar update --no-scripts
^^^^^^^^^^^^
By default, Composer scripts are only executed1 in the base package2. So you could have one package for development and in the live environment make it a dependency of the live system.
Apart from that, I do not see any way to differentiate scripts automatically.
This answer is back from 2012, the additional options in order of appearance can now safely be listed. As the list is composer-only and the original question smells to fall for x/y, the general answer is to use a build manager.
But turns out this could be done already at the day of asking, as in this composer-json example:
{
"scripts": {
"post-update-cmd": "composer::dev-post-update-cmd",
"dev-post-update-cmd": [
"rm -rf vendor/Behat",
": ... ",
"ln -sf ../Behat/bin/behat vendor/bin/"
]
}
}
1.0.0-alpha6 (2012-10-23): dispatch dev-only scripts with PHP script class and __callStatic, e.g. composer::dev-post-update-cmd. if in_array('--dev', $_SERVER['argv']) then $eventDispatcher->dispatchCommandEvent($name).
1.0.0-alpha7 (2013-05-04): --dev is now default and henceforth optional, --no-dev required for not --dev script dispatching. this effectively changes the command-line in question from: composer update --dev running only to: not running on composer update --no-dev. $event->isDevMode() now available, also required for new second parameter on dispatching the script on the event dispatcher. Compare with answer by Christian Koch.
1.0.0-alpha9 (2014-12-07): autoload-dev now allows to not have the script class in --no-dev automatically by removing it from autoload. this works b/c non-existing classes fall-through w/o error.
1.3.0-RC (2016-12-11): --dev is deprecated. COMPOSER_DEV_MODE environment parameter now available in update/install/dumpautoload scripts. no inherit need any longer for the PHP script class, unless enviroment parameters do not work in your setup, then use a PHP class script for a workaround. Compare with answer by Veda.
3 (future): --dev will needlessly make composer fatal, at least this is announced. this closes the circle to pre-1.0.0-alpha7 which also failed on the opposite, --no-dev. the command-line library in use then and yet in the future is not able to cope with -[-not]-args symmetrically, and if the pair is divided and one must go, then it can only throw.
References
See "Note:" in What is a script? - Scripts - Composer Docs
Base package is commonly referred to as root package in the Composer documentation.
Introduction
Some of the answers are a bit brief and don't go into detail about the context in which this is done. I'd like to share some knowledge with whoever is still puzzled after reading the previous answers.
Determine the right option for you
First, take a moment to realise that you're effectively creating a different flow, specific for a certain environment (i.e. your development server/container). This is against any best practices, as it is generally prone to errors. Having said that, you can achieve what you want in several ways;
Not triggering any scripts (docs)
If on some environment you do not want to trigger any scripts, you can prevent this using the --no-scripts flag.
Documentation reads: --no-scripts: Skips execution of scripts defined in composer.json.
composer upgrade --no-scripts
This is especially useful when upgrading packages while your code is currently not working. It would also work if your only scripts are development and test-related.
Running one script separately (docs)
Simply run the specific command as needed:
composer run-script [--dev] [--no-dev] script
This is useful when you want to run a script only on specific occasions.
For example, on build systems that have to perform a certain script before running any tests; build systems offer configuration options to call custom scripts like the above.
Defining a condition in the command (docs)
Documentation reads: During a composer install or update process, a variable named COMPOSER_DEV_MODE will be added to the environment. If the command was run with the --no-dev flag, this variable will be set to 0, otherwise it will be set to 1.
An example could look like
"scripts": {
"post-install-cmd": [
"[ $COMPOSER_DEV_MODE -eq 0 ] || <your command>"
]
}
Personally i would say this is the recommended way if you are using containers.
Note: this does not work on windows, since it would need %COMPOSER_DEV_MODE%.
There are also packages (like scriptsdev by neronmoon) that help you achieve the same goal without having to type the above in all commands, using a dev-scripts section in the extra section in composer.json
Defining a condition in your PHP script (docs)
Call a PHP method, that checks your environment based on how your application already does this. You can even reuse this condition by combining it with the method above; "Defining a condition in the command".
"scripts": {
"post-update-cmd": [
"AppNameSpaceName\\YourClassName::methodName"
]
}
You can then go ahead and create the class, like so:
<?php
namespace AppNameSpaceName;
class YourClassName
{
methodName() {
// do stuff
}
}
In many modern frameworks there is already a mechanism present to determine the runtime environment of the application (Symfony way, Laravel way).
Yarn run (docs)
Since most PHP applications nowadays also transpile their javascript files, either NPM or Yarn would be installed. You can use the scripts section to run this part only on development machines/containers. For example:
yarn run dev-only-script
having a section in package.json
"scripts": {
"dev-only-script": "rm some/folder && ln -s path/to/your/folder some/"
}
The point of this is would be to your composer.json clean. In yarn you could have scripts for dev-server, test and build.
It's not possible to choose different script for default install and the --dev option but you can use the method isDevMode() in Composer\Script\Event to run command only in a development enviroment. http://getcomposer.org/apidoc/master/Composer/Script/Event.html
You can use the COMPOSER_DEV_MODE environment variable (new in version 1.3.0-RC - 2016-12-11):
"scripts": {
"post-install-cmd": [
"[ $COMPOSER_DEV_MODE -eq 0 ] || echo devmode only"
]
},
You can achieve the same effect by setting up a custom script for the dev pathway, instead of using the post-update-cmd hook.
"scripts": {
"update-behat": [
"rm -rf vendor/Behat",
"git clone git://github.com/Behat/Behat.git",
"cp composer.phar Behat/composer.phar",
"cd Behat && git submodule update --init",
"cd Behat && php composer.phar install",
"cd Behat && php composer.phar require guzzle/guzzle:3.0.*",
"mv Behat vendor/Behat",
"ln -sf ../Behat/bin/behat vendor/bin/"
],
"dev-update": [
"#composer update --dev",
"#update-behat"
]
}
Then simply run php composer.phar dev-update
Run the following command.
composer update --no-scripts
Here is the small package, that you may use to do that
https://github.com/neronmoon/scriptsdev
It adds ability to define only-dev scripts.
usage
...
"extra": {
"scripts-dev": {
"post-install-cmd": [
"npm install --dev"
],
"post-update-cmd": "php ./someCoolCommand.php"
},
}
...
You can run either one and check,
composer update --no-scripts
or
composer dump-autoload