load cities in choiceType after select one gouvernorat in a second ChoiceType - forms

I have two entities with association Gouvernorat -> Villes.
This is the Gouvernorat entity:
class Gouvernorat
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100, nullable=false)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="EntiteBundle\Entity\Ville", mappedBy="idGouvernorat")
*/
private $villes;
//getters & setters & constructor
}
and this is the City Entity:
class Ville
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=200, nullable=false)
*/
private $name;
/**
* #var \Gouvernorat
*
* #ORM\ManyToOne(targetEntity="EntiteBundle\Entity\Gouvernorat",inversedBy="villes")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id_gouvernorat", referencedColumnName="id")
* })
*/
private $idGouvernorat;
}
In a third entity called Etablissement, i have string gouvernorat and string string ville.So i am trying to create an EtablissementType. This form contains
two Entity type for the child gouvernorat and ville
Brief copy :
class EtablissementType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nom')
->add('gouvernorat', EntityType::class, array(
'class' => 'EntiteBundle\Entity\Gouvernorat',
'choice_label' => 'name',
'multiple' => false
))
->add('ville',EntityType::class,
array(
'class' => 'EntiteBundle\Entity\Ville',
'choice_label' => 'name',
'multiple' => false
))
->add('Enregistrer',SubmitType::class)
-> setMethod('POST');
}
when i select gouvernorat i want that all cities of this gouvernorat are loaded i the second ChoiceType so i added this event:
public function buildForm(FormBuilderInterface $builder, array $options)
{
//$builder-> ...
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
$gouv = $data-> getGouvernorat();
$villes = null === $gouv ? array() : $gouv->getVilles();
$names = array_map(function ($value) {
return $value['name'];
}, $villes);
$form->add('ville', ChoiceType::class,
array(
'choices' => $names
));
}
);
}
shortcut for the data(in json forma):
[
{
"id": 1,
"name": "ARIANA",
"villes": [
{
"id": 1,
"name": "RAOUED",
"idGouvernorat": null
},
{
"id": 2,
"name": "SIDI THABET",
"idGouvernorat": null
},
{
"id": 3,
"name": "ARIANA VILLE",
"idGouvernorat": null
},
{
"id": 4,
"name": "LA SOUKRA",
"idGouvernorat": null
},
{
"id": 5,
"name": "KALAAT LANDLOUS",
"idGouvernorat": null
},
{
"id": 6,
"name": "ETTADHAMEN",
"idGouvernorat": null
},
{
"id": 7,
"name": "MNIHLA",
"idGouvernorat": null
}
]
},
{
"id": 2,
"name": "BEJA",
"villes": [
{
"id": 8,
"name": "BEJA NORD",
"idGouvernorat": null
},
{
"id": 9,
"name": "NEFZA",
"idGouvernorat": null
},
{
"id": 10,
"name": "GOUBELLAT",
"idGouvernorat": null
},
{
"id": 11,
"name": "MEJEZ EL BAB",
"idGouvernorat": null
},
{
"id": 12,
"name": "AMDOUN",
"idGouvernorat": null
},
{
"id": 13,
"name": "TEBOURSOUK",
"idGouvernorat": null
},
{
"id": 14,
"name": "TESTOUR",
"idGouvernorat": null
},
{
"id": 15,
"name": "THIBAR",
"idGouvernorat": null
},
{
"id": 16,
"name": "BEJA SUD",
"idGouvernorat": null
}
]
},
etc...
The problem, is that the second choiceType always empty that mean $gouv->getVilles(); doesn't work
Where is the problem, i didn't find the issue exactly , i usedsymfony documentation--Dynamic Generation for Submitted Forms
<script>
var $gouvernorat = $('#etablissement_gouvernorat');
// When gouvernorat gets selected ...
$gouvernorat.change(function() {
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data, but only include the selected gouvernorat value.
var data = {};
data[$gouvernorat.attr('name')] = $gouvernorat.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
// Replace current ville field ...
$('#etablissement_ville').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#etablissement_ville')
);
// Ville field now displays the appropriate Villes.
}
});
});
</script>

First when you get your gouv data in the form, I am not sure if it works as expected.
Replace
$form = $event->getForm();
$data = $event->getData();
$gouv = $data->getGouvernorat();
By:
$form = $event->getForm();
$data = $event->getData();
$gouv = $data->get('gouvernorat')->getData(); // basically, you get the form data for the gouvernorat field
At this moment I think gouvernorat is not populated with its own villes which are stored in the database (I suppose).
Now you will need to check if the getGouvernorat method of your $data (which is an Etablissement instance) returns a Gouvernorat instance.
If yes you will get this gouvernerat from your database, in order to access all its cities.
if (!is_null($data->getGouvernorat())) {
$persistedGouvernorat = $gouvernoratRepository->find($event->getData()->getGouvernorat());;
if (!is_null($persistedGouvernorat)) {
$gouverorat = $persistedGouvernorat;
}
}
$villes = $gouvernorat->getVilles();
Then I think you can get rid your issue.

Related

API Request body format accepted by form

I build an API with Symfony, so I create a CRUD for an entity, and I import Nelmio Api Doc Bundle for generate a doc with Swagger.
I build POST action with a form, and in the request body, I need to add products relation to the cart I create. So this is the body request I got in my Swagger documentation.
{
"datetime": "2023-02-03T12:54:05.661Z",
"customer": {},
"products": [
{
"id": 0
}
]
}
But this body don't work, only this format is accepted :
"products": [
2, 4
]
Or this one :
"products": {
"a": 2,
"b": 4
}
Can you help me to find the good configuration in my form, for my form can accept the JSON body format :
"products": [
{
"id": 0
}
]
Cart.php
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $datetime = null;
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
private Customer $customer;
#[ORM\ManyToMany(targetEntity: Product::class)]
private ?Collection $products = null;
(getters and setters...)
CartType.php
->add('products', EntityType::class, [
'class' => Product::class,
'multiple' => true,
'constraints' => [
new NotNull(),
],
])
CartController.php
#[Route('/api/v1/customer/cart', name: 'cart_create', methods: ['POST'])]
public function createAction(EntityManagerInterface $em, Request $request): Response
{
$form = $this->buildForm(CartType::class);
$form->handleRequest($request);
if (!$form->isSubmitted() || !$form->isValid()) {
return $this->respond($form, Response::HTTP_BAD_REQUEST);
}
/** #var Cart $cart */
$cart = $form->getData();
$em->persist($cart);
$em->flush();
return $this->respond($cart);
}

Symfony Form CollectionType with a media field (VichUpload for example)

I've got a problem with my collection of object which have a media field.
Entity Section with a collection of sectionContent:
class Section
{
/**
* #var ArrayCollection|Collection|SectionContent[]
* #ORM\OneToMany(targetEntity="MyBundle\Entity\SectionContent", mappedBy="section", cascade={"persist", "remove"})
* #Groups({"section_full"})
*/
protected Collection $sectionContents;
}
Form :
->add(
'sectionContents',
CollectionType::class, [
'entry_type' => SectionContentType::class,
'required' => false,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'delete_empty' => true,
]
)
SectionContent entity with a picture field
class SectionContent
{
/**
* #Groups({"section_full"})
*
* #ORM\ManyToOne(targetEntity="MyBundle\Entity\PublicMedia", cascade={"persist", "remove"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="public_media_id", referencedColumnName="id")
* })
*
* #var PublicMedia
*/
protected $picture;
}
Form:
->add(
'picture',
SectionPictureType::class,
[
'label' => false,
'required' => false
]
)
PublicMedia entity is a Vich/Uploadable class
/**
* #ORM\MappedSuperclass
* #Vich\Uploadable
*/
abstract class PublicMedia
{
/**
* #Vich\UploadableField(mapping="public_media_uploader", fileNameProperty="filename")
*
* #var File|string
*/
private $file;
}
If I've got an Section like this :
"sections": {
"0": {
"id": 1,
"sectionContents": {
"0": {
"id": 1,
"picture": {
"id": 1,
"uuid": "uuid1",
"filename": "test_1.png"
}
},
"1": {
"id": 2,
"picture": {
"id": 2,
"uuid": "uuid2",
"filename": "test_2.png"
}
}
}
}
},
I've got two pictures test_1 and test_2 saved in a directory on my project (web/upload/section/setion_content for example), but when I delete the first one (test_1), symfony didn't delete the linked picture as I expected.
It update the first section with the data of the second so I've got:
"sections": {
"0": {
"id": 1,
"sectionContents": {
"0": {
"id": 1,
"picture": {
"id": 1,
"uuid": "uuid1",
"filename": "test_2.png"
}
}
}
}
},
As I understand, symfony update the first section data with the second and delete the second, but when it delete the second section, it delete the linked picture as well so I've got a section with test_2 picture on data and test_1 linked picture on the directory. So my sectionContent is linked to a deleted picture and I've got a picture without linked sectionContent.
Before:
[{picture: {filename: test_1}}, {picture: {filename: test_2}}] -> web/upload/.../test_1 and web/upload/.../test_2
After:
[{picture: {filename: test_2}}] -> web/upload/.../test_1
I don't know how to fix that ...
When I delete a sectionContent I want to delete the linked picture and not the last one !
Do you have some ideas please ?

PHP/MongoDB - Doctrine ODM Hydrate in some cases others not

I need some help in Doctrine ODM, in some cases the hydrate do not return the expected values.
I have on project as example and when I query for a collection and all work fine with hydrate, this is the case that works:
ProductsCollection:
<?php
namespace MongodbManager\Documents;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\Common\Collections\ArrayCollection;
/** #ODM\Document */
class ProductsODM
{
/** #ODM\Id */
public $id;
/** #ODM\Field(type="string") */
public $name;
/** #ODM\Field(type="float") */
public $price;
/** #ODM\Field(type="date") */
public $date;
/** #ODM\EmbedMany(targetDocument=CategoriesODM::class) */
public $categories;
/** #ODM\ReferenceMany(targetDocument=TagsODM::class, storeAs="id") */
public $tags;
/** #ODM\ReferenceOne(targetDocument=TagsODM::class, storeAs="id") */
public $tagsPrimary;
public function __construct()
{
$this->categories = new ArrayCollection();
}
}
TagsCollection
<?php
namespace MongodbManager\Documents;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/** #ODM\Document */
class TagsODM
{
/** #ODM\Id */
public $id;
/** #ODM\Field(type="string") */
public $name;
}
Query (WORKS!)
$this->dm->createQueryBuilder(ProductsODM::class)->hydrate(true)->getQuery()->execute();
Return (content):
{
"id": "5d9e23b32b251b2fc7438d14",
"name": "Martini 1570644915",
"price": 5.99,
"date": {
"date": "2019-10-09 15:15:15.000000",
"timezone_type": 3,
"timezone": "America/Sao_Paulo"
},
"categories": [
{
"id": "5d9e23b32b251b2fc7438d15",
"name": "bar"
},
{
"id": "5d9e23b32b251b2fc7438d16",
"name": "night"
}
],
"tags": [
{
"id": "5d9dde11982e830950453618",
"name": "COMIDA"
},
{
"id": "5d9dde11982e830950453619",
"name": "BEBIDA"
}
],
"tagsPrimary": {
"id": "5d9dde11982e830950453618",
"name": "COMIDA"
}
}
As you can see the result came with Tags values.
HERE IS THE PROBLEM:in the UsersODM when I query for documents do not include the values of UsersGrousODM in the result, just the id, here is the code:
<?php
namespace MongodbManager\Documents;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/** #ODM\Document */
class UsersODM
{
/** #ODM\Id */
public $id;
/** #ODM\Field(type="string") */
public $users_login_code;
/** #ODM\Field(type="string") */
public $users_username;
/** #ODM\Field(type="string") */
public $users_password;
/** #ODM\Field(type="string") */
public $users_status;
/** #ODM\Field(type="date") */
public $users_update_date;
/** #ODM\ReferenceOne(targetDocument=UsersGroupODM::class, storeAs="id") **/
public $users_group_id;
}
The UsersGroupODM
<?php
namespace MongodbManager\Documents;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/** #ODM\Document */
class UsersGroupODM
{
/** #ODM\Id */
public $id;
/** #ODM\Field(type="string") */
public $users_group_name;
/** #ODM\Field(type="string") */
public $users_group_status;
}
The Query:
$this->dm->createQueryBuilder(UsersODM::class)hydrate(true)->getQuery()->execute();
Return:
{
"id": "5d9e2b0991055769a44078c6",
"users_login_code": null,
"users_username": "webmaster",
"users_password": "d68b87ecdf82164583816f1306f4c342ba57ad3e......",
"users_status": "active",
"users_update_date": {
"date": "2019-10-09 15:46:33.000000",
"timezone_type": 3,
"timezone": "America/Sao_Paulo"
},
"users_group_id": {
"id": "5d9e289358063a6594142cbc"
},
"users_info": null
}
the users_group_id do not include the field users_group_name and users_group_status.

What should be the base URL for the images in magento?

After accessing the Rest API (http://192.168.1.180/magento/index.php/rest/V1/products/SKU) to get the product details, the response is something like this:
{
"attribute_code": "image",
"value": "/6/4/64275-152378-large.jpg"
},
{
"attribute_code": "small_image",
"value": "/6/4/64275-152378-large.jpg"
},
{
"attribute_code": "thumbnail",
"value": "/6/4/64275-152378-large.jpg"
}
What should be the base url for the jpg in the attribute_code keys ?
There is no need for modifying the API request.
Just add a prefix: http://magento.com/pub/media/catalog/product/
So the new URL according to my response will be:
Prefix: http://magento.com/pub/media/catalog/product/6/4/64275-152378-large.jpg
/** #return string */
function getMediaBaseUrl() {
/** #var \Magento\Framework\ObjectManagerInterface $om */
$om = \Magento\Framework\App\ObjectManager::getInstance();
/** #var \Magento\Store\Model\StoreManagerInterface $storeManager */
$storeManager = $om->get('Magento\Store\Model\StoreManagerInterface');
/** #var \Magento\Store\Api\Data\StoreInterface|\Magento\Store\Model\Store $currentStore */
$currentStore = $storeManager->getStore();
return $currentStore->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
}

How can I fetch just a document without his referenced documents

I have two Documents: Client and PV. Many PV are referenced in one Client. It's unidirectional.
Client
/**
* #MongoDB\Document
*/
class Client
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/**
* #MongoDB\String
*/
protected $name;
/**
* #MongoDB\ReferenceMany(targetDocument="PV", simple=true, cascade={"persist", "remove"})
*/
private $PV = array();
public function __construct()
{
$this->PV = new \Doctrine\Common\Collections\ArrayCollection();
}
}
PV
/**
* #MongoDB\Document
*/
class PV
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/**
* #MongoDB\String
*/
protected $name;
}
To fetch a Client Document I use:
$client = $this->get('doctrine_mongodb')
->getRepository('HubMainBundle:Client')
->findOneById($id);
And I get:
"53da113176a2955c6d8b4567": {
"id": "53da113176a2955c6d8b4567",
"name": "Test",
"_p_v": [
{
"id": "53da121276a2956c708b4568",
"name": "test pv"
},
{
"id": "53da4e2876a295b7088b4567",
"name": "pv 2"
}
]
}
But I want:
"53da113176a2955c6d8b4567": {
"id": "53da113176a2955c6d8b4567",
"name": "Test",
"_p_v" : [
"53da121276a2956c708b4568",
"53da4e2876a295b7088b4567"
]
}
So how can I fetch just the Parent Document with MongoIds for every PV referenced not the entires referenced PVs ? (In MongoDB when I do db.Client.find({name: 'Test'}) I got the MongoIds not the documents).
Is it related to the Doctrine MongoDB hydrator ?