symfonytwig

neither the property school nor one of the methods school(), getschool()/... exist and have public access in class Symfony\Component\Form\FormView


I am getting the following error:

neither the property school nor one of the methods school(), getschool()/isschool()/hasschool() or __call() exist and have public access in class Symfony\Component\Form\FormView

I don't have enough characters left to post the Organizations entity class.

Here is my controller function

public function convertTrialAction(
        EventDispatcherInterface $dispatcher,
        NetResultsService $netResultsService,
        Request $request,
        #[MapEntity(mapping: ["groupId"=> "groupId"] )] Organization $organization): Response
    {
        // default to 1000 student ids
        $organization->setMaxStudents(Organization::UNLIMITED_ID_CAP);
        $form = $this->createForm(ConvertTrialType::class, $organization);
        $form->handleRequest($request);
        // dump($form);

        $allGood = true;
        
        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->doctrine->getManager();
            // update max students
            $organization->setMaxStudents($form->get('maxStudents')->getData());

            // create or select school
            // it's possible we already have a school for this org, in which case the field has been removed from the form
            if ($form->has('school')) {
                $newOrExistingSchool = $form->get('school')->getData();
                if ($newOrExistingSchool['existingSchool'] instanceof School) {
                    $organization->setSchool($newOrExistingSchool['existingSchool']);
                } else {
                    if ($newOrExistingSchool['newSchool'] instanceof School) {
                        $school = $newOrExistingSchool['newSchool'];
                        $em->persist($school);
                        $organization->setSchool($school);
                    } else {
                        $form->get('school')->addError(
                            new FormError('Either New School or Existing School must be provided')
                        );
                        $allGood = false;
                    }
                }
            }

            $subscriptionData = $form->get('subscriptions')->getData();
            foreach ($subscriptionData['applications'] as $app) {
                $sub = $organization->getSubscriptionFor($app);
                if (!$sub) {
                    $sub = new OrganizationSubscription();
                    $sub->setApplication($app)
                        ->setOrganization($organization);
                }
                $sub->setExpiresOn($subscriptionData['expiresOn'])
                    ->setSubscriptionType($subscriptionData['subscriptionType']);
                $em->persist($sub);
            }

            if ($allGood) {
                try {
                    $em->flush();

                    // dispatch edit event
                    $event = new FilterOrganizationEvent($organization);
                    $dispatcher->dispatch($event, CoreEvents::ORGANIZATION_EDIT);

                    // now that the trial has been converted, update NetResults
                    $netResultsService->updateContact($organization->getPrimaryUser()->getEmail(), [
                        'WBLPurchase' => 'Yes',
                        'WBLClassification' => $organization->getSchool()->getCategoryLabel(),
                        'WBLTrial' => 'Converted'
                    ]);

                    $this->addFlash('success', 'Converted customer from trial');
                    return $this->redirectToRoute('admin_organization_view', ['groupId' => $organization->getGroupId()]);
                } catch (Exception $e) {
                    $form->addError(new FormError($e->getMessage()));
                }
            }
        }

        return $this->render('Admin/Organizations/convertTrial.html.twig', [
            'form' => $form->createView(),
            'organization' => $organization,
            'isTrial' => $organization->isTrialCustomer()
        ]);
    }

here is converTrialType.php form file

<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use App\Entity\Organization;

class ConvertTrialType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('school', SelectOrCreateSchoolType::class, ['mapped' => false, 'required' => true])
            ->add('maxStudents', IntegerType::class)
            ->add('subscriptions', SubscriptionsType::class, ['mapped' => false])
            ;

        $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
            $org = $event->getData();
            $form = $event->getForm();

            if ($org instanceof Organization && $org->getSchool() !== null) {
                $form->remove('school');
            }
        });
    }

    public function configureOptions(OptionsResolver $resolver)
    {
    }

    public function getBlockPrefix() : string
    {
        return 'whitebox_admin_bundle_convert_trial_type';
    }
}

Twig file:

{% extends "Admin/Organizations/base.html.twig" %}
{% import "Macros/twitter-bootstrap.html.twig" as bs %}

{% block title "Convert Trial Customer: " ~ organization %}

{% block breadcrumbs %}
    {{
    bs.breadcrumbs([
        {'href': path('admin_home'), 'label': 'Home'},
        {'href': path('admin_organizations'), 'label': 'Groups'},
        {'href': path('admin_organization_view', { 'groupId': organization.groupId }), 'label': organization.groupId },
        {'href': null, 'label': 'Convert Trial to Customer'}
    ])
    }}
{% endblock %}

{% block content %}
    <div class="alert alert-{{ isTrial ? 'info' : 'warning' }}">
        <p>
            You are updating the group named <strong>{{ organization.name }}</strong> in
            <strong>{{ organization.location }}</strong>,
            owned by teacher <strong>{{ organization.primaryUser }}</strong>.
            <br/>
            <em>However,</em> this customer appears to have had at least one paid subscription and
            may not be considered a trial user at this point.
        </p>
        <p>
            Completing this form will convert the teacher from a trial customer to a paid customer.
            Please review all fields carefully before submitting the form.
        </p>
    </div>
    {{ form_start(form, { attr: { class: 'form-horizontal' }}) }}
    {{ form_errors(form) }}
    {% if form.school %}
        <div class="panel space-b">
            <h3>Step 1: Select or Create School</h3>
            <div class="row-fluid">
                <div class="span4">
                    <div class="pad-all">
                        <p>
                            If the school that this customer belongs to is already in the database, you can
                            type the school name to select it.  If adding a new school, please complete the form.
                        </p>
                        <p class="text-warning">
                            <strong><em>Be sure to do one or the other, but not both.</em></strong>
                        </p>
                        <p>
                            <strong>Tip: </strong> If you know the zip code, type it first and the
                            city/state fields will be automatically filled.
                        </p>
                        <p>
                            If the school belongs to a district, you can start typing the name of an existing
                            district to select it here.  If you are creating a new district, you may want
                            to use the Create District wizard.
                        </p>
                    </div>
                </div>
                <div class="span8">
                    <div class="pad-all">
                        {{ form_row(form.school.existingSchool) }}
                        <p class="hr-text">OR</p>
                        {{ form_row(form.school.newSchool) }}
                    </div>
                </div>
            </div>
        </div>
    {% else %}
        <div class="panel space-b">
            <h3>Step 1: Select or Create School</h3>
            <div class="row-fluid">
                <div class="span4">
                    <div class="pad-all">
                        This customer already belongs to a school.  Nothing to do here!
                    </div>
                </div>
                <div class="span8">
                    <div class="pad-all">
                        {{ organization.school.name }}
                        <br/>
                        {{ organization.school.city }}, {{ organization.school.state }}
                    </div>
                </div>
            </div>
        </div>
    {% endif %}
    <div class="panel space-b">
        <h3>Step 2: Update Max Students</h3>
        <div class="row-fluid">
            <div class="span4">
                <div class="pad-all">
                    <p>
                        For standard subscriptions, the max number of students is "unlimited", but has a literal cap of
                        1000.  This has been set as the default but you may change it for "limited use" customers or for
                        special cases.
                    </p>
                </div>
            </div>
            <div class="span8">
                <div class="pad-all">
                    {{ form_row(form.maxStudents) }}
                </div>
            </div>
        </div>
    </div>
    <div class="panel space-b">
        <h3>Step 3: Update Subscriptions</h3>
        <div class="row-fluid">
            <div class="span4">
                <div class="pad-all">
                    <p>
                        Check all subscriptions that have been purchased and set the expiration.  Existing subscriptions
                        for any applications that are not checked will remain unchanged.
                    </p>
                    <p>
                        <strong>Tip</strong>: Use the "Defaults" dropdown to pre-select common subscription periods.  You can also click
                        the dropdown arrow on the date field to reveal a calendar tool, or manually type the date in
                        the mm/dd/yyyy format.
                    </p>
                </div>
            </div>
            <div class="span8">
                <div class="pad-all">
                    {{ form_widget(form.subscriptions) }}
                </div>
            </div>
        </div>
    </div>
    <button class="btn btn-primary btn-large">Save</button>
    <a href="{{ path('admin_organization_view', { groupId: organization.groupId }) }}"
       class="btn btn-large btn-default">Cancel</a>
    {{ form_end(form) }}
{% endblock %}

Solution

  • In your twig template you have the line:

    {% if form.school %}
    

    But school may not be defined, as you remove the field in some cases in ConvertTrialType. This could trigger the error you've described. You can resolve it by replacing the line in twig with

    {% if form.school is defined %}
    

    https://twig.symfony.com/doc/3.x/tests/defined.html