Laravel Eloquent Subquery Using 3 Tables - eloquent

The goal of this query is to find all Stories which have an Image Type with a name of "email_small" associated with them. Not all stories have images.
There are three tables/models involved: Storys, StoryImage, and ImageTypes
A story can have many story images
/* Story model */
public function storyImages()
{
return $this->hasMany(StoryImage::class);
}
While a story image has one image type
/* Storyimage model */
public function imgtype()
{
return $this->belongsTo('App\Imagetype','imagetype_id');
}
I can get to the second step of selecting all stories with an image, but I'm lost within the subquery
$stories = Story::whereHas('storyImages', function($query){
$query->where($query->imgtype()->name, '=', 'email_small');
})
->->get();

Why can't you use two queries? First select ID of imgType with name "email_small" and then check that ID:
$id = Imagetype::where('name', 'email_small')->first()->id;
$stories = Story::whereHas('storyImages', function($q) use ($id) {
$q->where('imagetype_id', $id);
})->get();
I'm sure that even if you write everything in one function Laravel will still call few queries.

Related

Return additional relationship data in Laravel Pivot table (Laravel 9, Inertia, Vue)

I'm in a Laravel 9 project trying to access extra relationship data in a pivot table - I'm sure this will have been answered before but the answers are confusing me more!
I have a set of courses, a set of cohorts and a set of sessions. Each course can be run multiple times (each one of these I've called an instance), with multiple sessions, and one cohort.
I've created an instances table in my database which has:
course_id
cohort_id
I have a sessions table which has data on each individual session, for example a name, a review date and review status.
I then have a pivot table called instance_sessions which looks like this:
instance_id
session_id
date
trainer_id
zoom_room_id
cohort_id
I'm not sure I need the cohort id but thats by the by :-)
My question is how can I get the relationships from this pivot table to the trainer and the zoom room?
In my instance model my relationships are setup like this:
public function sessions(){
return $this->belongsToMany(Session::class)->withPivot(['date'])
->using(InstanceSession::class);
}
public function course(){
return $this->belongsTo(Course::class);
}
public function cohort(){
return $this->hasOne(Cohort::class, 'id', 'cohort_id');
}
Session model:
function instances(){
return $this->belongsToMany(Instance::class);
}
Instance Session Model:
class InstanceSession extends Pivot
{
use HasFactory;
protected $table = 'instance_session';
protected $fillable = ['instance_id', 'session_id', 'date', 'trainer_id', 'zoom_room_id', 'cohort_id' ];
public function instance(){
return $this->belongsTo(Instance::class);
}
public function session(){
return $this->belongsToMany(Session::class);
}
public function zoomRoom(){
return $this->belongsTo(ZoomRoom::class);
}
public function trainer(){
return $this->hasOne(Trainer::class);
}
}
And my Instance Controller:
$instances = Instance::with(['course', 'cohort', 'sessions'])->get();
which returns the data to an Inertia/Vue view. I've attached an image of the data being retrieved.
Any help would be gratefully received as I'm clearly not understanding something :-)
EDIT: End goal being that I want to show on the front end all of the instances with all the sessions that belong to that instance, the date those sessions take place on, the trainer name (from trainers table) taking the session and the zoom room link (from zoom room table) for the session.

I have made a category and want to make sub category, how can I add dynamically?

I made a form in which I have titlte, image, pdf, content and category and all are working fine, but I want to add submenu in my form and also want to make this dynamic so can show all sub-menu on my website.
You must have to intruduce a key parent_id with categories table.
And in category model do create the relation like this.
class Category extends Model
{
public $fillable = ['title','parent_id'];
/**
* Get the index name for the model.
*
* #return string
*/
public function childs() {
return $this->hasMany('App\Category','parent_id','id') ;
}
}
Here you can find the complete example..https://itsolutionstuff.com/post/laravel-5-category-treeview-hierarchical-structure-example-with-demoexample.html
Hopefully this could help you.

Magento 2: Get Product Stock Quantity and Other Stock Information

Magento 2: Get Product Stock Quantity and Other Stock Information
How to get the product stock quantity and information in magento 2
If we look at the StockItemRepository class the get method wants parameter $stockItemId, not $productId. Reference:
https://github.com/magento/magento2/blob/develop/app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php#L202
I've seen many sites where stock item id IS NOT the same as product id and we should not assume it's the same ID.
To get this working you could use \Magento\CatalogInventory\Model\Stock\Item class instead and load the model by product_id field instead. I am also aware of the website_id and stock_id fields, but as far as I know it's not used (yet) and also existed in M1.
It should look something like this (code not tested):
<?php
namespace Vendor\Module\Model;
use \Magento\CatalogInventory\Model\Stock\Item;
class Mymodel
{
/**
* #var Item
*/
protected $stockItem;
/**
* Mymodel constructor.
*
* #param Item $stockItem
*/
public function __construct(Item $stockItem)
{
$this->stockItem = $stockItem;
}
/**
* Description
*
* #param $productModel
*/
public function getStockQtyByProductId($productModel)
{
try {
$stockItem = $this->stockItem->load($productModel->getId(), 'product_id');
return $stockItem->getQty();
} catch (\Exception $e) {
echo 'Something went wrong and was not handled: ' . $e->getMessage();
exit;
}
}
}
if you have product object then just use following:
echo $_product->getExtensionAttributes()->getStockItem()->getQty();
conplete object can be find as follow:
var_dump($_product->getExtensionAttributes()->getStockItem()->getData());
Actually this operation should be performed using \Magento\CatalogInventory\Api\StockRegistryInterface and here we can obtain \Magento\CatalogInventory\Api\Data\StockItemInterface, by product id or sku and we can use bunch of usefull methods to get stock information - linked product. For general stock information I recommend explore other service contracts declared in Magento\CatalogInventory\Api
Example of usage:
<?php
namespace Test\Test\Model;
class Test
{
protected $_stockRegistry;
public function __construct(\Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry)
{
$this->_stockRegistry = $stockRegistry;
}
public function getStockItem($productId)
{
return $this->_stockRegistry->getStockItem($productId);
}
}
this code help you to get product quantity
<?php
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$StockState = $objectManager->get('\Magento\CatalogInventory\Api\StockStateInterface');
echo $StockState->getStockQty($productId);
?>
If you have the product object and do not want to use the other classes, You can try in the following way.
// For phtml file
$prodObj = $_product->load($_product->getId()); // $_product object in list.phtml
$stockItem = $prodObj->getExtensionAttributes()->getStockItem();
$stockQty = $stockItem->getQty(); // $stockItemData = $stockItem->getData();
// For php class file
$stockItem = $prodObj->getExtensionAttributes()->getStockItem();
$stockQty = $stockItem->getQty(); // $stockItemData = $stockItem->getData();
Credits:
https://github.com/magento/magento2/issues/7057#issuecomment-256052729
Actually \Magento\CatalogInventory\Api\Data\StockStatusInterface
should answer to all your questions.
Long story short:
Magento has StockItem entity which represents amount (Qty) of specific product (productId) on a concrete stock (stockId).
StockItemInterface should be used when you would like to "write" data into the data storage (like update amount of products to sync up Magento with your ERP system or to make deduction of stock during the checkout process).
StockStatusInterface is opposite to it. It should be used to "read" data for representation (on front-end). Consider StockStatus as an index which contains aggregated stock data for each specific product.
So, if you would like to get product stock status (in stock, out of stock) by product_id.
You need using StockStatusRepositoryInterface::getList(StockStatusCriteriaInterface $searchCriteria);
get StockStatus entity for specified product
/** #var \Magento\CatalogInventory\Api\StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory **/
$criteria = $stockStatusCriteriaFactory->create();
$criteria->setProductsFilter($productId);
/** #var \Magento\CatalogInventory\Api\Data\StockStatusRepositoryInterface $stockStatusRepository **/
$result = $stockStatusRepository->getList($criteria);
$stockStatus = current($result->getItems());
$stockStatus->getProductId(); // product id
$stockStatus->getQty(); // quantity of specified product
$stockStatus->getStockStatus(); // Could be
// Magento\CatalogInventory\Model\Stock\Status::STATUS_OUT_OF_STOCK = 0;
// or
// Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK = 1;

Laravel 4 Auth with Facebook (no password authentication)

I'm trying to set up an authentication system with Laravel 4 with a Facebook login. I am using the madewithlove/laravel-oauth2 package for Laravel 4.
Of course, there is no password to add to my database upon a user loggin in with Facebook. I am, however, trying to check to see if a user id is in the database already to determine if I should create a new entity, or just log in the current one. I would like to use the Auth commands to do this. I have a table called "fans".
This is what I'm working with:
$fan = Fan::where('fbid', '=', $user['uid']);
if(is_null($fan)) {
$fan = new Fan;
$fan->fbid = $user['uid'];
$fan->email = $user['email'];
$fan->first_name = $user['first_name'];
$fan->last_name = $user['last_name'];
$fan->gender = $user['gender'];
$fan->birthday = $user['birthday'];
$fan->age = $age;
$fan->city = $city;
$fan->state = $state;
$fan->image = $user['image'];
$fan->save();
return Redirect::to('fans/home');
}
else {
Auth::login($fan);
return Redirect::to('fans/home');
}
Fan Model:
<?php
class Fan extends Eloquent {
protected $guarded = array();
public static $rules = array();
}
When I run this, I get the error:
Argument 1 passed to Illuminate\Auth\Guard::login() must be an instance of Illuminate\Auth\UserInterface, instance of Illuminate\Database\Eloquent\Builder given
EDIT: When I use: $fan = Fan::where('fbid', '=', $user['uid'])->first();
I get the error:
Argument 1 passed to Illuminate\Auth\Guard::login() must be an instance of Illuminate\Auth\UserInterface, null given, called in /Applications/MAMP/htdocs/crowdsets/laravel-master/vendor/laravel/framework/src/Illuminate/Auth/Guard.php on line 368 and defined
I do not know why it is giving me this error. Do you have suggestions on how I can make this work? Thank you for your help.
You have to implement UserInterface to your model for Auth to work properly
use Illuminate\Auth\UserInterface;
class Fan extends Eloquent implements UserInterface{
...
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->password;
}
}
getAuthIdentifier and getAuthPassword are abstract method and must be implemented in you class implementing UserInterface
To login any user into the system, you need to use the User model, and I bet inherited classes will do the trick as well but I'm not sure.
Anyway, your Fan model does not associate with the User model/table in any way and that's a problem. If your model had a belong_to or has_one relationship and a user_id field then you could replace Auth::login($user) with Auth::loginUsingId(<some id>).
Original answer:
You are missing an extra method call: ->get() or ->first() to actually retrieve the results:
$fan = Fan::where('fbid', '=', $user['uid'])->first();
Alternatively, you can throw an exception to see what's going on:
$fan = Fan::where('fbid', '=', $user['uid'])->firstOrFail();
If you see different errors, update your question with those errors.

Symfony: How to hide form fields from display and then set values for them in the action class

I am fairly new to symfony and I have 2 fields relating to my table "Pages"; created_by and updated_by. These are related to the users table (sfGuardUser) as foreign keys. I want these to be hidden from the edit/new forms so I have set up the generator.yml file to not display these fields:
form:
display:
General: [name, template_id]
Meta: [meta_title, meta_description, meta_keywords]
Now I need to set the fields on the save. I have been searching for how to do this all day and tried a hundred methods. The method I have got working is this, in the actions class:
protected function processForm(sfWebRequest $request, sfForm $form)
{
$form_params = $request->getParameter($form->getName());
$form_params['updated_by'] = $this->getUser()->getGuardUser()->getId();
if ($form->getObject()->isNew()) $form_params['created_by'] = $this->getUser()->getGuardUser()->getId();
$form->bind($form_params, $request->getFiles($form->getName()));
So this works. But I get the feeling that ideally I shouldnt be modifying the web request, but instead modifying the form/object directly. However I havent had any success with things like:
$form->getObject()->setUpdatedBy($this->getUser()->getGuardUser());
If anyone could offer any advice on the best ways about solving this type of problem I would be very grateful.
Thanks,
Tom
After processing and saving the form you could set those fields on the object and re-save:
protected function processForm(sfWebRequest $request, sfForm $form)
{
$form->bind($request->getParameter($form->getName()));
if ($form->isValid())
{
$page = $form->save();
$user = $this->getUser()->getGuardUser();
$page->setUpdatedBy($user);
if (empty($page->created_by))
{
$page->setCreatedBy($user);
}
$page->save();
$this->getUser()->setFlash('notice', 'Successfully saved page.');
$this->redirect('#homepage');
}
}
There's also a Doctrine extension called Blameable that automatically sets edited_by and created_by fields on specified models. The Doctrine website is undergoing some reorganization but here is the cached page for the extension.
To process your form create a new object, set the fields then save.
$article = new Article();
$article->setName($request->getParameter($form->getName());
$article->setDescription($request->getParameter($form->getDescription());
$article->setMetaKeywords($request->getParameter($form->getMetaKeywords());
$article->save();
What you want to do is customize your form and unset the 'created_at' and 'updated_at' pieces of the form in configure
class SampleForm extends BaseSampleForm
{
public function configure()
{
unset(
$this['created_at'],
$this['updated_at']
);
}
}
Then they won't show up in the form and will get the values setup by the "Timestampable" behavior before being saved
http://stereointeractive.com/blog/2010/04/07/symfony-forms-hide-created_at-updated_at-columns/