Laravel 5.3 Save related model with array - laravel-5.3

I have a User model and Event model.
A User can have/create many Events
An Event belongs to User.
I have made this form just for demo:
And i get this output when i dd($request);
How to save this in my database table events.
These array fields are problem...do i need to make some new table except users and events??

Yes, it looks like you need another table. I've just taken an educated guess at the table names because I'm not 100% sure what these times and professions refer to, it looks like you already have a table storing the professions, but here are the relationships I can see:
A user can have many events
An event belongs to a user
An event has many timeslots
A timeslot belongs to an event
A profession has many timeslots
A timeslot has many professions
So your events and professions (don't worry if you've called it something else) table should look like:
events(id, user_id, name, start, end);
professions(id, profession,..);
And you need to add an extra table:
time_slots(id, event_id, profession_id, amount, from, to, hours)
Then set those relationships up inside your models.
EDIT
The basic way to make a store method is to use the relationships like so:
public function store(Request $request){
// Get the request as an array
$request = $request->all();
// create a new event
$event = Event::create($request);
// Map timeslots to an array of Timeslot objects:
$timeslots = array_map(function($personalId, $amount, $from, $to, $hours) {
return new App\Timeslot($personalId, $amount, $from, $to, $hours);
}, $request['personal_id'], $request['amount'], $request['from'], $request['to'], $request['hours']);
// Save all timeslots for the event
$event->timeslots()->saveMany($timeslots)
}
I haven't tried that code, but it should point you inb the right direction. You should take a look at laravel relationships to see how this works:
https://laravel.com/docs/5.3/eloquent-relationships#the-save-method

Related

Recover data from two classes into many to many

I have a User table and a Library table, the relationship between them are many to many.
So I have a user_library table.
I manage to add data to the Library table from User but I cannot recover the data afterwards.
I add them like this:
$em = $this->getDoctrine()->getManager();
$repoUser = $em->getRepository('App:User');
$user = $repoUser->findOneBy(['token' => $token_user]);
$library = new Library();
$library->setIdBook($id_book);
$user->addLibrary($library);
$em->persist($library);
$em->persist($user);
$em->flush();
I thought that simply doing: $user->getLibrary()->getIdBook() would be enough but it is not the case.
How do you think I can get all the id_book that match the user?
The thing is that your getLibrary returns ArrayCollection, you need to specify which Library you exactly want
$libararies = $user->getLibrary() // <- this returns ArrayCollection
$library = $libraries->first() // <- return 1st element
Based on this code you can do a search for example, or just use doctrine to fetch library with desired ID, user, whatever you need straight from the database
EDIT
Lets say you want all libraries that are in relation with user with ID = 4
... // your code
$user = $this->getDoctrine()->getRepository('your user class')->find(4); // here we find your user from DB
$libraries = $user->getLibrary() // here we get all libraries which are in relation with user #4, you might want to rename the function as it returns ArrayCollection of Libraries, not Library
$bookIds = array();
foreach($libraries as $library) {
$bookIds[] = $library->getIdBook();
}
dump($bookIds); // all user #4 book ids
die;

Doctrine 2, prevent getting unjoined entities

given a user and his coupons, I want to get a user and all of his coupons:
foreach ($this->createQueryBuilder('x')->select('u, c')->where('x.email = ?0')->setParameter(0, $email)->leftJoin('u.coupons', 'c')->getQuery()->getResult() as $entity)
{
$entity->getCoupons();
}
this is very good until I forget to join the coupons:
foreach ($this->createQueryBuilder('x')->select('u')->where('x.email = ?0')->setParameter(0, $email)->getQuery()->getResult() as $entity)
{
$entity->getCoupons();
}
sadly this still works even though no coupons were joined. Here it does an other SELECT. In additional, this 2nd select will be wrong. Id rather want to get a exception or AT LEAST an empty array instead. Is there any workaround for this?
What you're experiencing is expected doctrine behavior.
When you select a User entity, Doctrine will get the record from the database. If you aren't explicitly joining the Coupon entity (or any other entities with relationship to User), Doctrine will create a Proxy object. Once you access this proxy object by calling $user->getCoupons(), Doctrine will fire a new query to the database to get the coupons for your User entity. This is called lazy-loading.
I'm not sure if there is a way to change this in the way you described.
What you can do is to create a method in your UserRepository called findUserAndCoupons($email) and have your query there. Whenever you need to find a user and his coupons, you could simply retrieve it in your controller using:
class MyController extends Controller {
public function myAction(){
$user = $this->getDoctrine()->getRepository('UserRepository')->findUserAndCoupons($email);
foreach($user->getCoupons() as $coupon) {
// ....
}
}
}
This way you won't need to remember the actual query and copy/paste it all over the place. :)

Add a child to a #OneToMany bidirectionnal with FOSRestBundle

I'm building a REST API with FOSRestBundle on my Symfony2 application.
What I want to do is to allow my POST and PUT actions, let say on a Product entity who got a #OneToMany relationship with another entity called Risk, to add/delete the children I past in JSON.
Let me give to you an example of JSON:
{
"cproduct": "ASSOC000000000999",
"risks": [
{
//first risk fields
},
{
//second risk fields
}
]
}
This is a simple JSON (the real one got more fields but these aren't needed here).
So here I've my Product ID (ASSOC000000000999) and I want to update this product by adding to him 2 new risks.
I know that normally I would have to create a Risk with the product ID separately, but for the needs of my application, I need to make only one request to the database. I want my users to be able to create a product, then add one or more risks and only then persist it into the database.
In a second time I would like them to be able to delete a child (risk) if he doesn't appear in the JSON sent with PUT action.
Here an example, let say that product “ASSOC000000000999” got a risk “RISK1”.
If I send this JSON:
{
"cproduct": "ASSOC000000000999",
"risks": [
{
“id”: “RISK2”,
//other fields
},
{ “id”: “RISK3”,
//other fields
}
]
}
On persist I want RISK1 to be deleted.
How can I do that? I found nothing on the web about that, please help me. :-)
PS: Sorry for my English, this isn't my birth langage.
EDIT:
I target what my problem really is.
When I send that JSON file with HTTP PUT verb:
{
"cfam": "AUTE",
"lpronom": "My Contract",
"riss": [{
"cris": "AS",
"lris": "Organization Law of 1901",
"lrisfic": "RCAD_FICHERCA9"
}]
}
Doctrine does a SELECT on RIS (my Risk table is called RIS, so the collection is $riss in my PROduct entity) where CRIS = "AS", and that's my problem. Here I want doctrine to create a RIS if the composite PK {cpro, nprover, cris} doesn't exist, and an update if it exist.
How can I do that?
(Without using Symfony form if possible).
Here my API call :
http://localhost/web/web/app_dev.php/fos/api/pros/ASSOC000000000009_1
My putProAction():
public function putProAction($id, Request $request)
{
$detachedEntity = $this->reqDeserialize($request, 'Namespace\Bundle\ProductBundle\Entity\Pro');
// Here I need to explode my serialized PUT parameter ID
list($cpro, $nprover) = explode('_', $id);
$detachedEntity->setCPRO($cpro);
$detachedEntity->setNPROVER($nprover);
$em = $this->getDoctrine()->getManager();
// I use merge to attache the entity to perform the persist
$entity = $em->merge($detachedEntity);
$em->persist($entity);
$em->flush();
return $entity;
}
You should use Symfony's Form Collections.
The example listed on that page is very similar to your requirements.

Symfony/SonataAdmin Show fields from two entities

I have two entities :
User that contains login data (with FOSUser),
and other informations about them (name, first name, date of birth, etc) in another entity called UserInfo.
In SonataAdmin, I want to manage my Users (done) but I need to add fields in the table that are in UserInfo (name, first name...).
Any idea ?
Thanks !
Depending on the relationship type, you should be able to just reference userinfo.firstName, eg:
public function configureShowFields(ShowMapper $show)
{
$show->add('userinfo.firstName')
->add('userinfo.dob');
}
Of course, if you have many userinfo's attached to the entity I don't think this will work.
There must be existing a relation in between user and userInfo. say OneToOne relation. Then from userInfo entity u will get the user data and will show on the Admin side.
i.e.
$subject = $this->getSubject();
$user = $this->subject->getUser();
Will give you user, if you want to further perform actions on that user.

Magento: how to merge two product collections into one?

if i have two product collections is there a way to merge them into one?
for example (my final intent isn't to actually just get a collection of 2 cats, this is just to illustrate the issue):
$collection1 = Mage::getModel('catalog/category')->load(148)->getProductCollection();
$collection2 = Mage::getModel('catalog/category')->load(149)->getProductCollection();
$merged_collection = merge_collections($collection1,$collection2);
any help would be appreciated!
Assuming the items you wish to group together are of the same type and exist in the database then you can do this:
$collection1 = Mage::getModel('catalog/category')->load(148)->getProductCollection();
$collection2 = Mage::getModel('catalog/category')->load(149)->getProductCollection();
$merged_ids = array_merge($collection1->getAllIds(), $collection2->getAllIds());
// can sometimes use "getLoadedIds()" as well
$merged_collection = Mage::getResourceModel('catalog/product_collection')
->addFieldToFilter('entity_id', array('in' => $merged_ids))
->addAttributeToSelect('*');
Here I know to filter by entity_id because that is products' key field, like it is for most entity types, some flat tables have a different primary key. Often you can generalise that with one of the collection's getIdFieldName() method. Products are a bad example in this case because it's ID field name isn't filled out correctly.
Almost every (or every?) collection in Magento inherits from a Varien Data Collection. A collection is a special object that holds objects of another type. There's no method for merging collections, but you can add additional items of the appropriate type to the collection.
Code like this should get you where you want to go, although there's probably more efficient ways to loop and do the actual merging.
$collection1 = Mage::getModel('catalog/category')->load(148)->getProductCollection();
$collection2 = Mage::getModel('catalog/category')->load(149)->getProductCollection();
//load an empty collection (filter-less collections will auto-lazy-load everything)
$merged = Mage::getModel('catalog/product')->getCollection()->addFieldToFilter('entity_id',-1);
//add items from the first collection
foreach($collection1 as $item)
{
$merged->addItem($item);
}
//add items from the second collection
foreach($collection2 as $item)
{
//magento won't let you add two of the same thing to a collection
//so make sure the item doesn't already exist
if(!$merged->getItemById($item->getId()))
{
$merged->addItem($item);
}
}
//lets make sure we got something
foreach($merged as $product)
{
var_dump($product->getName());
}
I don't think there is such a method, but you can probably do something like that :
foreach ($collection1 as $item){
$collection2->addElem($item);
}
you can filter your collection directly without using 2.
$products = Mage::getModel('catalog/product');
$_collection = $products->getCollection();
->addCategoryFilter(2)
->load();
or try using 'addItem' to add your results to a collection. See also in Magento wiki
for the collection of products of several categories, you can use the following code
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('name')
->addAttributeToSelect('sku');
$collection->getSelect()
->join(
'catalog_category_product',
'product_id=entity_id',
array('category_id')
)
->where('catalog_category_product.category_id IN (?)', $categories);

Resources