Commit e5836a24 authored by Antonin's avatar Antonin

Contact form

parent d9977726
ACL
---
- Créer pages contenu
- Page de contact mail
- Footer
- Design plus cohérent (breadcrumb dans le template ?, séparation fullwidth)
- Nouvelle couleurs ?
- Pages dans le menu (automatique ?)
- Problème small devices titre + menu barre
- Ajouter les pages crées dans le menu
- Nettoyage (commentaires, code non utilisé, indentation)
- Validation (html, css, bonnes pratiques, sitemap, etc)
- Animation de démarage seulement la premièer fois (session ? Cookie ?)
- Traductions manquantes
- Traductions manquantes (admin + )
- Autopublish ?
- Mise en ligne automatique
- Conservation des données ?
......@@ -14,8 +17,6 @@ ACL
- Mail (site + info adhérants)
- Wysiwyg
- Commentaires filtrés / controllés
-
Mail
----
......
......@@ -76,9 +76,6 @@ class AppKernel extends Kernel
new Application\Sonata\SeoBundle\ApplicationSonataSeoBundle(),
new Sonata\DatagridBundle\SonataDatagridBundle(),
// Search Integration
//new FOS\ElasticaBundle\FOSElasticaBundle(),
// CMF Integration
new Symfony\Cmf\Bundle\RoutingBundle\CmfRoutingBundle(),
......@@ -87,8 +84,16 @@ class AppKernel extends Kernel
new Sonata\TimelineBundle\SonataTimelineBundle(),
new Application\Sonata\TimelineBundle\ApplicationSonataTimelineBundle(), // easy extends integration
// Boostrap
new Mopa\Bundle\BootstrapBundle\MopaBootstrapBundle(),
// ACL bundle
new ACL\Bundle\ACLBundle\ACLBundle(),
// Contact page
new Mremi\ContactBundle\MremiContactBundle(),
new Application\Mremi\ContactBundle\ApplicationMremiContactBundle(),
new Genemu\Bundle\FormBundle\GenemuFormBundle(),
);
if (in_array($this->getEnvironment(), array('dev', 'test'))) {
......
......@@ -446,6 +446,12 @@ class SymfonyRequirements extends RequirementCollection
);
}
$this->addRequirement(
function_exists('iconv'),
'iconv() must be available',
'Install and enable the <strong>iconv</strong> extension.'
);
$this->addRequirement(
function_exists('json_encode'),
'json_encode() must be available',
......@@ -546,10 +552,10 @@ class SymfonyRequirements extends RequirementCollection
require_once __DIR__.'/../vendor/autoload.php';
try {
$r = new \ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle');
$r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle');
$contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php');
} catch (\ReflectionException $e) {
} catch (ReflectionException $e) {
$contents = '';
}
$this->addRecommendation(
......@@ -638,7 +644,7 @@ class SymfonyRequirements extends RequirementCollection
}
$this->addRecommendation(
class_exists('Locale'),
extension_loaded('intl'),
'intl extension should be available',
'Install and enable the <strong>intl</strong> extension (used for validators).'
);
......
......@@ -42,9 +42,9 @@ foreach ($symfonyRequirements->getRecommendations() as $req) {
}
if ($checkPassed) {
echo_block('success', 'OK', 'Your system is ready to run Symfony2 projects', true);
echo_block('success', 'OK', 'Your system is ready to run Symfony2 projects');
} else {
echo_block('error', 'ERROR', 'Your system is not ready to run Symfony2 projects', true);
echo_block('error', 'ERROR', 'Your system is not ready to run Symfony2 projects');
echo_title('Fix the following mandatory requirements', 'red');
......
......@@ -35,6 +35,9 @@ imports:
- { resource: sonata/sonata_user.yml }
- { resource: sonata/sonata_notification.yml }
# Contact bundle
- { resource: contact.yml }
framework:
#esi: ~
translator: { fallbacks: ["%locale%"] }
......
mremi_contact:
store_data: false
contact_class: Application\Mremi\ContactBundle\Model\Contact
form:
type: application_contact
name: contact_form
validation_groups: [ApplicationValidation]
subject_provider: mremi_contact.subject_provider.noop
captcha_type: genemu_captcha
email:
mailer: mremi_contact.mailer.twig_swift
from:
- { address: "%email_from_address%", name: "%email_from_name%"}
to:
- { address: "%email_to_address%", name: "%email_to_name%"}
template: MremiContactBundle:Contact:email.txt.twig
services:
application_frontend.contact_form_type:
class: Application\Mremi\ContactBundle\Type\ContactType
tags:
- { name: form.type, alias: application_contact }
arguments: ["@mremi_contact.subject_provider.noop", "Application\Mremi\ContactBundle\Model\Contact", "genemu_captcha"]
genemu_form:
captcha: ~
\ No newline at end of file
......@@ -7,4 +7,7 @@ _admin:
_api:
resource: routing_api.yml
prefix: /api
\ No newline at end of file
prefix: /api
mremi_contact_form:
resource: "@MremiContactBundle/Resources/config/routing.xml"
\ No newline at end of file
......@@ -19,8 +19,9 @@ sonata_page:
- ^/api/(.*)
ignore_route_patterns:
- (.*)admin(.*) # ignore admin route, ie route containing 'admin'
- ^_(.*) # ignore symfony routes
- (.*)admin(.*) # ignore admin route, ie route containing 'admin'
- ^_(.*) # ignore symfony routes
- ^mremi_contact_(.*) # ignore contact stuff
ignore_routes:
- sonata_page_cache_esi
......
......@@ -73,7 +73,10 @@
"stephpy/TimelineBundle": "~2.0@dev",
"stephpy/timeline": "~1.0@dev",
"incenteev/composer-parameter-handler": "~2.0"
"incenteev/composer-parameter-handler": "~2.0",
"mremi/contact-bundle": "dev-master",
"genemu/form-bundle": "2.2.*"
},
"require-dev": {
"sensio/generator-bundle": "~2.3"
......@@ -91,7 +94,6 @@
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::removeSymfonyStandardFiles"
],
"post-update-cmd": [
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
......
This diff is collapsed.
<?php
/**
* Created by PhpStorm.
* User: antonin
* Date: 11/10/15
* Time: 12:02 PM
*/
namespace Application\Mremi\ContactBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ApplicationMremiContactBundle extends Bundle
{
public function getParent()
{
return 'MremiContactBundle';
}
}
\ No newline at end of file
<?php
/*
* This file is part of the Mremi\ContactBundle Symfony bundle.
*
* (c) Rémi Marseille <marseille.remi@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Application\Mremi\ContactBundle\Model;
use Mremi\ContactBundle\Model\ContactInterface;
/**
* Contact class.
*
* @author Rémi Marseille <marseille.remi@gmail.com>
*/
class Contact implements ContactInterface
{
/**
* @var string
*/
protected $title;
/**
* @var string
*/
protected $firstName;
/**
* @var string
*/
protected $lastName;
/**
* @var string
*/
protected $email;
/**
* @var string
*/
protected $subject;
/**
* @var string
*/
protected $message;
/**
* @var mixed
*/
protected $captcha;
/**
* @var \DateTime
*/
protected $createdAt;
/**
* Constructor.
*/
public function __construct()
{
$this->setCreatedAt(new \DateTime());
}
/**
* {@inheritdoc}
*/
public function setCaptcha($captcha)
{
$this->captcha = $captcha;
}
/**
* {@inheritdoc}
*/
public function getCaptcha()
{
return $this->captcha;
}
/**
* {@inheritdoc}
*/
public function setCreatedAt(\DateTime $createdAt)
{
$this->createdAt = $createdAt;
}
/**
* {@inheritdoc}
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* {@inheritdoc}
*/
public function setEmail($email)
{
$this->email = $email;
}
/**
* {@inheritdoc}
*/
public function getEmail()
{
return $this->email;
}
/**
* {@inheritdoc}
*/
public function setFirstName($firstName)
{
$this->firstName = $firstName;
}
/**
* {@inheritdoc}
*/
public function getFirstName()
{
return $this->firstName;
}
/**
* {@inheritdoc}
*/
public function setLastName($lastName)
{
$this->lastName = $lastName;
}
/**
* {@inheritdoc}
*/
public function getLastName()
{
return $this->lastName;
}
/**
* {@inheritdoc}
*/
public function getFullName()
{
return sprintf('%s %s', $this->firstName, $this->lastName);
}
/**
* {@inheritdoc}
*/
public function setMessage($message)
{
$this->message = $message;
}
/**
* {@inheritdoc}
*/
public function getMessage()
{
return $this->message;
}
/**
* {@inheritdoc}
*/
public function setSubject($subject)
{
$this->subject = $subject;
}
/**
* {@inheritdoc}
*/
public function getSubject()
{
return $this->subject;
}
/**
* {@inheritdoc}
*/
public function setTitle($title)
{
$validTitles = self::getTitleKeys();
if (!in_array($title, $validTitles)) {
throw new \InvalidArgumentException(sprintf('Invalid title %s, possible values are: %s', $title, implode(', ', $validTitles)));
}
$this->title = $title;
}
/**
* {@inheritdoc}
*/
public function getTitle()
{
return $this->title;
}
/**
* {@inheritdoc}
*/
public function getTitleValue()
{
$titles = self::getTitles();
if (!empty($titles[$this->title]))
return $titles[$this->title];
else
return null;
}
/**
* {@inheritdoc}
*/
public static function getTitles()
{
return array(
self::TITLE_MR => 'mremi_contact.form.title_mr',
self::TITLE_MRS => 'mremi_contact.form.title_mrs',
);
}
/**
* {@inheritdoc}
*/
public static function getTitleKeys()
{
return array_keys(self::getTitles());
}
/**
* {@inheritdoc}
*/
public function toArray()
{
return array(
'title' => $this->title,
'firstName' => $this->firstName,
'lastName' => $this->lastName,
'email' => $this->email,
'subject' => $this->subject,
'message' => $this->message,
'createdAt' => $this->createdAt->format('c'),
);
}
/**
* {@inheritdoc}
*/
public function fromArray(array $data)
{
foreach ($data as $property => $value) {
if (!$value) {
// prevent to call setters which raise an exception if value is not valid (title for instance)
// data can be null if associated field is removed from the form
continue;
}
$method = sprintf('set%s', ucfirst($property));
$this->$method('createdAt' === $property ? new \DateTime($value) : $value);
}
}
/**
* {@inheritdoc}
*/
public function serialize()
{
return serialize($this->toArray());
}
/**
* {@inheritdoc}
*/
public function unserialize($data)
{
$this->fromArray(unserialize($data));
}
}
<?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>ApplicationValidation</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>ApplicationValidation</value></option>
</constraint>
</property>
<property name="lastName">
<constraint name="NotBlank">
<option name="message">mremi_contact.last_name.blank</option>
<option name="groups"><value>ApplicationValidation</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>ApplicationValidation</value></option>
</constraint>
</property>
<property name="email">
<constraint name="NotBlank">
<option name="message">mremi_contact.email.blank</option>
<option name="groups"><value>ApplicationValidation</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>ApplicationValidation</value></option>
</constraint>
<constraint name="Email">
<option name="message">mremi_contact.email.invalid</option>
<option name="groups"><value>ApplicationValidation</value></option>
</constraint>
</property>
<property name="subject">
<constraint name="NotBlank">
<option name="message">mremi_contact.subject.blank</option>
<option name="groups"><value>ApplicationValidation</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>ApplicationValidation</value></option>
</constraint>
</property>
<property name="message">
<constraint name="NotBlank">
<option name="message">mremi_contact.message.blank</option>
<option name="groups"><value>ApplicationValidation</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>ApplicationValidation</value></option>
</constraint>
</property>
<property name="createdAt">
<constraint name="DateTime">
<option name="message">mremi_contact.created_at.invalid</option>
<option name="groups"><value>ApplicationValidation</value></option>
</constraint>
</property>
</class>
</constraint-mapping>
{#
This file is part of the Mremi\ContactBundle Symfony bundle.
(c) Rémi Marseille <marseille.remi@gmail.com>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
#}
{% extends "form_div_layout.html.twig" %}
{% block form_start %}
{% spaceless %}
{% set method = method|upper %}
{% if method in ["GET", "POST"] %}
{% set form_method = method %}
{% else %}
{% set form_method = "POST" %}
{% endif %}
{% set attr = attr|merge({'class': attr.class|default('') ~ ' form-horizontal', 'role': 'form'}) %}
{% if app.debug and app.request.query.get('novalidate') %}
{% set action = action|default('') ~ '?novalidate=1' %}
{% set attr = attr|merge({'novalidate': 'novalidate'}) %}
{% endif %}
<form method="{{ form_method|lower }}" action="{{ action }}"{% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}{% if multipart %} enctype="multipart/form-data"{% endif %}>
{% if form_method != method %}
<input type="hidden" name="_method" value="{{ method }}" />
{% endif %}
{% endspaceless %}
{% endblock form_start %}
{% block form_label %}
{% spaceless %}
{% set label_attr = label_attr|merge({'class': label_attr.class|default('') ~ ' col-lg-2 control-label' }) %}
{% if not compound %}
{% set label_attr = label_attr|merge({'for': id}) %}
{% endif %}
{% if required %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{% endif %}
{% if label is empty %}
{% set label = name|humanize %}
{% endif %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ label|trans({}, translation_domain) }}
{% if required %} *{% endif %}
</label>
{% endspaceless %}
{% endblock %}
{% block form_row %}
{% spaceless %}
<div class="form-group{% if errors|length > 0 %} has-error{% endif %}">
{{ form_label(form, label|default(null)) }}
<div class="col-lg-3">
{% set attr = attr|merge({'class': attr.class|default('') ~ ' form-control'}) %}
{{ form_widget(form, {'attr': attr}) }}
{{ form_errors(form) }}
</div>
</div>
{% endspaceless %}
{% endblock form_row %}
{% block choice_widget_expanded %}
{% spaceless %}
{% set label_attr = label_attr|merge({'class': label_attr.class|default('') ~ ' radio-inline'}) %}
{% for child in form %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ form_widget(child) }}
{{ child.vars.label|trans({}, translation_domain) }}
</label>
{% endfor %}
{% endspaceless %}
{% endblock choice_widget_expanded %}
{% block button_row %}
{% spaceless %}
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
{% set attr = attr|merge({'class': attr.class|default('') ~ ' btn btn-default'}) %}
{{ form_widget(form, {'attr': attr}) }}
</div>
</div>
{% endspaceless %}
{% endblock button_row %}
{% block form_errors %}
{% spaceless %}
{% if errors|length > 0 %}
<span class="help-block">
{% for error in errors %}
{{ error.messageTemplate|trans(error.messageParameters, 'validators') }}<br />
{% endfor %}