lendable/form-error-log-bundle

This package is abandoned and no longer maintained. No replacement package was suggested.

Log form errors

v2.0.0 2017-11-24 17:39 UTC

README

Log form errors.

Functional testing your forms is all well and good, but how do you know your users are using it correctly? This plugin can log the errors your users are making so that you can spot any usability problems.

WARNING: If the error is on the whole form this bundle tries to json_encode your bound entity. If it can't be json_encoded it will try to serialize before finally logging the whole _POST request for the form. THIS IS A SECURITY RISK IF USED ON FORMS CONTAINING SENSITIVE DATA, LIKE PASSWORDS OR CREDIT CARD INFORMATION. If this is the case, you should implement the Serializeable or JsonSerializable (PHP 5.4) interfaces on your bound objects to block out the sensitive data.

Installation

This bundle is alpha stability due to the lack of testing on different form types.

Install this bundle as usual by adding to composer.json:

"lendable/form-error-log-bundle": "~1.0"

Register the bundle in app/AppKernel.php:

// app/AppKernel.php
public function registerBundles()
{
    return array(
        // ...
        new Oh\FormErrorLogBundle\OhFormErrorLogBundle(),
    );
}

Set up

There are 2 logging methods provided. One uses your normal logger (Monolog) and the other logs into a database

Method 1: Monolog

You will need to create a new channel in your monolog settings called 'formerror'

#app/config/config_prod.yml
monolog:
	handlers:
		main:
			type:         fingers_crossed
			action_level: error
			handler:      nested
		nested:
			type:  stream
			path:  %kernel.logs_dir%/%kernel.environment%.log
			level: debug
		formerror:
			type:  stream
			path:  %kernel.logs_dir%/form-error-%kernel.environment%.log
			channels: formerror

Method 2: Database

This uses Doctrine. You should create your own Entity which implements FormErrorLogEntityInterface

<?php

namespace Your\Bundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Oh\FormErrorLogBundle\Entity\FormErrorLogEntityInterface;

/**
 * @ORM\Table(name="form_error_log")
 * @ORM\Entity
 */
class FormErrorLog implements FormErrorLogEntityInterface
{
	
	/**
	 * @var integer $id
	 *
	 * @ORM\Column(name="id", type="integer")
	 * @ORM\Id
	 * @ORM\GeneratedValue(strategy="AUTO")
	 */
	private $id;
	
	/**
	 * @ORM\Column(name="form_name", type="string", length=255)
	 * @var type 
	 */
	private $form_name;
	
	/**
	 * @var string $field
	 * 
	 * @ORM\Column(name="field", type="string", length=255)
	 */
	private $field;
	
	/**
	 * @var string $error
	 * 
	 * @ORM\Column(name="error", type="string", length=2000)
	 */
	private $error;
	
	/**
	 * @var string $error
	 * 
	 * @ORM\Column(name="value", type="string", length=2000)
	 */
	private $value;

    /**
     * @var string $uri
     *
     * @ORM\Column(type="string", length=512)
     */
    private $uri;
	
	public function getFormName()
	{
		return $this->form_name;
	}

	public function setFormName($formName)
	{
		$this->form_name = $formName;
	}

	public function getField()
	{
		return $this->field;
	}

	public function setField($field)
	{
		$this->field = $field;
	}

	public function getError()
	{
		return $this->error;
	}

	public function setError($error)
	{
		$this->error = $error;
	}
	
	public function getValue()
	{
		return $this->value;
	}

	public function setValue($value)
	{
		$this->value = $value;
	}

    public function setUri($uri)
    {
        $this->uri = $uri;

        return $this;
    }

    public function getUri()
    {
        return $this->uri;
    }
	
}

You can create your own methods to store the date (I use Gedmo Timestampable)

In your parameters.yml you can set the class to your entity

#app/config/parameters.yml
oh_form_error_log.db.entity.class: Your\Bundle\Entity\FormErrorLog

Your Form

Insert the listener into your form class:

#YourBundle/Form/YourEntityType.php
<?php

namespace Your\Bundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class YourEntityType extends AbstractType
{
	public function buildForm(FormBuilderInterface $builder, array $options)
	{		
		if($options['logger']) {
			$builder->addEventSubscriber($options['logger']);
		}
	}

	public function setDefaultOptions(OptionsResolverInterface $resolver)
	{
		$resolver->setDefaults(array(
			'data_class' => 'Your\Bundle\Entity\YourEntity',
			'logger'=>false
		));
	}

	public function getName()
	{
		return 'your_bundle_yourentity';
	}
}

And in your controller

<?php

namespace Your\Bundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Your\Bundle\Entity\YourEntityType;

class YourController extends Controller
{

	public function createAction()
	{

		$form = $this->createForm(new YourEntityType(), $entity, array(
				'logger'=>$this->get('oh_form_error_log.listener'))
				// or for the database version
				//'logger'=>$this->get('oh_form_error_log.listener.db'))
			);
		
		if ($form->isValid()) {
			// do stuff
		}
		
		return array(
			'form' => $form->createView(),
		);
	}
}

Todo

  • Tests
  • Support for Symfony\Component\Serializer\Normalizer
  • Test with different FormTypes (like FileType)

Credits

  • Ollie Harridge (ollietb) as the original author.
  • Lendable Ltd as the maintainer.