mremi / ContactBundle

Provides a contact form for a Symfony project.
27 stars 23 forks source link

Extends the bundle for remove unwanted fields and add new ones #6

Closed reypm closed 10 years ago

reypm commented 10 years ago

It's possible to remove fields like for example title and add new ones like phone and company? How I do that and where? In ContactType.php?

mremi commented 10 years ago

Hi, you can define your own form type with the semantic config:

# app/config/config.yml
mremi_contact:
    form:
        type: your_custom_type

Then you can extend the form type provided by this bundle and remove/add what you want.

Maybe you could create a pull request to add some documentation about this?

reypm commented 10 years ago

@mremi Yes, I can create a PR and add some docs but first needs to get this working. This is the steps I followed:

Copy the content of file https://github.com/mremi/ContactBundle/blob/master/Form/Type/ContactType.php to FrontendBundle/Form/TanContactType.php and fix namespaces and names. This is the content of TanContactType.php:

namespace Tan\FrontendBundle\Form\Type;
class TanContactType extends AbstractType
{
    // The rest of the file

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'tan_contact';
    }
}

Then in config I tried with:

mremi_contact:
    form:
        type:              Tan\FrontendBundle\Form\TanContactType
        name:              contact_form
        validation_groups: [Default]
        subject_provider:  mremi_contact.subject_provider.noop
        captcha_disabled:  false
        captcha_type:      genemu_captcha

Error:

Could not load type "Tan\FrontendBundle\Form\TanContactType"

And:

mremi_contact:
    form:
        type:              tan_contact
        name:              contact_form
        validation_groups: [Default]
        subject_provider:  mremi_contact.subject_provider.noop
        captcha_disabled:  false
        captcha_type:      genemu_captcha

Error:

Could not load type "tan_contact"

What I miss?

mremi commented 10 years ago

The second solution is the good one, with type: tan_contact. But you need to define this new service, for example:

# app/config/config.yml
services:
    tan_frontend.contact_form_type:
        class: Tan\FrontendBundle\Form\Type\TanContactType
        tags:
            -  { name: form.type, alias: tan_contact }
        # inject your needs...
        # arguments: []

You can also do it in the xml format, see http://symfony.com/doc/current/book/forms.html#defining-your-forms-as-services

reypm commented 10 years ago

Good, I fixed that part but know I'm getting this error:

Catchable Fatal Error: Argument 1 passed to Tan\FrontendBundle \Form\TanContactType::__construct() must be an instance of Mremi\ContactBundle\Provider \SubjectProviderInterface, none given, called in /var/www/html/tan/var/cache /dev/appDevDebugProjectContainer.php on line 7016 and defined in /var/www/html/tan/src/Tan /FrontendBundle/Form/TanContactType.php line 42

I think due to I didn't inject the Interface, I was looking in MremiContactExtension.php but didn't found which one to pass as arguments, any advice?

mremi commented 10 years ago

This fatal means you extend the ContactType, so you have to inject the dependencies. You have to do it yourself (following are default values):

# app/config/config.yml
services:
    tan_frontend.contact_form_type:
        class: Tan\FrontendBundle\Form\Type\TanContactType
        tags:
            -  { name: form.type, alias: tan_contact }
        arguments: ["@mremi_contact.subject_provider.noop", "Mremi\ContactBundle\Model\Contact", false, "genemu_captcha"]
reypm commented 10 years ago

@mremi Excellent, apparently it works now, I'll do some more test and if all go fine then I'll made a PR for docs to include this part as a suggestion will be nice if we could use Google reCaptcha instead this one on the Bundle, think on it as a new feature and if you need any help from me let me know

mremi commented 10 years ago

GenemuFormBundle already provides it: https://github.com/genemu/GenemuFormBundle/blob/master/Resources/doc/recaptcha/index.md . To use it, you need to configure it and then:

# app/config/config.yml
mremi_contact:
    form:
        captcha_type: genemu_recaptcha
reypm commented 10 years ago

Well something isn't good here since I'm getting this message all the time:

Please select a title

This is the content of TanContactType.php:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
            ->remove('title')
            ->add('firstName', 'text', array('label' => 'mremi_contact.form.first_name'))
            ->add('lastName', 'text', array('label' => 'mremi_contact.form.last_name'))
            ->add('company', 'text', array('label' => 'Compañía', 'mapped' => false))
            ->add('phone', 'text', array('label' => 'Teléfono(s)', 'mapped' => false))
            ->add('email', 'email', array('label' => 'mremi_contact.form.email'));

    if ($subjects = $this->subjectProvider->getSubjects()) {
        $builder->add('subject', 'choice', array(
            'choices' => $subjects,
            'label' => 'mremi_contact.form.subject',
        ));
    }
    else {
        $builder->add('subject', 'text', array('label' => 'mremi_contact.form.subject'));
    }

    $builder->add('message', 'textarea', array('label' => 'mremi_contact.form.message'));

    if (!$this->captchaDisabled) {
        $builder->add('captcha', $this->captchaType, array(
            'label' => 'mremi_contact.form.captcha',
            'mapped' => false,
        ));
    }

    $builder->add('save', 'submit', array('label' => 'mremi_contact.form_submit'));
}

Why, if I'm removing the title, validator continue asking for them?

mremi commented 10 years ago

Try this:

<?xml version="1.0" ?>
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
        http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

    <class name="Mremi\ContactBundle\Model\Contact">

        <property name="firstName">
            <constraint name="NotBlank">
                <option name="message">mremi_contact.first_name.blank</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
            <constraint name="Length">
                <option name="min">2</option>
                <option name="minMessage">mremi_contact.first_name.short</option>
                <option name="max">50</option>
                <option name="maxMessage">mremi_contact.first_name.long</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
        </property>

        <property name="lastName">
            <constraint name="NotBlank">
                <option name="message">mremi_contact.last_name.blank</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
            <constraint name="Length">
                <option name="min">2</option>
                <option name="minMessage">mremi_contact.last_name.short</option>
                <option name="max">50</option>
                <option name="maxMessage">mremi_contact.last_name.long</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
        </property>

        <property name="email">
            <constraint name="NotBlank">
                <option name="message">mremi_contact.email.blank</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
            <constraint name="Length">
                <option name="min">2</option>
                <option name="minMessage">mremi_contact.email.short</option>
                <option name="max">254</option>
                <option name="maxMessage">mremi_contact.email.long</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
            <constraint name="Email">
                <option name="message">mremi_contact.email.invalid</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
        </property>

        <property name="subject">
            <constraint name="NotBlank">
                <option name="message">mremi_contact.subject.blank</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
            <constraint name="Length">
                <option name="min">2</option>
                <option name="minMessage">mremi_contact.subject.short</option>
                <option name="max">50</option>
                <option name="maxMessage">mremi_contact.subject.long</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
        </property>

        <property name="message">
            <constraint name="NotBlank">
                <option name="message">mremi_contact.message.blank</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
            <constraint name="Length">
                <option name="min">2</option>
                <option name="minMessage">mremi_contact.message.short</option>
                <option name="max">500</option>
                <option name="maxMessage">mremi_contact.message.long</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
        </property>

        <property name="createdAt">
            <constraint name="DateTime">
                <option name="message">mremi_contact.created_at.invalid</option>
                <option name="groups">
                    <value>TanValidation</value>
                </option>
            </constraint>
        </property>
    </class>

</constraint-mapping>
# app/config/config.yml
mremi_contact:
    form:
        validation_groups: [TanValidation]

Note also that:

reypm commented 10 years ago

@mremi I did the validation as you suggest but in .yml format since I have others validators in there and it works, after fix the email.txt.twig template and add my own additions as type has I get this error:

Method "company" for object "Mremi\ContactBundle\Model\Contact" does not exist in MremiContactBundle:Contact:email.txt.twig at line 5

This is the content of email.txt.twig:

{% trans_default_domain 'MremiContactBundle' %}

{% block body_text %}
{% autoescape false %}
{{ 'mremi_contact.email_message_txt'|trans({
    '%firstName%': contact.firstName,
    '%lastName%':  contact.lastName,
    '%company%':  contact.company,
    '%phone%':  contact.phone,
    '%email%':     contact.email,
    '%message%':   contact.message
}) }}
{% endautoescape %}
{% endblock %}

{% block body_html %}
{% autoescape false %}
{{ 'mremi_contact.email_message_html'|trans({
    '%firstName%': contact.firstName,
    '%lastName%':  contact.lastName,
    '%company%':  contact.company,
    '%phone%':  contact.phone,
    '%email%':     contact.email,
    '%message%':   contact.message|nl2br
}) }}
{% endautoescape %}
{% endblock %}

What's wrong?

But this only render those two fields the rest wasn't rendered, is the call wrong?

reypm commented 10 years ago

@mremi Trying to find a solution for this problem I'm having I create a model at Tan\FrontendBundle\Model\TanContact.php and extends or at least try from Mremi\ContactBundle\Model\Contact. See the code below:

namespace Tan\FrontendBundle\Model;
use Mremi\ContactBundle\Model\Contact;

class TanContact extends Contact
{

    /**
     * @var string
     */
    protected $company;

    /**
     * @var string
     */
    protected $phone;

    public function __construct()
    {
        parent::__construct();
    }

    public function setCompany($company)
    {
        $this->company = $company;
    }

    /**
     * {@inheritdoc}
     */
    public function getCompany()
    {
        return $this->company;
    }

    /**
     * {@inheritdoc}
     */
    public function setPhone($phone)
    {
        $this->phone = $phone;
    }

    /**
     * {@inheritdoc}
     */
    public function getPhone()
    {
        return $this->phone;
    }

    /**
     * {@inheritdoc}
     */
    public function toArray()
    {
        return array(
            'title' => $this->title,
            'firstName' => $this->firstName,
            'lastName' => $this->lastName,
            'email' => $this->email,
            'subject' => $this->subject,
            'message' => $this->message,
            'company' => $this->company,
            'phone' => $this->phone,
            'createdAt' => $this->createdAt->format('c'),
        );
    }
}

But I still having the issue, any advice?

mremi commented 10 years ago

About your first problem, is the TanContactType extend the ContactType? About the 2nd, you forgot to inject your model class into your form service tan_frontend.contact_form_type (replace mine by yours).

reypm commented 10 years ago

No at the moment I wrote the post but now it's extending from ContactType and ContactType overwrite TanType. This is the code of TanType at this moment:

class TanContactType extends ContactType
{
    public function __construct()
    {
        parent::__construct();
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);
        $builder
                ->remove('title')
                ->add('company', 'text', array('label' => 'Compañía', 'mapped' => false))
                ->add('phone', 'text', array('label' => 'Teléfono(s)', 'mapped' => false));
    }
}

I don't know what is wrong there. And where should I replace tan_frontend.contact_form_type? This is my services definition at config.yml:

services:
    tan_frontend.contact_form_type:
        class: Tan\FrontendBundle\Form\TanContactType
        tags:
            -  { name: form.type, alias: tan_contact }
        arguments: ["@mremi_contact.subject_provider.noop", "Mremi\ContactBundle\Model\Contact", false, "genemu_captcha"]

Should I pass my own Tan\FrontendBundle\ModelTanContact model which extends from Mremi\ContactBundle\Model\Contact instead of yours on the arguments or not?

mremi commented 10 years ago

So if your form type extends mine, you should see all fields, including those of this bundle.

For the model, yes you have to replace the second argument because you override both form and model.

reypm commented 10 years ago

@mremi I get this error:

The data class "Tan\FrontendBund\Model\TanContact" is not a valid class.

This is the content of that file:

namespace Tan\FrontendBundle\Model;
use Mremi\ContactBundle\Model\Contact;

class TanContact extends Contact
{

    protected $company;
    protected $phone;

    public function __construct()
    {
        parent::__construct();
    }

    public function setCompany($company)
    {
        $this->company = $company;
    }

    public function getCompany()
    {
        return $this->company;
    }

    public function setPhone($phone)
    {
        $this->phone = $phone;
    }

    public function getPhone()
    {
        return $this->phone;
    }

    public function toArray()
    {
        return array(
            'title' => $this->title,
            'firstName' => $this->firstName,
            'lastName' => $this->lastName,
            'email' => $this->email,
            'subject' => $this->subject,
            'message' => $this->message,
            'company' => $this->company,
            'phone' => $this->phone,
            'createdAt' => $this->createdAt->format('c'),
        );
    }
}

What's wrong in that class?

mremi commented 10 years ago

The error message shows the namespace is wrong: Tan\FrontendBund\Model\TanContact instead of Tan\FrontendBundle\Model\TanContact

reypm commented 10 years ago

Still having issues now this is the error:

The form's view data is expected to be an instance of class Tan\FrontendBundle\Model \TanContact, but is an instance of class Mremi\ContactBundle\Model\Contact

I though this is due to this 'data_class' => $this->class in my custom type, but if I set this to null what will be the result? The data_class is only for persistence or it's used for something else?

mremi commented 10 years ago

Can you show me both mremi_contact config and service definition of tan_frontend.contact_form_type?

reypm commented 10 years ago

Sure,

services:
    tan_frontend.contact_form_type:
        class: Tan\FrontendBundle\Form\TanContactType
        tags:
            -  { name: form.type, alias: tan_contact }
        arguments: ["@mremi_contact.subject_provider.noop", "Tan\FrontendBundle\Model\TanContact", false, "genemu_captcha"]

mremi_contact:
    form:
        type:              tan_contact
        name:              contact_form
        validation_groups: [TanValidation]
        subject_provider:  mremi_contact.subject_provider.noop
        captcha_disabled:  false
        captcha_type:      genemu_captcha

And if this help this is how my TanContactType.php looks:

namespace Tanane\FrontendBundle\Form;
use Tanane\FrontendBundle\Model\TananeContact;
use Mremi\ContactBundle\Form\Type\ContactType;

class TananeContactType extends ContactType
{

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);
        $builder
                ->remove('title')
                ->add('company', 'text', array('label' => 'Company', 'mapped' => false))
                ->add('phone', 'text', array('label' => 'Phone', 'mapped' => false));
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'tanane_contact';
    }

}
mremi commented 10 years ago

You have to add contact_class: Tan\FrontendBundle\Model\TanContact in the mremi_contact config. It is used by the contact manager to create a new contact instance.

reypm commented 10 years ago

Grrrrr now it says that my TanContactType isn't compatible with FormTypeInterface::buildForm():

Compile Error: Declaration of Tan\FrontendBundle\Form\TanContactType::buildForm() must be compatible with Symfony\Component\Form\FormTypeInterface::buildForm(Symfony\Component \Form\FormBuilderInterface $builder, array $options)

My form looks like the one I leave in the post above

mremi commented 10 years ago

I think you forgot a use statement, can you show me the header of this file?

reypm commented 10 years ago

Sure,

namespace Tan\FrontendBundle\Form;
use Tan\FrontendBundle\Model\TanContact;
use Mremi\ContactBundle\Form\Type\ContactType;
mremi commented 10 years ago

So a use is missing for FormBuilderInterface

reypm commented 10 years ago

Still not working :-(:

Invalid title , possible values are: mr, mrs

And also the email I'm getting miss values for: %subject% and the fields I'm adding %company% and %phone% so apparently the bundle isn't getting the right form since in TanContactType I'm removing title and setting up company, phone

mremi commented 10 years ago

This exception is raised because you removed the title field, but the setter is still called. You can override this method like this for instance:

public function setTitle($title)
{
    if ($title) {
        parent::setTitle($title);
    }
}

About the email, can you dump the contact variable in the confirmAction (after clearing your cookie to be sure your session is clean)?

mremi commented 10 years ago

@paquitodev Something new?

reypm commented 10 years ago

@mremi sorry I was out for a few days but I'm back now. The title issue is fixed with your suggestion. This is the result of var_dump($contact):

object(Tan\FrontendBundle\Model\TanContact)[503] 
    protected 'company' => null 
    protected 'phone' => null 
    protected 'title' => null 
    protected 'firstName' => string 'Reynier' (length=7) 
    protected 'lastName' => string 'Perez' (length=5) 
    protected 'email' => string 'reynierpm@gmail.com' (length=19) 
    protected 'subject' => string 'Test' (length=4) 
    protected 'message' => string 'Test' (length=4) 
    protected 'createdAt' => object(DateTime)[117] 
        public 'date' => string '2014-08-02 07:57:53.000000' (length=26) 
        public 'timezone_type' => int 1 
        public 'timezone' => string '-04:30' (length=6)

And this is the email I'm getting in my inbox:

Subject: %subject% Send by: Reynier Perez From company: Email: reynierpm@gmail.com Phone: Message: Test

Something is wrong and I can't find where

mremi commented 10 years ago

In a previous comment, you pasted email.txt.twig, still the same content? If so, subject variable is not passed to the trans Twig function. About company and phone, is your TanContact::toArray method still contains these properties as you show me previously? If so, can you dump the $contact and $_POST variables in the indexAction when form is valid?

reypm commented 10 years ago

I fixed the subject issue by adding this line: '%subject%': contact.subject, to the email.txt.twig. Now as for the other issue I'm getting this error:

An exception has been thrown during the rendering of a template ("Notice: Undefined index: in /var/www/html/tan/vendor/mremi/contact-bundle/Mremi/ContactBundle/Model/Contact.php line 197") in MremiContactBundle:Contact:confirm.html.twig at line 6.

Where this is the line 197

mremi commented 10 years ago

This exception is raised because you removed the title field, so you have to override the template Contact/confirm.html.twig. This should be the last "problem" :)

reypm commented 10 years ago

Not at all, you're right I have removed the %title% from confirm.html.twig but still not getting company and phone in the email I receive, any other advice?

mremi commented 10 years ago

What about the second part of my answer from yesterday?

reypm commented 10 years ago

Yes, the toArray() function still the same at Tan\FrontendBundle\Model\TanContact.php, see below:

public function toArray()
{
    return array(
        'title' => $this->title,
        'firstName' => $this->firstName,
        'lastName' => $this->lastName,
        'email' => $this->email,
        'subject' => $this->subject,
        'message' => $this->message,
        'company' => $this->company,
        'phone' => $this->phone,
        'createdAt' => $this->createdAt->format('c'),
    );
}

This is the output of var_dump($contact):

object(Tanane\FrontendBundle\Model\TananeContact)[988]
  protected 'company' => null
  protected 'phone' => null
  protected 'title' => null
  protected 'firstName' => string 'Reynier' (length=7)
  protected 'lastName' => string 'Perez Mira' (length=10)
  protected 'email' => string 'reynierpm@gmail.com' (length=19)
  protected 'subject' => string 'Test' (length=4)
  protected 'message' => string 'Testing' (length=7)
  protected 'createdAt' => 
    object(DateTime)[989]
      public 'date' => string '2014-08-03 02:05:15.000000' (length=26)
      public 'timezone_type' => int 3
      public 'timezone' => string 'America/Caracas' (length=15)

And this is the output of var_dump($_POST)

array (size=1)
  'contact_form' => 
    array (size=10)
      'firstName' => string 'Reynier' (length=7)
      'lastName' => string 'Perez Mira' (length=10)
      'email' => string 'reynierpm@gmail.com' (length=19)
      'subject' => string 'Test' (length=4)
      'message' => string 'Testing' (length=7)
      'captcha' => string '9987' (length=4)
      'save' => string '' (length=0)
      'company' => string 'Freelance' (length=9)
      'phone' => string '04241805609' (length=11)
      '_token' => string 'OzIaoNUMnvLUoS4UvKOkNCevB50RHVUeXwUHt3G7rzg' (length=43)
mremi commented 10 years ago

Just remove the option mapped to the company and phone fields in your TanContactType ;-)

reypm commented 10 years ago

@mremi thanks it's done I'll write the doc about this and made a PR

mremi commented 10 years ago

:+1:

webdevilopers commented 9 years ago

:+1: Any update on a docs section for this @paquitodev ?

reypm commented 9 years ago

Not at the moment I'll made a PR with this but at this moment I'm very busy so you'll need to wait

Sent from my MotoG On Nov 30, 2014 4:17 PM, "webDEVILopers" notifications@github.com wrote:

[image: :+1:] Any update on a docs section for this @paquitodev https://github.com/paquitodev ?

— Reply to this email directly or view it on GitHub https://github.com/mremi/ContactBundle/issues/6#issuecomment-64999626.

numerogeek commented 9 years ago

Hi @mremi ,

This issue is itself a great doc, but it miss a point : I'd like to remove the title field, but I have activated the database storage. Currently, and following this step-by-step tutorial, I finally have a doctrine error sayin that de title field can't be null ( Constraint violation..) In your xml, nothin is specified, so it's required by default. Do you have an idea about how to override the mapping ?

Thx !

mremi commented 9 years ago

Hi @numerogeek ,

The mapping file should be updated with nullable="true" for all fields except createdAt. Thus, all the use cases will be covered. Do you want to do it?