PHP define constants with arrays

You need to define a constant containing an array but the code below doesn’t work ?

define('FILTER_ECOLE', array('price, categorie, niveau'));

You get an error :

Notice: Use of undefined constant FILTER_ECOLE - assumed 'FILTER_ECOLE'  in /home/www/adin/app/code/local/Adin/Catalog/Block/Nav/Catalog/Layer/View/Sidebar.php on line 50

To define an use a constant containing an array you can simply serialize it :

#define
define('FILTER_ECOLE', serialize(array('price, categorie, niveau')));

#use
$filter = unserialize(FILTER_ECOLE);

PHP – Use of undefined constant MCRYPT_BLOWFISH – assumed ‘MCRYPT_BLOWFISH

While your coding session, you encounter this error :

Use of undefined constant MCRYPT_BLOWFISH - assumed 'MCRYPT_BLOWFISH

You think, easy, a module should be missing on my php
So you install it :

sudo apt-get install php5-mcrypt

And restart apache.

But it still doesn’t work. In phpinfo() it seems the module is not installed.

In fact with the new version of PHP, you still need to activate the module

php5enmod -s apache2 mcrypt

The restart apache and the module should work.

doctrine2 random

For some really good reasons or, doctrine2 do not implement the RAND() fonction to sort randomly your query results. Here some dirty ways to do it. Don’t use them it’s bad.

One solution is to shuffle your collection of rows using php

      public function getRandom($max = 10,$site) {
        $results = $this->createQueryBuilder('u')
                ->where('u.site = :site')
                ->setParameter('site', $site)
                ->orderBy('u.sort', 'DESC')
                ->setMaxResults($max)
                ->getQuery()
                ->getResult();
        shuffle($results);
        return $results;
    }

In this solution, you retrieve the last 10 rows and shuffle them after. Peformances are not too bad but you will always retrieves the same last rows from your table.

Another solution is to use the array_rand php fonction

      public function getRandom($site) {
        $results = $this->createQueryBuilder('u')
                ->where('u.site = :site')
                ->setParameter('site', $site)
                ->orderBy('u.sort', 'DESC')
                ->getQuery()
                ->getResult();
        $result2 = array_rand($results);
        return $result2;
    }

In this case you fetch all rows from your table, this could be slow and memory consuming…

If you need to retrieve only one row, you can use somethinfg like this

 public function getOneRandom()
{
$em = $this->getEntityManager();
$max = $em->createQuery('
SELECT MAX(q.id) FROM questions q
')
->getSingleScalarResult();
return $em->createQuery('
SELECT q FROM questions q
WHERE q.id >= :random
ORDER BY q.id ASC
')
->setParameter('random',rand(0,$max))
->setMaxResults(1)
->getSingleResult();
}

This solution can only be used if you want to retrieve any of the tables rows, if you add a filtrer you may return an empty result.

This solution is not dirty it just use 2 queries instead of one. the tips is to use the offset. And you can use a filter !!!

$qCount = Doctrine::getTable('Questions')
     ->createQuery()
     ->select('count(*)')
     ->where('site = :site')
     ->setParameter('site', $site)
     ->fetchOne(array(), Doctrine::HYDRATE_NONE);
$question = Doctrine::getTable('Questions')
     ->createQuery()
     ->select('*')
     ->where('site = :site')
     ->setParameter('site', $site)
     ->limit(1)
     ->offset(rand(0, $qCount[0] - 1))
     ->fetchOne();

And you still can use native queries : http://docs.doctrine-project.org/en/latest/reference/native-sql.html

Using GnuPG with PHP

GnuPG is a great tool to encrypt texts and files and you can use it with PHP, only if you install it succesfully.

First, you will get this error : Fatal error: Class ‘gnupg’ not found in ….

OK the lib is not installed, do it with pecl

pecl install gnupg

But you will also have this error :

configure: error: Please reinstall the gpgme distribution
ERROR: `/tmp/pear/temp/gnupg/configure' failed

You need to install the libgpgme too !!!

apt-get install libgpgme11-dev

Now retry to install gnupg

pecl install gnupg

It should be OK.

Don’t forget to modify your php.ini file to load the extension

extension=gnupg.so

And of course, restart your apache web server

/etc/init.d/apache2 restart

PHP form limited to 1000 fields

Since PHP 5.3.9 form are limited to 1000 fields by default.
To fix it, you can edit your php.ini file and modify this variable

max_input_vars = 4000

And don’t forget to restart apache.

You can also edit it in your .htaccess file

 php_value max_input_vars 4000 

Change it directly in your php file with this

 ini_set('php_value max_input_vars', 4000); 

won’t work.

But change this varible may not fix your issue.
If you have suhosin installed, you laso have to edit his configuration file (/etc/php5/apache2/conf.d/suhosin.ini)

suhosin.get.max_vars = 4000 
suhosin.post.max_vars = 4000 
suhosin.request.max_vars = 4000 

To check your suhison configuration, use phpinfo() or in your php script

echo ini_get('suhosin.post.max_vars');

Doctrine2 override save method

With Doctrine2 you cannot override save method but you can execute preUpdate() method.
See below how to implement it.

On your entity class, for example AdminBundle/Entity/Annonce.php, add the HasLifecycleCallbacks annontation

/**
 * @ORM\Entity(repositoryClass="Tripix\AdminBundle\Repository\AnnonceRepository")
 * @ORM\HasLifecycleCallbacks
 */

And your method, with the annotation

/** @ORM\PreUpdate() */
        public function preUpdate()
        {
                $this->created_at = new \DateTime("now");
        }

That’s all, it should works.

A complete example, just in case :

<?php
namespace Tripix\AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;


/**
 * @ORM\Entity(repositoryClass="Tripix\AdminBundle\Repository\AnnonceRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Annonce
{

/** @ORM\PreUpdate() */
        public function preUpdate()
        {
                $this->created_at = new \DateTime("now");
        }

    public function __construct()
    {
        $this->created_at = new \DateTime("now");
        $this->visuels = new ArrayCollection();
    }

Symfony2 sonata custom CRUD template

It is possible to change templates use by default.

First, override the controller action method, in your AdminBundle/Controller/SecteurAdminController.php file

 /**
     * return the Response object associated to the list action
     *
     * @return Response
     */
    public function listAction()
    {
        if (false === $this->admin->isGranted('LIST')) {
            throw new AccessDeniedException();
        }

        $datagrid = $this->admin->getDatagrid();
        $formView = $datagrid->getForm()->createView();

        // set the theme for the current Admin Form
        $this->get('twig')->getExtension('form')->setTheme($formView, $this->admin->getFilterTheme());

        //custom code from here
        $total = 0;
        $enable = 0;
        $new = 0;
        $site = $this->admin->site;

        $repository = $this->getDoctrine()->getRepository('TripixAdminBundle:Annonce');
        $total = $repository->getNombreAnnonceTotal($site);
        $enable = $repository->getNombreAnnonceEnabled($site);
        $new = $repository->getNombreAnnonceNew($site);



        return $this->render('TripixAdminBundle:CRUD:list_secteur.html.twig', array(
            'action'   => 'list',
            'form'     => $formView,
            'datagrid' => $datagrid,
            'total'     => $total,
            'enable'    => $enable,
            'new'       => $new,
        ));
    }

The import thing on previous code is the render() fonction, the first parameter is the template to use.
In our example, the template file will be /AdminBundle/Ressources/view/CRUD/list_secteur.html.twig

You can use the /AdminBundle/Ressources/view/CRUD/base_secteur.html.twig file as example for your custom template.

Parent function to override on the controller are here : /vendor/bundles/Sonata/AdminBundle/Controller/CRUDController.php

Symfony2 Sonata add custom column on page list

To add a custom column on a page list, just follow these steps. In the example, we will add a “Nombre d’annoce(s)” column.

On your admin class file (ex: /AdminBundle/Admin/SecteurAdmin.php), on your configureListFields() fonction, add a new entry on the listMapper object

    /**
     * @param \Sonata\AdminBundle\Datagrid\ListMapper $listMapper
     * @return void
     */
    protected function configureListFields(ListMapper $listMapper) {
        $listMapper
                ->addIdentifier('titre')
                ->add('Tri', 'string', array('template' => 'TripixAdminBundle:Admin:list_tri.html.twig'))
                ->add('Nb', 'string', array('label' => 'Nombre d\'annonce(s)', 'template' => 'TripixAdminBundle:Admin:list_nb_annonce.html.twig'))
                ->add('_action', 'actions', array(
                    'actions' => array(
                        'edit' => array(),
                        'delete' => array(),
                    )
                ))
        ;
    }

This new entry said to use the TripixADminBundle:Admin:list_tri.html.twig template.

Now, create your template file (list_nb_annonce.html) in the /AdminBundle/ressources/view/admin/ directory.

{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}

{% block field%}
{% if admin.datagrid.results|length > 1 %}
 <div>
        <strong>{{ object.getNombreAnnonce}}</strong>
    </div>
{% endif %}
{% endblock %}

In our example, getNombreAnnonce() is not defined, let’s do it
In the /adminBundle/Entity/Secteur.php file, add

   public function getNombreAnnonce()
    {
      return count($this->getAnnonces());
    }

That’s all.