I'm using the Laravel framework for my web app, eloquent models for data and Fractal to transform some data.
I want to use the parseIncludes functionality of fractal but I can't seem to get it working despite following the docs.
Here's my code:
StudentTransformer.php
class StudentTransformer extends Fractal\TransformerAbstract
{
protected $availableIncludes = [
'course'
];
public function transform(Student $student)
{
return [
'name' => $student->name,
// other attributes
];
}
public function includeCourse(Student $student)
{
$course = $student->course;
return $this->item($course, new CourseTransformer);
}
}
CourseTransformer.php
class CourseTransformer extends Fractal\TransformerAbstract
{
public function transform(Course $course)
{
return [
'name' => $course->name
// other attributes
];
}
}
In one of my controllers:
$student = App\Models\Student::first();
$fractal = new \League\Fractal\Manager();
$fractal->parseIncludes('/student?include=course');
$fractal->setSerializer(new \League\Fractal\Serializer\ArraySerializer());
$response = new \League\Fractal\Resource\Item($student, new \App\Transformers\Models\StudentTransformer);
return response()->json($fractal->createData($response)->toArray());
Also, when I remove the availableIncludes from the StudentTransformer and use defaultIncludes instead, like so:
protected $defaultIncludes = [
'course'
];
It works just fine?! No idea why! Any help would be appreciated.
Fixed it. For the benefit of others, the issue was here:
$fractal->parseIncludes('/student?include=course');
It should just be:
$fractal->parseIncludes('course');
Related
I am trying to make a POST request to add a showroom in the Laravel application. When I try to do it with Showroom model using Eloquent ORM , it shows 500 internal server error. But if I do it with DB query, then it successfully CREATE the showroom. I commented out the db query lines and apply dd debugging and found out table for Showroom Model is null.
This is my controller code -
public function store(ShowroomRequest $request)
{
$showroom = new Showroom([
"name" => $request->get('name'),
"address" => $request->get('address'),
"description" => $request->get('description'),
]);
dd($showroom);
$ret = $showroom->save();
// $name = $request->input('name');
// $address = $request->input('address');
// $description = $request->input('description');
// DB::table('showroom')->insert(
// ['name' => $name, 'address' => $address, 'description' => $description]
// );
return redirect()->route('back.showroom.index')->withSuccess(__('Showroom Added Successfully.'));
}
And this is my model -
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Showroom extends Model
{
protected $fillable = ['name', 'description', 'address'];
protected static $ordersModel = 'App\Models\Order';
protected static $reviewsModel = 'App\Models\Review';
public function Orders()
{
return $this->hasMany(static::$ordersModel, 'showroom_id');
}
public function Reviews()
{
return $this->hasMany(static::$reviewsModel, 'showroom_id');
}
}
Finally this is my db structure -
Can anyone help me to find out what went wrong here? Thanks in advance.
in controller can you assign static values instead of request->get, and see if it saves.
please let me what happens afterwards.
also assign name of table in model like this,
protected $table = 'tablename';
I'm trying to implement the repository pattern and save a relationship using the create method as shown below.
abstract class EloquentRepository implements Repository {
public function create($data)
{
return $this->model->create($data);
}
}
Within my controller I have injected the repository:
public function __construct(SubscriberRepository $subscriberRepository,
SubscribableRepository $subscribableRepository)
{
$this->subscriberRepository = $subscriberRepository;
$this->subscribableRepository = $subscribableRepository;
}
My store method looks like:
public function store(CreateSubscriberRequest $request): JsonResponse
{
$subscribable = $this->subscribableRepository->findByIdentifier($request->input('type'))
->firstOrFail();
$attributes = [
'name' => $request->input('name'),
'email' => $request->input('email')
];
$subscriber = $this->subscriberRepository->create($attributes);
}
Subscriber Model
public function subscribable()
{
return $this->belongsTo(Subscribable::class, 'subscribable_id');
}
Subscribable Model
public function subscribers()
{
return $this->hasMany(Subscriber::class);
}
My issue General error: 1364 Field 'subscribable_id' doesn't have a default value is because the subscribable_id is a foreign key and not set in the create method.
How do I relate the subscribable model, setting the subscribable_id? I don't think setting the subscribable_id in the fillable property is the way to go with this.
Many thanks in advance.
Laravel gives functionality to save relations using the related model instances.
So You can save relation by calling create method on relation like this:
public function store(CreateSubscriberRequest $request): JsonResponse
{
$subscribable = $this->subscribableRepository->findByIdentifier($request->input('type'))
->firstOrFail();
$attributes = [
'name' => $request->input('name'),
'email' => $request->input('email')
];
$subscribable->subscribers()->create($attributes);
}
See laravel doc on relationship
So, when getting an Object from the database i do something like this in the Object Controller:
public function show(Request $request, Response $response, array $args)
{
$id = (int)$args['oid'];
$object = $this->object->getObjectById($id);
$data = $this->fractal->createData(new Item($object, new ObjectTransformer()))->toArray();
return $response->withJson($data);
}
I'm using fractal to transform the database structure to the needed JSON format and Eloquent for the Database access.
Then i'm getting something like this:
{
"propertyId": 12345,
"created": "2017-12-29T19:25:23+01:00",
"modified": "2018-06-07T17:28:04+02:00",
"published": true,
"market": [
"buy"
],
"text": {
"title": "Object Title"
}
}
I'm sending the exact same JSON string (without the ID) via Postman as application/json.
When trying to save a new object i'm doing this in the Controller:
public function store(Request $request, Response $response, array $args)
{
$object = new Object($request->getParsedBody());
//dd($request->getParsedBody());
$object->save(); // nothing happens, just an empty entry
}
The Object Class
class Object extends \Comp\Models\Mapper
{
protected $database;
protected $hidden = array('created_by', 'checked_out', 'checked_out_time', 'modified_by', 'access', 'params', 'oid', 'video');
protected $casts = [
'published' => 'boolean',
'featured' => 'boolean',
'rating' => 'float',
];
protected $dates = ['created','modified'];
public $timestamps = false;
/*protected $fillable = [
'shop_id','vendor_id','name','address','pincode','phone','shop_type'
];*/
public function __construct( $database)
{
$this->setTable('objects');
$this->database = $database;
}
}
The "Mapper" Class
<?php
namespace Comp\Models;
use Interop\Container\ContainerInterface;
use Illuminate\Database\Eloquent\Model;
abstract class Mapper extends Model {
protected $db;
public function __construct(ContainerInterface $container) {
}
public function removeEmptyElements(array $array)
{
}
}
I don't know if and how to do a transformation again, to map the structure for the Eloquent ORM.
Update 1:
I just spotted this:
https://github.com/tuupola/slim-todo-backend/blob/master/app.php
So do i need something like Spot and Fractal together? I wanted to have a central Transformer and not multiple places for output and input. And also i use Eloquent and cant use another ORM...
Update 2:
Added Object Model and Mapper Class
Any ideas are very appreciated.
We can insert it very easily.I did this .I use slim 3.0 frame work and laravel Eloquent
Here i explain detailed structure of my project
First you need to install Eloquent data base driver and create models
<?php
require 'vendor/autoload.php';
include 'dbboot.php';
use User\Models\User;
$app = new \Slim\App([
'settings' => [
'displayErrorDetails' => true,
'debug' => true,
'whoops.editor' => 'sublime',
]
]);
$app->get('/user', function ($request, $response, $args) {
$_user = new User();
$users = $_user->all();
$payload = [];
$payload['user']=$users;
return $response->withStatus(200)->withJson($payload);
});
$app->post('/user', function($request,$response,$args) {
$_user = new User();
$user = $request->getParsedBodyParam('userinfo', '');
$user_id=$_user :: insertGetId($user);
$payload = [];
$payload['user_id']=$user_id;
$payload['message']="Insertion success";
return $response->withStatus(200)->withJson($payload);
});
// Run app
$app->run();
For source code please clone my Github repository:
https://github.com/sherinmac/slim3-with-eloquent.git
I'm trying to update some values of a related model but after assigning the new values and using save() or push() the values are not updated in database. More than that, execution just stops at those methods and all I can see is a blank page. No errors, no nothing, it just doesn't even reach the return statement. If I use the try-catch, it just skips the save() or push().
Here is the Product model (just without the fields and methods that are not related to what I'm currently trying to do):
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $table = "products";
public $timestamps = false;
public $fillable = [
...
];
public function userProduct()
{
return $this->belongsTo("\\App\\Models\\UserProduct", "id", "product_id");
}
}
The UserProduct model with fields which I'm trying to update:
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class UserProduct extends Model
{
protected $primaryKey = null;
public $incrementing = false;
protected $table = "user_product";
public $fillable = [
...
"is_featured",
"is_hidden_from_latest"
...
];
public function product()
{
return $this->belongsTo("\\App\\Models\\Product", "product_id", "id");
}
public function pendingProduct()
{
return $this->belongsTo("\\App\\Models\\PendingProduct", "target_product_id", "target_product");
}
}
Code from the controller:
$replaced_product_sku = Input::get("replaced_sku");
$new_product_sku = Input::get("new_sku");
$products = Product::with([
"userProduct" => function($q) {
$q->orderBy("updated_at", "asc");
}
])->where("product_status", "live")->get();
if (!$found_replaced = $products->where("item_sku", $replaced_product_sku)->first()) {
return redirect("admin/content")
->with("danger", "Replaced product was not found.");
}
if (!$found_new = $products->where("item_sku", $new_product_sku)->first()) {
return redirect("admin/content")
->with("danger", "The new featured product was not found.");
}
$found_replaced->userProduct->is_featured = 0;
$found_replaced->userProduct->is_hidden_from_latest = 1;
$found_new->userProduct->is_featured = 1;
$found_new->userProduct->is_hidden_from_latest = 0;
$found_replaced->userProduct->save();
$found_new->userProduct->save();
return redirect("admin/content")
->with("...", "...");
Tried using push() method instead of save() but the only thing that happens is that execution stops at $found_replaced->userProduct->save(); and a blank page is displayed. Also tried something like this:
$found_replaced->update([
"userProduct.is_featured" => 0,
"userProduct.is_hidden_from_latest" => 1
]);
$found_new->update([
"userProduct.is_featured" => 1,
"userProduct.is_hidden_from_latest" => 0
]);
but still without success.
First you have to fix the relations:
In Product model:
public function userProduct()
{
return $this->hasOne("\\App\\Models\\UserProduct", "product_id", "id");
}
In UserProduct model:
public function product()
{
return $this->belongsTo("\\App\\Models\\Product", "product_id", "id");
}
The solution was using this approach:
$found_replaced->update([
"userProduct.is_featured" => 0,
"userProduct.is_hidden_from_latest" => 1
]);
$found_new->update([
"userProduct.is_featured" => 1,
"userProduct.is_hidden_from_latest" => 0
]);
that I've posted in the question, but the mistake was that I was using it wrong, so I've edited it into this and it worked fine:
$found_replaced->userProduct()->update([
"is_featured" => 0,
"is_hidden_from_latest" => 1
]);
$found_new->userProduct()->update([
"is_featured" => 1,
"is_hidden_from_latest" => 0
]);
Seems that save() just doesn't work as expected on relation attributes.
Thank you for your help anyway! ;)
I am trying to use the laravel 5.3 notification system. I have a many to many relationship on a couple of models. What I need to do is loop through all of the request data and send a notification to everyone appropriate. It seems that the notification methods won't work within a foreach loop. The error is:
BadMethodCallException in Builder.php line 2448:
Call to undefined method Illuminate\Database\Query\Builder::routeNotificationFor()
The code I am trying to figure out is:
public function storeHoursused(Request $request, Lessonhours $lessonhours)
{
$this->validate($request, [
'date_time' => 'required',
'numberofhours' => 'required|numeric',
'comments' => 'required|max:700'
]);
$hoursused = new Hoursused();
$hoursused->date_time = $request['date_time'];
$hoursused->numberofhours = $request['numberofhours'];
$hoursused->comments = $request['comments'];
$lessonhours->hoursused()->save($hoursused);
foreach($lessonhours->players as $player){
$player->users;
Notification::send($player, new HoursusedPosted($player->user));
//$lessonhours->player->notify(new HoursusedPosted($lessonhours->player->users));
}
return back()->with(['success' => 'Hours Used successfully added!']);
}
Is there a way to collect related data and pass to notification methods?
UPDATE:
The Players model looks like:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Collective\Html\Eloquent\FormAccessible;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Notifiable;
use Carbon\Carbon;
class Players extends Model
{
public $table = "players";
protected $fillable = array('fname', 'lname', 'gender', 'birthdate');
public function users()
{
return $this->belongsTo('App\User', 'users_id');
}
public function lessonhours()
{
return $this->belongsToMany('App\Lessonhours', 'lessonhour_player', 'players_id', 'lessonhours_id')
->withTimestamps();
}
public function getFullName($id)
{
return ucfirst($this->fname ) . ' ' . ucfirst($this->lname);
}
protected $dates = ['birthdate'];
protected $touches = ['lessonhours'];
public function setBirthdateAttribute($value)
{
$this->attributes['birthdate'] = Carbon::createFromFormat('m/d/Y', $value);
}
}
Your $player model needs to use the Illuminate\Notifications\Notifiable trait.