I am getting PDOException in edit album "SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'artist' cannot be null". I debugged the code and found that after edit form action runs all the column(id,title,artist) values change to the null value in the insert statement, whereas it should be POST values of the edit form. I am using the same code as of ZF2 tutorial.
$request->getPost() has correct edited values but $form->getData() returns empty form post values for (id,title,artist).
can anybody please help.
My code is:
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('album', array(
'action' => 'add'
));
}
$album = $this->getAlbumTable()->getAlbum($id);
$form = new AlbumForm();
$form->bind($album);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getAlbumTable()->saveAlbum($form->getData());
// Redirect to list of albums
return $this->redirect()->toRoute('album');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
According to the ZF2 example, shouldn't it be
$this->getAlbumTable()->saveAlbum($album);
instead of
$this->getAlbumTable()->saveAlbum($form->getData());
Because you have already bind the $album which attaches the model to the form. This basically does two things
Displays the initial values fetched from that Album with unique ID
After validation of the form the data is put back into the model.
Just try what I have suggested
Perhaps you were experiencing the same issue as I did when creating an Entity (Model object) that was to be bound to the Form object.
The mistake I made was that I was providing always a new instance of the InputFilter from the entity's method
getInputFilter();
And after calling $form->isValid(), Zend Form was actually looking to see if there is an entity object bound to it...if so, then it would call the $entity->getInputFilter(), inside the form's $this->bindValues() method and after receiving the filter object the code would return $filter->getValues() to populate the bound model. Since the entity was always returning new InputFilter instance, naturally the values were empty/null.
For me, the mistake was writing something like this in the entity(Model):
public function getInputFilter()
{
return new SomeInputFilter();
}
But actually, I needed to write the method like this:
public function getInputFilter()
{
if(empty($this->inputFilter)){
$this->inputFilter = new SomeInputFilter();
}
return $this->inputFilter;
}
As you can see, the solution was to set a protected property $inputFilter, and populate it with a new instance of the InputFilter object only if it's empty. Didn't pay attention to the docs thoroughly while I was coding, and was having the same issue as you did (empty data in the bound model), while trying to insert a record.
Hopefully, you'll find this useful, if not however, I'm sorry to waste your time reading this. :)
P.S.: Thank you for reading my answer and I know I am a little late with the response to the topic, but I've recently started working with Zend 2 Framework, and I've experienced a similar issue, so I tried to share my 2 cents in the hope of helping somehow if possible.
Related
I have created a project that have three tables (hardwarePlacement , HardwareUnitType, hardwareUnit)
And created the entities / controllers for them, with get, post, put and delete.
And it works perfectly when i test the methods for hardwarePlacement and HardwareUnitType, but the last table "hardwareUnit" is a relational table to the other two. so i have Forign keys (hardwarePlacementId and HardwareUnitTypeId).
So when i from postman try to make a post request, i get the error: "that my setHardwareUnitTypeId and hardwarePlacementId must be of type integer".
In my HardwareUnit entity i have the following for the other tables:
#[ORM\ManyToOne(inversedBy: 'hardwareUnits')]
#[ORM\JoinColumn(nullable: false)]
private ?HardwareUnitType $hardwareUnitTypeId = null;
#[ORM\ManyToOne(inversedBy: 'hardwareUnits')]
#[ORM\JoinColumn(nullable: false)]
private ?HardwarePlacement $hardwarePlacementId = null;
public function getHardwareUnitTypeId(): ?HardwareUnitType
{
return $this->hardwareUnitTypeId;
}
public function setHardwareUnitTypeId(?HardwareUnitType $hardwareUnitTypeId): self
{
$this->hardwareUnitTypeId = $hardwareUnitTypeId;
return $this;
}
public function getHardwarePlacementId(): ?HardwarePlacement
{
return $this->hardwarePlacementId;
}
public function setHardwarePlacementId(?HardwarePlacement $hardwarePlacementId): self
{
$this->hardwarePlacementId = $hardwarePlacementId;
return $this;
}
And my create method in HardwareUnit controller:
#[Route('/hardwareUnit', name: 'hardwareUnit_new', methods: ['POST'])]
public function new(ManagerRegistry $doctrine, Request $request): JsonResponse
{
$entityManager = $doctrine->getManager();
$hardwareUnit = new HardwareUnit();
$hardwareUnit->setHardwareUnitTypeId($request->request->get('hardwareUnitTypeId'));
$hardwareUnit->setHardwarePlacementId($request->request->get('hardwarePlacementId'));
$hardwareUnit->setName($request->request->get('name'));
$hardwareUnit->setCreatedDate(new \DateTime());
$hardwareUnit->setEditedDate(new \DateTime());
$entityManager->persist($hardwareUnit);
$entityManager->flush();
return $this->json('Oprettet ny hardware unit id: ' . $hardwareUnit->getId());
}
I have tried retrieving request as intval:
$hardwareUnit->setHardwareUnitTypeId($request->request->get(intval('hardwareUnitTypeId')));
$hardwareUnit->setHardwarePlacementId($request->request->get(intval('hardwarePlacementId')));
But then i get the error that my post value for setHardwareUnitTypeId and setHardwarePlacementId is null
Any suggestions on how i can convert my request to int?
Here is an image of my postman, if it helps:
You're reading the error wrong. It states that the argument of setHardwareUnitTypeId should be of type HardwareUnitType, but that you're providing a string:
App\Entity\HardwareUnit::setHardwareUnitTypeId(): Argument #1 ($hardwareUnitTypeId) must be of type ?App\Entity\HardwareUnitType, string given ...
Looking at your code, the error is quite clear. In your "new" route, you're calling the functions like this:
$hardwareUnit->setHardwareUnitTypeId($request->request->get('hardwareUnitTypeId'));
$hardwareUnit->setHardwarePlacementId($request->request->get('hardwarePlacementId'));
The $request->request->get() method returns a string (or int|float|bool|null), as it's parsing request parameters. It's not "magically" returning objects of the correct type. You need to take that ID and fetch the correct entity.
So what you need to do is the following:
Get the repository for HardwareUnitType and HardwarePlacement. This can be done through dependency injection of the repository directly into your controller action "new". See the docs for more info. You could also use $entityManager that you already have, like this example from docs, to get the repository.
In your controller, use the repository to fetch the entity based on $request->request->get('hardwareUnitTypeId') and $request->request->get('hardwarePlacementId'). You should be able to use the repository's built in find method (see previous example from docs). You'd get something like this:
$entity = $repository->find((int) $request->request->get('...'));
Use the result from find as argument to your setters. Building on on the example at the previous list item: you'd get something like: $hardwareUnit->setHardwareUnitTypeId($entity)
I hope this will help you figuring out your problem. Let me know if you need more help!
I'm implementing editing user profile via API. The page where user edits its data contains a lot of fields, but when user submits the form, only edited fields are sent to my API endpoint. Also I'm not using form mapping.
Only way I see is to write something like this:
public function editProfile(FormInterface $form, User $user): User
{
$args = $form->getData();
if ($args['email']) {
$user->setEmail($args['email']);
}
if ($args['phone']) {
$user->setPhone($args['phone']);
}
// ...
$this->em->persist($user);
$this->em->flush();
return $user;
}
But it looks terrible and my form may contain up to several tens of fields.
Does anybody know good solution for this case?
Use form mapping and submit form with disabled clear missing fields option:
In form builder:
$options->setDefaults([
'data_class' => MyEntity:class
]);
In controller:
$data = $request->request->all();
$form->submit($data, false);`
instead of $form->handleRequest($request);
I am trying to print a variable fromm saveAction so i can see what is the value of that variable. I am learning Zend2 and i have continued where other developer stoped so i am trying to understand it better...This application is also using Doctrin.
I have this action which will save some data to database.
public function saveAction() {
$view = new ViewModel();
$logedUser = $this->getLogedUser();
print_r($_POST);
$shopId = (int) $this->params()->fromPost('shop_id', null);
print_r($shopId);
$shop = $this->getServiceLocator()
->get('Catalog\Model\Shop')
->getRepository()
->findOneBy(array('id' => $shopId, 'user' => $logedUser->getId()));
print_r($shop);
return $logedUser;
return $shop;
return $view;
}
I can print values from post, and variable shopId, but print_r($shop); doesn't show anything. How can i see the value of shop variable?
Try this
echo $shop->__toString();
Hi there you might want to try this one:
print_r($this->getAllParams());
instead of using $_POST
$shop = $this->getServiceLocator()
->get('Catalog\Model\Shop')
->findOneBy(array('id' => $shopId, 'user' => $logedUser->getId()));
please remove ->getRepository() from your code, then you will get your result.
At this point we dont know what the Service/Factory 'Catalog\Model\Shop' does. I assume it get's the Entity manager. The query looks ok to me 2. But having 3 return's is just wrong!
Your view will never have the $shop; nor the $view; variable in your .phtml view File. In ZF2 you can just return a Array to your view like so:
return array('shop' => $shop, 'logedUser' => $logedUser);
This will save those variables within your save.phtml
in /yourmodule/view/yourcontroller/save.phtml
If you want to set the .phtml matching yourself you indeed could use the view model like you tried in your code the procedure is a litle diffrent then. It could look like this:
$viewModel = new ViewModel(array(
'logedUser' => $logedUser,
'shop' => $shop,
));
$viewModel->setTemplate('yourmodul/yourcontroller/save');
return $this->getContainerViewModel($viewModel);
Once you have that you can just access your variables in the save.phtml template file like so:
<?php echo $shop->getSomething(); ?>
You did not show us the Shop entity but I assume it has methods like getName(), __toString() etc. You can just call these Object methods within your view.
If you still have trouble understanding the mvc concept of zf2 you might want to re-read the zf2 documentation.
You have to show us what Catalog\Model\Shop and what query are you using for getting your data. Is there possibility that your query just getting null because it fails to get anything from database ? Do you have any kind of checks in your model to find out is your result from query good?
I am new to practicing CakePHP, I want to get value from the webuser and my controller will search that value from the DB. I am just wondering how I insert my $_post value add it to following code?
class DataviewsController extends AppController {
public $components = array('RequestHandler');
public function customer($id = null) {
$this->loadModel('Customer','Stock');
if (!$this->Customer->exists($id)) {
throw new NotFoundException(__('Invalid customer'));
}
$options = array('conditions' => array('Customer.' . $this->Customer->primaryKey => $id));
// Send the customer to the view
$this->set('customer', $this->Customer->find('first', $options));
$this->set('_serialize',array('customer'));
}
You can access post data in $this->request->data and get data in $this->request->query. As for your second question, I'm not sure what you are asking when it refers to the code you posted.
yes you can do with cakephp request handler object
here is very good example to create form and taking user data input and search from particular table. from that you can have very good idea how to implement in your application
just go throw this link Or this one for cakephp 2.0 and let me know if you need any more help
I am building an application where the user can edit some data and then gets presented with a screen where he can confirm (and comment on) his edits.
In the confirmation form I display the changes that have been made to the entity. This works for "normal" fields. Here is some code that works for checking a single field:
// create $form
// bind $form
if ($form->isValid() {
$data = $form->getData();
// example, get changes of a "normal" field
if ($data['color'] != $entity->getColor()) {
// do something with changes
}
}
But I can't do the same for a relation (example ManyToMany with Users) :
if ($data['users'] != $entity->getUsers()
doesn't work because $data['users'] and $entity->getUsers() refer to the same persistent collection. It is possible to call this function to see if there are changes:
if ($data['users']->isDirty())
but it isn't possible to see what changes were made.
The second problem with the above is that if all items are removed from the persistent collection, Doctrine does not mark it as "changed" (isDirty() = true), so I can't catch the specific change where the user removes all "users" from the entity in the form.
Please note that the code all works, the only problem I have is that I am unable to view/process the changes made on the confirmation step.
Doctrine\ORM\PersistentCollection has internal API (public) methods getSnapshot, getDeleteDiff, getInsertDiff that can be used during lifecycle events of the Doctrine\ORM\UnitOfWork. You could for example check the insert diff of a persistent collection during onFlush.
Solved it like this:
1) To get changes that will be made directly to the Entity, use the following:
// create form
// bind form
// form isValid()
$uow = $em->getUnitOfWork();
$uow->computeChangeSets();
$changeset = $uow->getEntityChangeSet($entity);
print_r($changeset);
2a) To get changes to the relations, use the answer from Lighthart above:
$oldUsers = $entity->getUsers()->toArray();
// bind form
// form isValid
$newUsers = $entity->getUsers()->toArray();
// compare $oldUsers and $newUsers
2b) Use these methods on Persistent Collection to find inserts / deletes:
$newUsers = $entity->getUsers();
$inserted = $newUsers->getDeleteDiff();
$deleted = $newUsers->getInsertDiff();
The only problem with (2b) is that if ALL users are removed and none added then getDeleteDiff() is empty which appears to be a Doctrine bug/idiosyncrasy
Store the original collection in a variable before bind and then compared the new collection after bind. PHP has quite a few array comparison functions, and collections are readily turned into native arrays by $collection->toArray();
eg:
// create form
$oldusers=$entity->getUsers()->toArray();
// bind form
if ($form->isValid() {
$data = $form->getData();
if ($data['users'] != $oldusers) {
// do something with changes
}
}