Categories
symfony2

Monolog logs the WARN after ERR

I have “the luck” to work on an old Symfony2.0 application and today I had the following *@#&$*@ problem. Monolog logs the WARN level messages if I log before an ERR level message.

[php]
$logger = $this->get(‘logger’);
//$logger->err(‘RAZV err’);
$logger->warn(‘RAZV 1 warn’);
$logger->warn(‘RAZV 2 warn’);
die;
[/php]

In the logs:
[bash]tail -f log/*[/bash]

Nothing.

Same piece of code but with err logged:
[php]
$logger = $this->get(‘logger’);
$logger->err(‘RAZV err’);
$logger->warn(‘RAZV 1 warn’);
$logger->warn(‘RAZV 2 warn’);
die;
[/php]

In the logs:

[bash]tail -f log/*

==> log/prod.log <==
[2013-06-04 11:45:40] app.ERROR: RAZV err [] []
[2013-06-04 11:45:40] app.WARNING: RAZV 1 warn [] []
[2013-06-04 11:45:40] app.WARNING: RAZV 2 warn [] []
[/bash]

WTF!!!!

Categories
Programming symfony2

Load bundle without composer.json in Symfony2.3

This is how I loaded a legacy budle without composer.json in a custom location for my Symfony2.3 project with composer.

In one of my Symfony2.3 projects I needed to use an old external bundle. This legacy bundle (from Symfony2.0) hasn’t a composer.json file and in my case I can not add one.
Anyway, I wanted to use composer and its autoloader also for this bundle in order to keep things simple for me.

Let’s assume I wanted to add TwitterClientBundle and its namespace is: Razvan\TwitterClientBundle

For this I added in my composer.json the following:

[javascript]

{
"name": "symfony/framework-standard-edition",
"license": "MIT",
"type": "project",
"description": "The \"Symfony Standard Edition\" distribution",
"autoload": {
"psr-0": {
"": "src/",
"Razvan\\TwitterClientBundle": "vendor/razvan/twitter-client-bundle"
}
},
"repositories": [
{
"type": "package",
"package": {
"name": "razvan/twitter-client-bundle/Razvan/TwittereClientBundle",
"version": "4.4.3",
"source": {
"url": "https://github.com/raztud/TwittereClientBundle",
"type": "git",
"reference": "master"
}
}
}
],
"require": {
"razvan/twitter-client-bundle/Razvan/TwitterClientBundle": "*"
},


[/javascript]

After that I ran:

[bash]php composer.phar update razvan/twitter-client-bundle[/bash]

and the bundle was added in /path/to/yourproject/vendor/razvan/twitter-client-bundle/

eg:

[bash]
razvan@main2:/var/www/twitter/vendor/razvan/twitter-client-bundle$ tree
.
— Razvan
— TwitterClientBundle
— DependencyInjection
   — RazvanTwitterClientExtension.php
— RazvanTwitterClientBundle.php
— Manager
….
[/bash]

After that I enabled the bundle in AppKernel.php

[php]new Razvan\TwitterClientBundle\RazvanTwitterClientBundle()[/php]

and that was all.

Disclaimer:
– Maybe there are better solution, but I did not find them yet.
– The bundle RazvanTwitterBundle doesn’t exist on Github.

P.S. Somebody else wrote a similar post in the past.

Categories
symfony2

How to use AWS SDK for PHP 2 and Symfony Console

Few days ago I wanted to write a small PHP script to backup (upload) some files in Amazon S3. And because Amazon just released last month a new version of their SDK, AWS SDK for PHP 2 I decided to use this one.
I also choose to use Console component from Symfony2 and Composer to install all the dependencies.

In the root folder of my project I downloaded and installed composer, like this:

[bash]
curl -s "http://getcomposer.org/installer" | php
[/bash]

In composer.json file I added this dependencies:

[javascript]
{
"require": {
"aws/aws-sdk-php": "*",
"monolog/monolog": "1.0.*",
"symfony/class-loader": "2.1.3",
"symfony/console": "2.1.3",
"symfony/yaml": "2.1.3",
"doctrine/common": "2.3.0",
"symfony/finder": "2.1.4"
},
"autoload": {
"psr-0": {
"Razvan": "src/"
}
}
}
[/javascript]

and after this I ran:

[bash]
php composer.phar install
[/bash]

After runing this command, you will see in the project folder, a directory called vendor where are installed all the dependencies.

After that I created on the same level with vendor a folder called src and inside this one another folder called Razvan.

[bash]mkdir -p src/Razvan[/bash]

inside the Razvan folder I put my BackupCommand.php

Below is a part of the code:

[php]
<?php

namespace Razvan;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Finder\Finder;

use Aws\S3\S3Client;
use Aws\S3\Enum\CannedAcl;
use Aws\S3\Exception\S3Exception;

/**
* BackupCommand
* eg: usage for upload:
* php sync.php s3 /path/to/folder/ upload –relative
*
* @author razvan tudorica
*/
class BackupCommand extends Command
{

private $s3;

protected function configure()
{
//… get the configuration for s3

$this
->setName(‘s3’)
->setDescription(‘Syncronize Amazon S3 folder with the local folder’)
->addArgument(‘localFolder’, InputArgument::REQUIRED, ‘Local folder FULL path’)
->addArgument(‘action’, InputArgument::REQUIRED, ‘upload (or download)’)
->addArgument(‘bucket’, InputArgument::OPTIONAL, ‘The bucket name’, $this->bucket)
->addArgument(‘s3Folder’, InputArgument::OPTIONAL, ‘Remote S3 folder path’)
->addOption(‘relative’, null, InputOption::VALUE_NONE, ‘If set, we will use relative path in the bucket’)
;

$conf = array(
‘key’=>’YOURKEY’,
‘secret’ => ‘YOURSECRET’,
‘region’ => ‘us-east-1’ //or your bucket’s region
);
$this->s3 = S3Client::factory($conf);
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$action = $input->getArgument(‘action’);
$localFolder = $this->input->getArgument(‘localFolder’);
$bucket = $this->input->getArgument(‘bucket’);

//check if input the parameters are correct
//…

$finder = new Finder();
$finder->files()->in($localFolder);
$finder->files()->followLinks();

foreach ($finder as $file)
{
//some extra logic for setting the key
//…
$key = $startFolder . DIRECTORY_SEPARATOR . $file->getRelativePathname();

$this->output->writeln($key);

try
{
$this->s3->putObject(array(
‘Bucket’ => $bucket,
‘Key’ => $key,
‘Body’ => fopen($file->getRealpath(), ‘r’),
‘ACL’ => CannedAcl::PUBLIC_READ
));
}
catch (S3Exception $e)
{
$this->output->writeln("The file was not uploaded: " . $e->getMessage());
}

}

}
[/php]

And now we have to call this command. For this, in the root folder of the project I created another small script called backup.php with this content:

[php]
#!/usr/bin/env php
<?php

require_once __DIR__.’/vendor/autoload.php’;

use Razvan\BackupCommand;
use Symfony\Component\Console\Application;

$command = new BackupCommand();

$application = new Application();

$application->add($command);
$application->run();
[/php]

Now, we can run it from the console, with:

[bash]php sync.php s3 /home/razvan/mypictures[/bash]

Based on this skeleton, I’m working for a more complex syncronization script between Amazon S3 and a local folder. You can find the code on GitHub.

Disclaimer:

It is possible the tutorial above to not be very complete and accurate.

The code it’s not optimized at all (eg: if you have a big amount of files or very big files).

 

Categories
symfony2

How to create a command (task) in Symfony 2

In Symfony 1.x a task is a command line tool to help perform tasks around the application. The same is in Symfony 2. Unfortunately in Symfony2 there is no tool to auto-generate some code for these. To create a Symfony2 Command you must to have or to create in your Bundle a folder named Command. Here, you must create a file named MytaskCommand.php with the following code:

<?php
namespace ApplicationVremeaBundleCommand;

use SymfonyBundleFrameworkBundleCommandCommand;
use SymfonyComponentConsoleInputInputDefinition;
use SymfonyComponentConsoleInputInputOption;
use SymfonyComponentConsoleInputInputArgument;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
use SymfonyComponentRazvanUtilsCurl;

class ImportCommand extends Command {

 const NEWLINE = true;
 private $connection;

 protected function configure() {
 parent::configure();

 $this
                ->setName('tudorica:razvan')
                ->addArgument('type', InputArgument::REQUIRED, 'Type')
                ->addOption('country', 'c', InputOption::VALUE_OPTIONAL, 'Country', '')

        ;
    }

    /**
     * Executes the current command.
     *
     * @param InputInterface  $input  An InputInterface instance
     * @param OutputInterface $output An OutputInterface instance
     *
     * @return integer 0 if everything went fine, or an error code
     *
     * @throws LogicException When this abstract class is not implemented
     */
    protected function execute(InputInterface $input, OutputInterface $output) {
        // your code here.
        //if you want to access database (must to setup doctrine.dbal)
        $this->connection = $this->container->get('database_connection');

         //to get the user input argument "type" for this command
        $type = $input->getArgument('type');        

        //to get use option "contry" for this command
        $country = $input->getOption('country');

        //to write a message (in symfony1.x was named log).
        $output->write('type: '.$type, true);
    }

}

Now, you can open a console and go to app folder. If you write:

./console

you will see something like

nit
  :acl                         
  :bundle                      
router
  :debug                       Displays current routes for an application
  :dump-apache                 Dumps all routes as Apache rewrite rules
tudorica
  :razvan                      

You can execute this Command with: ./console tudorica:razvan