Embrace Dreams
Archive for the ‘Symfony’ Category
Some ways to get value from request in Symfony2
April 15th, 2012 | admin
In symfony2, if you want to get value from request, you have many ways:
forst, bind request to form, then you can use the entity, official document has details.
If you are using formtype, there is another two ways to get value,
first:
$postData = $request->request->get('slackiss_bundle_qingbundle_registertype');
$name_value = $postData['email'];
second:
$email = = $form["email"]->getData();
or
$defaultData = array('message' => 'Type your message here');
$form = $this->createFormBuilder($defaultData)
->add('name', 'text')
->add('email', 'email')
->add('message', 'textarea')
->getForm();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
// data is an array with "name", "email", and "message" keys
$data = $form->getData();
}
If you do not use formtype, I mean, you are not using {{form_widget}}, you can get values:
echo $request->request->get('email');
About $request, the code is like:
public function doAction(Request $request)
{
}
or
$request = $this->getRequest();
Compare dates with Twig
January 12th, 2012 | admin
Here is a trick to compare two dates in Twig. Convert them as string with the date filter, with first the year, then the month and finally the day:
myDate|date('Y-m-d')
Then, you can compare strings because the chronological order is the same than the lexicographical order:
{% if date1|date('Y-m-d') > date2|date('Y-m-d') %}
{# ... #}
{% endif %}
Tip. If you want to get the current date, you can give the string now to the date filter:
{% if "now"|date('Y-m-d') > date2|date('Y-m-d') %}
{# ... #}
{% endif %}
Symfony2 Coding Standards
January 12th, 2012 | admin
Remember that the main advantage of standards is that every piece of code looks and feels familiar, it’s not about this or that being more readable.
Since a picture – or some code – is worth a thousand words, here’s a short example containing most features described below:
<!--?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com-->
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Acme;
class Foo
{
const SOME_CONST = 42;
private $foo;
/**
* @param string $dummy Some argument description
*/
public function __construct($dummy)
{
$this->foo = $this->transform($dummy);
}
/**
* @param string $dummy Some argument description
* @return string|null Transformed input
*/
private function transform($dummy)
{
if (true === $dummy) {
return;
}
if ('string' === $dummy) {
$dummy = substr($dummy, 0, 5);
}
return $dummy;
}
}
Structure
- Never use short tags ( closing tag;
- Indentation is done by steps of four spaces (tabs are never allowed);
- Use the linefeed character (0x0A) to end lines;
- Add a single space after each comma delimiter;
- Don’t put spaces after an opening parenthesis and before a closing one;
- Add a single space around operators (==, &&, …);
- Add a single space before the opening parenthesis of a control keyword (if, else, for, while, …);
- Add a blank line before return statements, unless the return is alone inside a statement-group (like an if statement);
- Don’t add trailing spaces at the end of lines;
- Use braces to indicate control structure body regardless of the number of statements it contains;
- Put braces on their own line for classes, methods, and functions declaration;
- Separate the conditional statements (if, else, …) and the opening brace with a single space and no blank line;
- Declare visibility explicitly for class, methods, and properties (usage of var is prohibited);
- Use lowercase PHP native typed constants: false, true, and null. The same goes for array();
- Use uppercase strings for constants with words separated with underscores;
- Define one class per file;
- Declare class properties before methods;
- Declare public methods first, then protected ones and finally private ones.
Naming Conventions
- Use camelCase, not underscores, for variable, function and method names;
- Use underscores for option, argument, parameter names;
- Use namespaces for all classes;
- Suffix interfaces with Interface;
- Use alphanumeric characters and underscores for file names;
- Don’t forget to look at the more verbose Conventions document for more subjective naming considerations.
Documentation
- Add PHPDoc blocks for all classes, methods, and functions;
- Omit the @return tag if the method does not return anything;
- The @package and @subpackage annotations are not used.
Put braces on their own line for classes, methods, and functions declaration;
Unit testing for Symfony2 repositories with PHPUnit
January 12th, 2012 | admin
Here is the workflow I have to add a new function in an entity repository. Let’s say I have a blog and I want to get the most seen posts by counting the visits for each post. Here is the workflow I have:
Write the functions structure in the repository Write the test structure test class Write the DQL query with the console Write the test in the test class Write the query in the repository
1
The usual way to do add a query in a repository to add a new function that query the database and return the results:
namespace Acme\BlogBundle\Repository;
use Doctrine\ORM\EntityRepository;
class PostRepository extends EntityRepository {
public function getMostSeen() {
// query database and return results
}
}
But this is hard to debug. I prefer to have for each query, two functions: one that build the query (that can easily be tested and debugged) and another one that execute that query and return result:
namespace Acme\BlogBundle\Repository;
use Doctrine\ORM\EntityRepository;
class PostRepository extends EntityRepository {
public function qbMostSeen() {
return $this->createQueryBuilder('p')
-> // ...
}
public function getMostSeen() {
return $this->qbMostSeen()
->getQuery()
->getResult();
}
}
2
The test class will be in the Tests directory of the bundle:
namespace Acme\BlogBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class PostRespositoryTest extends WebTestCase {
// ...
}
But we want to be able to instantiate PostRepository and for that we need the Entity Manager and a kernel (that we don’t have by default). So let’s add setUp() that will be executed before the tests:
namespace Acme\BlogBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class PostRespositoryTest extends WebTestCase {
private $repo;
public function setUp() {
$kernel = static::createKernel();
$this->repo = $kernel->boot();
$this->repo = $kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('AcmeBlogBundle:Post');
}
}
We add our tests:
on the query itself: here we compare the query DQL to the DQL we are going to write
on the results: here we check that we have some results
public function testMostSeen()
{
$this->assertEquals(
$this->repo->qbMostSeen()->getDql(),
"..." // the DQL query
);
$this->assertNotEquals(0, count($this->repo->getMostSeen()));
}
You can add your tests on either the query or the results.
3
Write the DQL. Let’s write the DQL step by step testing each step with the console. Here, we get all the posts:
app/console doctrine:query:dql --max-result=5 "SELECT p.title FROM Acme\BlogBundle\Entity\Post p"
then we add one by one parts of our query, testing on our database to check the result every time. A left join to get all the visits:
SELECT p.title, v.id FROM Acme\BlogBundle\Entity\Post p LEFT JOIN p.visits v
then we add the visit count:
SELECT p.title, COUNT(v) AS visit_count FROM Acme\BlogBundle\Entity\Post p LEFT JOIN p.visits v GROUP BY p.title
and we order by visit count:
SELECT p.title, COUNT(v) AS visit_count FROM Acme\BlogBundle\Entity\Post p LEFT JOIN p.visits v GROUP BY p.title ORDER BY visit_count DESC
Now that we are happy with the query, we can finish to write our tests.
4
Just insert the DQL in the test:
$this->assertEquals(
$this->repo->qbMostSeen()->getDql(),
"SELECT p.title, COUNT(v) AS visit_count FROM Acme\BlogBundle\Entity\Post p LEFT JOIN p.visits v GROUP BY p.title ORDER BY visit_count DESC"
);
5
Finally, write the query until PHPUnit is green!
namespace Acme\BlogBundle\Repository;
use Doctrine\ORM\EntityRepository;
class PostRepository extends EntityRepository {
public function qbMostSeen() {
return $this->createQueryBuilder('p')
->select('p.title', 'COUNT(v) AS visit_counts')
->leftJoin('p.visits', 'v')
->orderBy('visit_counts', 'DESC');
}
public function getMostSeen() {
return $this->qbMostSeen()
->getQuery()
->getResult();
}
}
Pro tip
You might want to add the alias dql to your shell environment (.bash_profile, .zsh/zshaliases or whatever):
alias dql="app/console doctrine:query:dql"
so you can just run in your shell:
dql "SELECT p.title FROM Acme\BlogBundle\Entity\Post p"
Feel free to ask questions right here
Thanks to the origin author here.
Learn more about Unit Test for Symfony2
January 12th, 2012 | admin
First of all, install PHPUnit:
$ pear channel-discover pear.phpunit.de $ pear channel-discover components.ez.no $ pear channel-discover pear.symfony-project.com $ pear install phpunit/PHPUnit
Then you can start to use PHP Unit like:
$phpunit -c app/
If you want to get report on HTML format, add parameter:
$ phpunit -c app/ --coverage-html=cov/
Not everybody has xdebug installed, maybe you will meet some problems like:
The Xdebug extension is not loaded. No code coverage will be generated.
That means you need to install xdebug for your PHP5. If you are using OpenSuse, it has a PHP Extensions repository, you can find more details from the following site:
http://download.opensuse.org/repositories/ and http://download.opensuse.org/repositories/server:/php:/extensions/openSUSE_12.1/server:php:extensions.repo
You just need to install it simply as:
$sudo zypper ar http://download.opensuse.org/repositories/server:/php:/extensions/openSUSE_12.1/server:php:extensions.repo $sudo zypper install php5-xdebug
Now you fix the problem.
Start
OK, Let’s start to mark some tips about unit test for Symfony2.
First, a simple unit test:
// src/Acme/DemoBundle/Tests/Utility/CalculatorTest.php
namespace Acme\DemoBundle\Tests\Utility;
use Acme\DemoBundle\Utility\Calculator;
class CalculatorTest extends \PHPUnit_Framework_TestCase
{
public function testAdd()
{
$calc = new Calculator();
$result = $calc->add(30, 12);
// assert that our calculator added the numbers correctly!
$this->assertEquals(42, $result);
}
}
You can run unit test via:
# run all tests in the Utility directory $ phpunit -c app src/Acme/DemoBundle/Tests/Utility/ # run tests for the Calculator class $ phpunit -c app src/Acme/DemoBundle/Tests/Utility/CalculatorTest.php # run all tests for the entire Bundle $ phpunit -c app src/Acme/DemoBundle/
What about a functional unit test?
// src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php
namespace Acme\DemoBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class DemoControllerTest extends WebTestCase
{
public function testIndex()
{
$client = static::createClient();
$crawler = $client->request('GET', '/demo/hello/Fabien');
$this->assertTrue($crawler->filter('html:contains("Hello Fabien")')->count() > 0);
}
}
Something more about links:
$link = $crawler->filter('a:contains("Greet")')->eq(1)->link();
$crawler = $client->click($link);
And form:
$form = $crawler->selectButton('submit')->form();
// set some values
$form['name'] = 'Lucas';
$form['form_name[subject]'] = 'Hey there!';
// submit the form
$crawler = $client->submit($form);
Now that you can easily navigate through an application, use assertions to test that it actually does what you expect it to. Use the Crawler to make assertions on the DOM:
// Assert that the response matches a given CSS selector.
$this->assertTrue($crawler->filter('h1')->count() > 0);
Or, test against the Response content directly if you just want to assert that the content contains some text, or if the Response is not an XML/HTML document:
$this->assertRegExp('/Hello Fabien/', $client->getResponse()->getContent());
The test Client simulates an HTTP client like a browser and makes requests into your Symfony2 application:
$crawler = $client->request('GET', '/hello/Fabien');
The request() method takes the HTTP method and a URL as arguments and returns a Crawler instance.
Use the Crawler to find DOM elements in the Response. These elements can then be used to click on links and submit forms:
$link = $crawler->selectLink('Go elsewhere...')->link();
$crawler = $client->click($link);
$form = $crawler->selectButton('validate')->form();
$crawler = $client->submit($form, array('name' => 'Fabien'));
The click() and submit() methods both return a Crawler object. These methods are the best way to browse your application as it takes care of a lot of things for you, like detecting the HTTP method from a form and giving you a nice API for uploading files.
The request method can also be used to simulate form submissions directly or perform more complex requests:
// Directly submit a form (but using the Crawler is easier!)
$client->request('POST', '/submit', array('name' => 'Fabien'));
// Form submission with a file upload
use Symfony\Component\HttpFoundation\File\UploadedFile;
$photo = new UploadedFile(
'/path/to/photo.jpg',
'photo.jpg',
'image/jpeg',
123
);
// or
$photo = array(
'tmp_name' => '/path/to/photo.jpg',
'name' => 'photo.jpg',
'type' => 'image/jpeg',
'size' => 123,
'error' => UPLOAD_ERR_OK
);
$client->request(
'POST',
'/submit',
array('name' => 'Fabien'),
array('photo' => $photo)
);
// Perform a DELETE requests, and pass HTTP headers
$client->request(
'DELETE',
'/post/12',
array(),
array(),
array('PHP_AUTH_USER' => 'username', 'PHP_AUTH_PW' => 'pa$$word')
);
Last but not least, you can force each request to be executed in its own PHP process to avoid any side-effects when working with several clients in the same script:
$client->insulate();
Browsing
The Client supports many operations that can be done in a real browser:
$client->back(); $client->forward(); $client->reload(); // Clears all cookies and the history $client->restart(); Accessing Internal Objects
If you use the client to test your application, you might want to access the client’s internal objects:
$history = $client->getHistory(); $cookieJar = $client->getCookieJar();
You can also get the objects related to the latest request:
$request = $client->getRequest(); $response = $client->getResponse(); $crawler = $client->getCrawler();
If your requests are not insulated, you can also access the Container and the Kernel:
$container = $client->getContainer(); $kernel = $client->getKernel();
Accessing the Container
It’s highly recommended that a functional test only tests the Response. But under certain very rare circumstances, you might want to access some internal objects to write assertions. In such cases, you can access the dependency injection container:
$container = $client->getContainer();
Be warned that this does not work if you insulate the client or if you use an HTTP layer. For a list of services available in your application, use the container:debug console task.
Something more details you should refer to the official symfony book from here.
Upgrade to Symfony 2.0.6 for security upgrade
November 24th, 2011 | admin
It’s easy, change your deps to :
[symfony]
git=http://github.com/symfony/symfony.git
version=v2.0.6
[twig]
git=http://github.com/fabpot/Twig.git
version=v1.1.2
[monolog]
git=http://github.com/Seldaek/monolog.git
version=1.0.2
[doctrine-common]
git=http://github.com/doctrine/common.git
version=2.1.2
[doctrine-dbal]
git=http://github.com/doctrine/dbal.git
version=2.1.3
[doctrine]
git=http://github.com/doctrine/doctrine2.git
version=2.1.2
[swiftmailer]
git=http://github.com/swiftmailer/swiftmailer.git
version=v4.1.3
[assetic]
git=http://github.com/kriswallsmith/assetic.git
version=v1.0.2
[twig-extensions]
git=http://github.com/fabpot/Twig-extensions.git
[metadata]
git=http://github.com/schmittjoh/metadata.git
version=1.0.0
[SensioFrameworkExtraBundle]
git=http://github.com/sensio/SensioFrameworkExtraBundle.git
target=/bundles/Sensio/Bundle/FrameworkExtraBundle
[JMSSecurityExtraBundle]
git=http://github.com/schmittjoh/JMSSecurityExtraBundle.git
target=/bundles/JMS/SecurityExtraBundle
version=origin/1.0.x
[SensioDistributionBundle]
git=http://github.com/sensio/SensioDistributionBundle.git
target=/bundles/Sensio/Bundle/DistributionBundle
version=origin/1.0
[SensioGeneratorBundle]
git=http://github.com/sensio/SensioGeneratorBundle.git
target=/bundles/Sensio/Bundle/GeneratorBundle
[AsseticBundle]
git=http://github.com/symfony/AsseticBundle.git
target=/bundles/Symfony/Bundle/AsseticBundle
version=v1.0.1
change your deps.lock to
symfony b55a43813e8fbcf4facd19ce1da0cd7acc67ce9b twig 396435ecd05556adb0a8bd05b14641cb4f8a8aa5 monolog b704c49a3051536f67f2d39f13568f74615b9922 doctrine-common b385ca770888248241bd3086a40d5b3bd082a706 doctrine-dbal e0b69790ab1ffd646fd70a04fdb91e5dfbb3ccf1 doctrine 144d0de0ab61dffc738d7fb590cff8d77919f553 swiftmailer daaff2b8515390fbb10882647311f476b89a67e6 assetic f829ad23d23c87480151a21faad49fefe7c09e5d twig-extensions d5851b96f06442e74590e5540a4209e9e3946243 metadata 8717ad2a5689480765d9ffafe925cd8a2457e582 SensioFrameworkExtraBundle dcd40eb4e2fff2d82fad644bb44fc2a40ccaf381 JMSSecurityExtraBundle b8b7eb294ed83d83ca7260ac018e701f08003538 SensioDistributionBundle 20b66a408084ad8752f98e50f10533f5245310bf SensioGeneratorBundle c6af9719ae9e81fa4e086f40697d35e7090921cc AsseticBundle 41b5913b5086a0909af92adcb4a6005ee0051b16
Is it enouth? No, another two part need to add to your deps:
[JMSAopBundle]
git=https://github.com/schmittjoh/JMSAopBundle.git
target=/bundles/JMS/AopBundle
[CGLibrary]
git=http://github.com/schmittjoh/cg-library.git
target=cg-library
At last, do not forget:
$bin/vendors install $php app/console cache:clear