Home > Software engineering >  Template doesn't work in Symfony - how to connect a new function?
Template doesn't work in Symfony - how to connect a new function?

Time:09-17

I'm creating an app and I want to enable users to change their data and password. I've created an email changing form and it works, but I've got a problem with password. I've got a page localhost:8000/user/{id} and here the buttons: edit email and edit password. Edit email is working and when I click on editing password - I got a blank page on localhost:8000/user/{id}/change_password (enter image description here enter image description here). Th PassType doesn't show there.

There are no syntax error on localhost:8000/user/{id} and localhost:8000/user/{id}/change_password.

I've added a function edit_pass to UserController, crated PassType (where is the form to change password) and make a template edit_password.html.twig.

I don't know where is the problem. I did the same thing as with other Forms which work. I've tried to clear the edit_password template (I've just left the base_html there and put some text) cause I've thought there is a problem in it, but it was still a blank page on localhost:8000/user/{id}/change_password.

PassType:

<?php
/*
 * Password type.
 */

namespace App\Form;

use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
 * Class PassType.
 */
class PassType extends AbstractType
{
    /**
     * Builds the form.
     *
     * This method is called for each type in the hierarchy starting from the
     * top most type. Type extensions can further modify the form.
     *
     * @see FormTypeExtensionInterface::buildForm()
     *
     * @param FormBuilderInterface $builder The form builder
     * @param array                $options The options
     */
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add(
            'password',
            RepeatedType::class,
            [
                'type' => PassType::class,
                'required' => true,
                'attr' => ['max_length' => 40],
                'first_options' => ['label' => 'label.password'],
                'second_options' => ['label' => 'label.repeat_password'],
            ]
        );
    }

    /**
     * Configures the options for this type.
     *
     * @param OptionsResolver $resolver The resolver for the options
     */
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults(['data_class' => User::class]);
    }

    /**
     * Returns the prefix of the template block name for this type.
     *
     * The block prefix defaults to the underscored short class name with
     * the "Type" suffix removed (e.g. "UserProfileType" => "user_profile").
     *
     * @return string The prefix of the template block name
     */
    public function getBlockPrefix(): string
    {
        return 'user';
    }
}

edit_password.html.twig

{% extends 'base.html.twig' %}

{% block title %}
    {{ 'title_password_edit'|trans({'%id%': user.id|default('')}) }}
{% endblock %}

{% block body %}
    <h1 class="display-4 d-flex justify-content-center">{{ 'title_password_edit'|trans({'%id%': user.id|default('')}) }}</h1>
    {{ form_start(form, { method: 'PUT', action: url('password_edit', {id: user.id}) }) }}
    {{ form_widget(form) }}
    <div class="form-group row float-sm-right">
        <input type="submit" value="{{ 'action_save'|trans }}" class="btn btn-primary" />
    </div>
    <div class="form-group row float-sm-left">
        <a href="{{ url('user_index') }}" class="btn btn-link">
            {{ 'action_back_to_list'|trans }}
        </a>
    </div>
    {{ form_end(form) }}

{% endblock %}

and part of UserController whith edit_pass function

 /**
     * Edit Password.
     *
     * @param \Symfony\Component\HttpFoundation\Request $request    HTTP request
     * @param \App\Entity\User                          $user       User entity
     * @param \App\Repository\UserRepository            $repository User repository
     *
     * @return \Symfony\Component\HttpFoundation\Response HTTP response
     *
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     *
     * @Route(
     *     "/{id}/change_password",
     *     methods={"GET", "PUT"},
     *     requirements={"id": "[1-9]\d*"},
     *     name="password_edit",
     * )
     */
    public function edit_pass(Request $request, User $user, UserPasswordEncoderInterface $passwordEncoder, UserRepository $repository): Response
    {
        $form = $this->createForm(PassType::class, $user, ['method' => 'PUT']);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $user->setPassword(
                $passwordEncoder->encodePassword(
                    $user,
                    $form->get('password')->getData()
                )
            );
            $repository->save($user);

            $this->addFlash('success', 'message.updated_successfully');

            return $this->redirectToRoute('user_show', array('id' => $this->getUser()->getId()));
        }

        return $this->render(
            'user/edit_password.html.twig',
            [
                'form' => $form->createView(),
                'user' => $user,
            ]
        );
    }

I'm also adding the user/show.html.twig

{% extends 'base.html.twig' %}

{% block title %}
    {{ 'label_detail_users'|trans({'%id%': user.id|default('')}) }}
{% endblock %}

{% block body %}
    <h1 class="display-4 d-flex justify-content-center">{{ 'label_detail_users'|trans({'%id%': user.id|default('')}) }}</h1>
    {% if users is defined and users|length %}
        <table class="table table-striped">
            <thead>
            <tr>
                <th>{{ 'label_user_id'|trans }}</th>
                <th>{{ 'label_email'|trans }}</th>
            </tr>
            </thead>
            <tbody>
                <tr>
                    <td>{{ users.id }}</td>
                    <td>{{ users.email }}</td>
                </tr>
            </tbody>
        </table>
        <p>
            <a class="btn btn-info" href="{{ url('user_edit', {id: users.id}) }}" title="{{ 'edit_email'|trans }}">
                {{ 'edit_email'|trans }}
            </a>
        </p>
        <p>
            <a class="btn btn-info" href="{{ url('password_edit', {id: users.id}) }}" title="{{ 'edit_password'|trans }}">
                {{ 'edit_password'|trans }}
            </a>
        </p>
        <p>
            <a class="btn btn-info" href="{{ url('user_index') }}" title="{{ 'action_back_to_list'|trans }}">
                {{ 'action_back_to_list'|trans }}
            </a>
        </p>

    {% else %}
        <p>
            {{ 'message_item_not_found'|trans }}
        </p>
    {% endif %}
{% endblock %}

CodePudding user response:

You produced an endless loop - its PasswordType in your RepeatedType. PassType is the name of your whole Form - you see the problem?

public function buildForm(FormBuilderInterface $builder, array $options): void
{
    $builder->add(
        'password',
        RepeatedType::class,
        [
            'type' => PasswordType::class,
            'required' => true,
            'attr' => ['max_length' => 40],
            'first_options' => ['label' => 'label.password'],
            'second_options' => ['label' => 'label.repeat_password'],
        ]
    );
}

And may I ask why you limit the length of a password?

  • Related