Представьте, что у вас есть несколько служб, и вы хотите их отобразить
Что бы вы сделали?
Мое решение:
Контроллер:
class DefaultController extends Controller
{
public function indexAction(Request $request)
{
/** @var $em \Doctrine\ORM\EntityManager */
$em = $this->get('doctrine.orm.entity_manager');
$services = $em->getRepository('ThestudioscheduleProfileBundlesServiceBundle:Service')->findAll();
$user = $this->get('security.context')->getToken()->getUser();
$form = $this->createForm(new UserServiceType($services, $user->getServiceDetails()));
if ('POST' == $request->getMethod()) {
$form->bindRequest($request);
if ($form->isValid()) {
$data = $form->getData();
$em->getConnection()->beginTransaction();
try {
foreach ($data['services'] as $serviceDetails) {
// if service is selected
if ($serviceDetails['id']) {
$serviceDetails['details']->setUser($user);
$serviceDetails['details']->setService($em->getRepository('ThestudioscheduleProfileBundlesServiceBundle:Service')->find($serviceDetails['service']));
$serviceDetails['details'] = $em->merge($serviceDetails['details']);
} else {
// if the entity is exist but user unchecked it - delete it
if ($serviceDetails['details']->getId()) {
$serviceDetails['details'] = $em->merge($serviceDetails['details']);
$em->remove($serviceDetails['details']);
}
}
}
$em->flush();
$em->getConnection()->commit();
// TODO: display success message to user
return $this->redirect($this->generateUrl('ThestudioscheduleProfileBundlesServiceBundle_homepage'));
} catch (\Exception $e) {
$em->getConnection()->rollback();
$em->close();
var_export($e->getMessage());die;
// TODO: log exception
// TODO: display something to user about error
}
}
}
return $this->render('ThestudioscheduleProfileBundlesServiceBundle:Default:index.html.twig', array(
'form' => $form->createView()
));
}
}
Тип обслуживания пользователя:
class UserServiceType extends AbstractType
{
private $services;
private $userServiceDetails;
public function __construct($services, $userServiceDetails)
{
$this->services = $services;
$this->userServiceDetails = $userServiceDetails;
}
/**
* @param \Symfony\Component\Form\FormBuilder $builder
* @param array $options
* @return void
*/
public function buildForm(FormBuilder $builder, array $options)
{
// all application services
$builder->add('services', 'collection');
foreach ($this->services as $key => $service) {
$serviceType = new ServiceType($service, null);
foreach ($this->userServiceDetails as $details) {
if ($service == $details->getService()) {
$serviceType->setUserServiceDetails($details);
}
}
$builder->get('services')->add('service_' . $key, $serviceType);
}
}
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
public function getName()
{
return 'profile_user_service';
}
}
Тип обслуживания:
class ServiceType extends AbstractType
{
private $service;
private $userServiceDetails;
public function __construct($service, $userServiceDetails)
{
$this->service = $service;
$this->userServiceDetails = $userServiceDetails;
}
/**
* @param \Symfony\Component\Form\FormBuilder $builder
* @param array $options
* @return void
*/
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('id', 'checkbox', array(
'label' => $this->service->getName(),
'required' => false))
->add('service', 'hidden')
->add('details', new ServiceDetailsType($this->userServiceDetails));
$values = array('service' => $this->service->getId());
if (null !== $this->userServiceDetails) {
$values = array_merge($values, array('id' => true));
}
$builder->setData($values);
}
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
public function getName()
{
return 'profile_service';
}
public function setUserServiceDetails($details)
{
$this->userServiceDetails = $details;
}
}
ServiceDetailsType:
class ServiceDetailsType extends AbstractType
{
private $details;
public function __construct($details)
{
$this->details = $details;
}
/**
* @param \Symfony\Component\Form\FormBuilder $builder
* @param array $options
* @return void
*/
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('id', 'hidden')
->add('minPrice', 'money', array('required' => false))
->add('maxPrice', 'money', array('required' => false))
->add('unit', 'choice', array(
'choices' => array(
'hour' => 'Hours',
'photo' => 'Photos'
),
'required' => false
))
->add('unitsAmount', null, array('required' => false));
if (!empty($this->details)) {
$builder->setData($this->details);
}
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Thestudioschedule\ProfileBundles\ServiceBundle\Entity\UserService',
'csrf_protection' => false
);
}
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
function getName()
{
return 'profile_service_details';
}
}
Самое удивительное, что все это работает!Большое спасибо Флориану за то, что он уделил мне время и заставил меня задуматься над решением, и я прошу прощения за неясный вопрос (если он есть).Я думаю, что документы Symfony должны быть обновлены с помощью более разнообразных примеров встраивания / сбора форм, подобных этому.
Cheers, Dima.