I am new to symfony. I have decided to move my wheel with Symfony version 2.
In my user form:
This stuff took me a while to track down too, so here's what I came up with. To be honest I'm not really sure about the getRoles() method of the User entity, but this is just a test setup for me. Context items like that are provided solely for clarity.
Here are some helpful links for further reading:
I set this all up to make sure it worked as a UserProvider for security as well since I figured you were probably doing that. I also assumed you were using the email as the username, but you don't have to. You could create a separate username field and use that. See Security for more information.
The Entity (only the important parts; autogenerateable getters/setters are omitted):
namespace Acme\UserBundle\Entity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
* @ORM\HasLifecycleCallbacks()
*
* list any fields here that must be unique
* @DoctrineAssert\UniqueEntity(
* fields = { "email" }
* )
*/
class User implements UserInterface
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length="255", unique="true")
*/
protected $email;
/**
* @ORM\Column(type="string", length="128")
*/
protected $password;
/**
* @ORM\Column(type="string", length="5")
*/
protected $salt;
/**
* Create a new User object
*/
public function __construct() {
$this->initSalt();
}
/**
* Generate a new salt - can't be done as prepersist because we need it before then
*/
public function initSalt() {
$this->salt = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',5)),0,5);
}
/**
* Is the provided user the same as "this"?
*
* @return bool
*/
public function equals(UserInterface $user) {
if($user->email !== $this->email) {
return false;
}
return true;
}
/**
* Remove sensitive information from the user object
*/
public function eraseCredentials() {
$this->password = "";
$this->salt = "";
}
/**
* Get the list of roles for the user
*
* @return string array
*/
public function getRoles() {
return array("ROLE_USER");
}
/**
* Get the user's password
*
* @return string
*/
public function getPassword() {
return $this->password;
}
/**
* Get the user's username
*
* We MUST have this to fulfill the requirements of UserInterface
*
* @return string
*/
public function getUsername() {
return $this->email;
}
/**
* Get the user's "email"
*
* @return string
*/
public function getEmail() {
return $this->email;
}
/**
* Get the user's salt
*
* @return string
*/
public function getSalt() {
return $this->salt;
}
/**
* Convert this user to a string representation
*
* @return string
*/
public function __toString() {
return $this->email;
}
}
?>
The Form class:
namespace Acme\UserBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class UserType extends AbstractType {
public function buildForm(FormBuilder $builder, array $options) {
$builder->add('email');
/* this field type lets you show two fields that represent just
one field in the model and they both must match */
$builder->add('password', 'repeated', array (
'type' => 'password',
'first_name' => "Password",
'second_name' => "Re-enter Password",
'invalid_message' => "The passwords don't match!"
));
}
public function getName() {
return 'user';
}
public function getDefaultOptions(array $options) {
return array(
'data_class' => 'Acme\UserBundle\Entity\User',
);
}
}
?>
The Controller:
namespace Acme\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Acme\UserBundle\Entity\User;
use Acme\UserBundle\Form\Type\UserType;
class userController extends Controller
{
public function newAction(Request $request) {
$user = new User();
$form = $this->createForm(new UserType(), $user);
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
// encode the password
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword($user->getPassword(), $user->getSalt());
$user->setPassword($password);
$em = $this->getDoctrine()->getEntityManager();
$em->persist($user);
$em->flush();
return $this->redirect($this->generateUrl('AcmeUserBundle_submitNewSuccess'));
}
}
return $this->render('AcmeUserBundle:User:new.html.twig', array (
'form' => $form->createView()
));
}
public function submitNewSuccessAction() {
return $this->render("AcmeUserBundle:User:submitNewSuccess.html.twig");
}
Relevant section of security.yml:
security:
encoders:
Acme\UserBundle\Entity\User:
algorithm: sha512
iterations: 1
encode_as_base64: true
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity: { class: Acme\UserBundle\Entity\User, property: email }
firewalls:
secured_area:
pattern: ^/
form_login:
check_path: /login_check
login_path: /login
logout:
path: /logout
target: /demo/
anonymous: ~
Check out http://github.com/friendsofsymfony there is a UserBundle that have that functionality. You can also check http://blog.bearwoods.com where there is a blog post about adding a custom field, constraint and validator for Recaptcha.
Thoose resources should get you started on the right path if you are still running into trouble people are generally helpful and friendly on irc at #symfony-dev on the Freenode network. On Freenoce there is also a general channel #symfony where you can ask questions about how to use stuff where #symfony-dev is for the development of Symfony2 Core.
Hopefully this will help you move forward with your project.
I think the main thing you need to look out for when creating your custom validator is the constant specified in the getTargets() method.
If you change
self::PROPERTY_CONSTRAINT
to:
self::CLASS_CONSTRAINT
You should be able to access all properties of the entity, not only a single property.
Note: If you are using annotations to define your constraints you will now need to move the annotation which defines your validator up to the top of the class as it is now applicable to the whole Entity and not just the single property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With