I have the following issue with my form class that extends the ContentEntityForm class.
When calling the parent buildForm which is needed my system runs out of memory.
/**
* {#inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
// Here is already runs of memory. $form is never initiated.
/* #var $entity \Drupal\sg_configuration_rule\Entity\ConfigurationRule */
$entity = $this->entity;
$form_state->set('old_cron_value', $entity->get('cron_settings')->first()->value);
$type = FALSE;
if (!$entity->isNew()) {
$type = $entity->getPluginInstance()->getPluginId();
}
if ($entity->isNew()) {
$type = \Drupal::request()->query->get('type');
if (!$type) {
return new RedirectResponse(Url::fromRoute('configuration_rule.add_form_step1')->toString());
}
}
if ($type) {
try {
/** #var \Drupal\sg_base_api\Plugin\BaseApiPluginInterface $enabled_api */
$enabled_api = $this->baseApiPluginManager->createInstance($type);
}
catch (PluginException $exception) {
LoggerService::error($exception->getMessage());
return new RedirectResponse(Url::fromRoute('configuration_rule.add_form_step1')->toString());
}
$enabled_api->configRuleForm($form, $entity);
$form['plugin_type']['widget'][0]['value']['#value'] = $type;
$form['plugin_type']['widget'][0]['value']['#access'] = FALSE;
$form['plugin_type']['widget'][0]['value']['#disabled'] = TRUE;
$form['server_node']['widget']['#options'] = $this->getServerNodesByType($enabled_api->entityType());
}
$form['user_id']['#access'] = FALSE;
return $form;
}
When i check the parent function i noticed that the line:
$form = $this->form($form, $form_state); is causing this in the class EntityForm(Core method).
/**
* {#inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// During the initial form build, add this form object to the form state and
// allow for initial preparation before form building and processing.
if (!$form_state->has('entity_form_initialized')) {
$this->init($form_state);
}
// Ensure that edit forms have the correct cacheability metadata so they can
// be cached.
if (!$this->entity->isNew()) {
\Drupal::service('renderer')->addCacheableDependency($form, $this->entity);
}
// Retrieve the form array using the possibly updated entity in form state.
// This is causing my memory timeout.
$form = $this->form($form, $form_state);
// Retrieve and add the form actions array.
$actions = $this->actionsElement($form, $form_state);
if (!empty($actions)) {
$form['actions'] = $actions;
}
return $form;
}
If i comment that line out it is working fine but this is needed to save my values in config. Also this is core and should work.
Anyone else have this problem and knows the solutions to this?
Thanks.
This is solved, the error was that too much results where loaded in a select field.
Related
I am making a form collection with the fos user register form. I overrided my register form and added the profile collection, its persisting the data in the database but whenever I load the page it shows this error more then 10 times.
Warning: Invalid argument supplied for foreach() in C:\xampp\htdocs\symfony-bootstrap\vendor\symfony\symfony\src\Symfony\Component\Validator\Mapping\Loader\AnnotationLoader.php on line 65
if i complete the form and send it, it does persist, but the view is a mess showing this error 10 times and i havent seen anyone with this error.
this is my registerformtype.
namespace sava\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class RegistroType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('perfil','sava_userbundle_tblperfil');
}
public function getParent()
{
return 'fos_user_registration';
}
public function getName()
{
return 'sava_user_registration';
}
}
this is how my webpage looks http://prntscr.com/5zess0.
validator code
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien#symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Mapping\Loader;
use Doctrine\Common\Annotations\Reader;
use Symfony\Component\Validator\Exception\MappingException;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints\GroupSequence;
use Symfony\Component\Validator\Constraints\GroupSequenceProvider;
use Symfony\Component\Validator\Constraint;
class AnnotationLoader implements LoaderInterface
{
protected $reader;
public function __construct(Reader $reader)
{
$this->reader = $reader;
}
/**
* {#inheritdoc}
*/
public function loadClassMetadata(ClassMetadata $metadata)
{
$reflClass = $metadata->getReflectionClass();
$className = $reflClass->name;
$loaded = false;
foreach ($this->reader->getClassAnnotations($reflClass) as $constraint) {
if ($constraint instanceof GroupSequence) {
$metadata->setGroupSequence($constraint->groups);
} elseif ($constraint instanceof GroupSequenceProvider) {
$metadata->setGroupSequenceProvider(true);
} elseif ($constraint instanceof Constraint) {
$metadata->addConstraint($constraint);
}
$loaded = true;
}
foreach ($reflClass->getProperties() as $property) {
if ($property->getDeclaringClass()->name == $className) {
foreach ($this->reader->getPropertyAnnotations($property) as $constraint) {
if ($constraint instanceof Constraint) {
$metadata->addPropertyConstraint($property->name, $constraint);
}
$loaded = true;
}
}
}
foreach ($reflClass->getMethods() as $method) {
if ($method->getDeclaringClass()->name == $className) {
foreach ($this->reader->getMethodAnnotations($method) as $constraint) {
if ($constraint instanceof Constraint) {
if (preg_match('/^(get|is)(.+)$/i', $method->name, $matches)) {
$metadata->addGetterConstraint(lcfirst($matches[2]), $constraint);
} else {
throw new MappingException(sprintf('The constraint on "%s::%s" cannot be added. Constraints can only be added on methods beginning with "get" or "is".', $className, $method->name));
}
}
$loaded = true;
}
}
}
return $loaded;
}
}
if line 65 == foreach ($this->reader->getMethodAnnotations($method) as $constraint) ...
chceck $this->reader->getMethodAnnotations($method)
example
print_r('===><pre>');
print_r($this->reader->getMethodAnnotations($method));
print_r('</pre>');
I think, $this->reader->getMethodAnnotations($method) is not array
In symfony 5
run composer require doctrine/annotations it will fix the issue
To clean up my controller code I want to move the "newPostAction" to a service. The problem I get is that now I cannot pass as a result of the funtion in the service two variables to the controller. I use the function to create a form, and the get the slug from the form's post and render it. I do not know how to pass it to the controller. I tried using the "list()" function but it does not get the info right.
How can I call the pos's "slug" from inside the controller?
Here is the controller code:
/**
* #param Request $request
* #return array
*
* #Route("/new/_post", name="_blog_backend_post_new")
* #Template("BlogBundle:Backend/Post:new.html.twig")
*/
public function newPostAction(Request $request)
{
$form_post = $this->getPostManager()->createPost($request);
$slug_post = ¿How do I get it from inside the createPost()?;
if (true === $form_post)
{
$this->get('session')->getFlashBag()->add('success', 'Your post was submitted successfully');
return $this->redirect($this->generateUrl('blog_blog_post_show', array('slug' => $slug_post)));
}
return array(
'post_slug' => $slug_post,
'form_post' => $form_post->createView()
);
}
Here is the PostManager service to create the new post entity:
/**
* Create and validate a new Post
*
* #param Request $request
* #return bool|FormInterface
*/
public function createPost (Request $request)
{
$post = new Post();
$post->setAuthor($this->um->getloggedUser());
$form_post = $this->formFactory->create(new PostType(), $post);
$form_post->handleRequest($request);
$slug_post = $post->getSlug();
if ($form_post->isValid())
{
$this->em->persist($post);
$this->em->flush();
return true;
}
return $form_post;
}
You just need to return an array from the service and access the values from the controller.
UPDATE
Some changes need to be made to your code in order to get things to work.
Explanation: when the form is valid, the previous code (I deleted it) returned true therefore $ret["form_post"] didn't make sense because $ret was not an array. It surprises me that it didn't throw you an error.
Anyway, that could explain why Doctrine didn't persist your entity. Talking about the redirection, the error could be due to the same reason. $ret was true (a boolean) and $ret["form_slug"] didn't make sense either.
I hope this fixes the problems. Please, let me know if it works.
Service
public function createPost (Request $request)
{
$post = new Post();
$post->setAuthor($this->um->getloggedUser());
$form_post = $this->formFactory->create(new PostType(), $post);
$form_post->handleRequest($request);
$slug_post = $post->getSlug();
if ($form_post->isValid())
{
$this->em->persist($post);
$this->em->flush();
return array("form_post" => true, "slug_post" => $slug_post);;
}
return array("form_post" => $form_post, "slug_post" => $slug_post);
}
Controller:
public function newPostAction(Request $request)
{
$ret = $this->getPostManager()->createPost($request);
$form_post = $ret["form_post"];
$slug_post = $ret["slug_post"];
if (true === $form_post)
{
$this->get('session')->getFlashBag()->add('success', 'Your post was submitted successfully');
return $this->redirect($this->generateUrl('blog_blog_post_show', array('slug' => $slug_post)));
}
return array(
'post_slug' => $slug_post,
'form_post' => $form_post->createView()
);
}
I have a problem with edititng embedded collection form. I have two object with many-to-one relation. When I create an object "Good" with related "photos" all successfully. When I update the Good object by adding some new photos all works fine too. But, if I try to delete a one photo in some Good object after update photo is not deleted.
Good.php
/**
* #ORM\OneToMany(targetEntity="Photo", mappedBy="good", cascade={"persist", "remove"})
**/
private $photos;
/**
* Add photos
*
* #param \VDKP\Site\BackendBundle\Entity\Photo $photos
* #return Good
*/
public function addPhoto(\VDKP\Site\BackendBundle\Entity\Photo $photos)
{
$photos->setGood($this);
$this->photos->add($photos);
return $this;
}
/**
* Remove photos
*
* #param \VDKP\Site\BackendBundle\Entity\Photo $photos
*/
public function removePhoto(\VDKP\Site\BackendBundle\Entity\Photo $photos)
{
$this->photos->removeElement($photos);
}
/**
* Get photos
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPhotos()
{
return $this->photos;
}
Photo.php
/**
* #ORM\ManyToOne(targetEntity="Good", inversedBy="photos")
* #ORM\JoinColumn(name="good_id", referencedColumnName="id")
**/
private $good;
GoodController, updateACtion:
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('VDKPSiteBackendBundle:Good')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Good entity.');
}
$originalPhotos = new \Doctrine\Common\Collections\ArrayCollection();
foreach ($entity->getPhotos() as $photo) {
$originalPhotos->add($photo);
}
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
foreach ($originalPhotos as $photo) {
if (false === $entity->getPhotos()->contains($photo)) {
$photo->setGood(null);
$em->persist($photo);
}
}
$em->persist($entity);
$em->flush();
}
return $this->redirect($this->generateUrl('good_edit', array('id' => $id)));
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
I did everything as written in the documentation here.
Sorry for my english. Thank you for your help.
It looks like you missed this part of docs:
foreach ($originalTags as $tag) {
if (false === $task->getTags()->contains($tag)) {
// remove the Task from the Tag
$tag->getTasks()->removeElement($task);
// if it was a many-to-one relationship, remove the relationship like this
// $tag->setTask(null);
$em->persist($tag);
// if you wanted to delete the Tag entirely, you can also do that
// $em->remove($tag);
}
}
So, I think you have to do something similar with your data types: Good and Photo.
I think, documentation is inaccurate, because:
In this part of code:
$originalTags = new ArrayCollection();
// Create an ArrayCollection of the current Tag objects in the database
foreach ($task->getTags() as $tag) {
$originalTags->add($tag);
}
we collect Tags, which have relations with current Task in database.
In this part of code:
foreach ($originalTags as $tag) {
if (false === $task->getTags()->contains($tag)) {
// remove the Task from the Tag
$tag->getTasks()->removeElement($task);
// if it was a many-to-one relationship, remove the relationship like this
// $tag->setTask(null);
$em->persist($tag);
// if you wanted to delete the Tag entirely, you can also do that
// $em->remove($tag);
}
}
we must compare $request data and $originalTags array data. But, we compare $originalTags with $task->getTags(), which is essentially the same.
I am new in Zend, my problem can be simple for you. I want to make a controller that displays form input data in another view. data are an email text and a text file uploaded. I created the index view and result view.
but i get nothing. when I replace the value of $email with text it works!! I can't find what is going wrong.
The controller also should display a sorted file by firstname
Id,Firstname,Lastname
5,John,Doe
6,Adam,Ant
7,Victor,Hugo
8,Britannie,Spears
this is my controller :
public function indexAction()
{
// initialzing of the customized form
$form = new Application_Form_Upload();
$rq = $this->getRequest();
$isForm = true; // the form has to be shown only if true
if ($rq->isPost()) {
if ($form->isValid($rq->getPost())) {
// show the uploaded data instead of the form
$isForm = false;
$this->view->data = new Application_Model_DataViewer();
$this->view->data->parseFromForm($form);
$result = new Zend_View();
$this->view->result= $result;
$this->render('result');
}
}
if ($isForm) {
$this->view->form = $form;}
}
this is my model :
class Application_Model_DataViewer
{
/**
* #var string Entered e-mail address
*/
private $email;
/**
* #var array Array of extracted data from uploaded file
*/
private $data;
public function __construct(){
$this->email=null;
$this->data=array();
}
/**
* Extracts the data from the form-object and saves it internally
* #param $form Application_Form_Upload
*/
public function parseFromForm($form){
if(!isset($form))return;
if(!isset($form->file)||!$form->file instanceof Zend_Form_Element_File){
throw new Zend_Exception('The field File is empty or has wrong type');
}
// for validation of the IDs
$ival = new Zend_Validate_Int();
// reading the CSV-file (values should be separated by comma, if not - should be extended)
if(($fp = #fopen($form->file->getFileName(), 'r')) !== false){
while(($data = fgetcsv($fp, 500, ',')) !== false){
if(
!is_array($data)
||!$ival->isValid($data[0])
||count($data)<3
)continue;
$this->data[$data[1]] = $data;
}
}else{return;}
#fclose($fp);
ksort($this->data);
$this->email = $form->getValue('email');
}
/**
* #return null|string
*/
public function getEmail(){
return $this->email;
}
/**
* #return array
*/
public function getData(){
return $this->data;
}
}
and here is my index and result views
<?php
// the form should only be rendered if form must be shown
if(isset($this->form)){
$this->form->setAction($this->url());
echo $this->form;
}
?>
result view:
<?php
// if the required data is submitted, it will be checked and displayed
if(isset($this->data)){
?>
<p>Thank you <strong><?php echo $this->escape($this->data->getEmail()); ?></strong>.</p>
<p>The result of the sorting is:
<?php
foreach($this->data->getData() as $row){
echo '<div>', $this->escape($row[0]), ',',
$this->escape($row[1]), ',',
$this->escape($row[2]), '</div>';
}
?></p><?php
}
?>
Use the partial helper in the view.
See: http://framework.zend.com/manual/2.2/en/modules/zend.view.helpers.partial.html
eg. your index.phtml
if ($this->data) {
echo $this->partial("result.phtml", array("data" => $this->data->getData()));
}
you can access the variable in result.phtml by $this->data
I need some improvements about my actual way to delete entities:
public function deleteAction($path)
{
$form = $this->createFormBuilder(array('path' => $path))
->add('path')
->setReadOnly(true)
->getForm();
if ($this->getRequest()->getMethod() === 'POST') {
$form->bindRequest($this->getRequest());
if ($form->isValid()) {
$image = $this->getImageManager()->findImageByPath($path);
$this->getImageManager()->deleteImage($image);
return $this->redirect($this->generateUrl('AcmeImageBundle_Image_index'));
}
}
return $this->render('AcmeImageBundle:Image:delete.html.twig', array(
'form' => $form->createView(),
));
}
Two improvements I already found while writting:
CreateFormBuilder in extra method in controller
Hidden field and overgive extra image-entity to get rendered
Are there other thing I could make better?
Regards
(my answer is too long for the comment so i add it here)
First you have to create a Type file (generally in YourApp\YourBundle\Form\yourHandler.php), some basique code to put inside if you don't know:
<?php
namespace ***\****Bundle\Form;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManager;
use ***\****Bundle\Entity\your_entity;
class *****Handler
{
protected $form;
protected $request;
protected $em;
public function __construct(Form $form, Request $request, EntityManager $em)
{
$this->form = $form;
$this->request = $request;
$this->em = $em;
}
public function process()
{
if( $this->request->getMethod() == 'POST' )
{
$this->form->bindRequest($this->request);
if( $this->form->isValid() )
{
$this->onSuccess($this->form->getData());
return true;
}
}
return false;
}
public function onSuccess(your_entity $object)
{
// Make your stuff here (remove,....)
}
}
And in your controller i just call it this way:
if (!empty($_POST))
{
$formHandler = new *****Handler($my_form, $this->get('request'), $this->getDoctrine()->getEntityManager());
$formHandler->process();
}
Hope i'm clear enough