When I run the code I get no error but the data I am trying to display is not displaying it's just blank.. can someone tell me what I'm doing wrong?
My controller:
public function openingPage($id) {
$this->getGames();
$games = $this->getGames();
return view('caseopener')->with('games',$games);
}
private function getGames() {
$games = array();
foreach ($this->data->items as $item) {
$game = new Game($item);
$games[] = array(
'id' => $game['id'],
'name' => $game['name'],
'price' => $game['price'],
'image' => $game['image'],
);
}
return $games;
}
The 'Game' Model that is used in 'getGames function':
class Game extends Model
{
private $id;
public $data;
public function __construct($id) {
parent::__construct();
$this->id = $id;
$this->data = $this->getData();
}
private function getData() {
$game = DB::table('products')->where('id', 1)->first();
if(empty($game)) return array();
return $game;
}
}
The view:
#foreach ($games as $game)
<div class="gold">$ {{ $game['price'] }}</div>
#endforeach
I think you are over-complicating things. You could simplify your flow like this:
Given your provided code, it seems like you are using a custom table name ('products') in your Game model. So we'll address this first:
Game.php
class Game extends Model
{
protected $table = 'products'; //
}
Now, it seems like you're searching an array of Game ids ($this->data->items). If so, you could make use of Eloquent for your query, specially the whereIn() method:
YourController.php
public function openingPage($id)
{
$games = Game::whereIn('id', $this->data->items)->get();
return view('caseopener')->with('games', $games);
}
Optionally, if you want to make sure of just returning the id, name, price and image of each Game/product, you could format the response with API Resources:
php artisan make:resource GameResource
Then in your newly created class:
app/Http/Resources/GameResource.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class GameResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'image' => $this->image,
];
}
}
So now just update your controller:
YourController.php
use App\Http\Resources\GameResource;
public function openingPage($id)
{
$games = Game::whereIn('id', $this->data->items)->get();
return view('caseopener')->with('games', GameResource::collection($games));
} // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Related
Project in Laravel (9), and PHP (8.1).
I want to import an excel file and use maatwebsite/excel (3.1) package.
I can import a file, and save the file into the model, like this:
import class:
class BankTransfersHistoryImport implements ToModel, WithHeadingRow, WithValidation
{
use Importable;
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new BankTransfersHistory([
'loanId' => $row['loanId'],
'actionDate' => transformDate($row['actionDate']),
'worth' => $row['worth'],
.
.
]);
}
public function headingRow(): int
{
return 2;
}
public function rules(): array
{
return [
'*.loanId' => ['required', 'numeric'],
... some roles ...
];
}
}
controller:
$import = new BankTransfersHistoryImport;
try {
// date validation
$collection = $import->toCollection($file);
... some validation about the date ...
$import->import($file);
... check and update rows ...
return [
"message" => some message,
"data" => [
some data
],
];
} catch (\Maatwebsite\Excel\Validators\ValidationException$e) {
$failures = $e->failures();
foreach ($failures as $failure) {
$failure->row(); // row that went wrong
$failure->attribute(); // either heading key (if using heading row concern) or column index
$failure->errors(); // Actual error messages from Laravel validator
$failure->values(); // The values of the row that has failed.
}
return $failures;
}
My question is:
If I can get the response of the file after saving the data, and that will give me the data with the id of the row that was saved.
In some cases, I will have to update a row. That's why I would like to get the ID.
Now in the check and update rows section, I update by loanId + actionDate. I want it to be done by ID.
something like this:
code:
$data = $import->import($file);
data will be like:
[
{
"id": 1,
"loanId": 21001,
"actionDate": "2020-01-02T00:00:00.000000Z",
"worth": 2997.09,
"offerId": 1,
},
{
"id": 2,
"loanId": 21002,
"actionDate": "2020-01-02T00:00:00.000000Z",
"worth": 3000,
"offerId": 10,
},
]
You can create a function on import class which will return the imported data, adding a sample for your reference.
UsersImport.php
<?php
namespace App\Imports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\ToModel;
class UsersImport implements ToModel
{
private $rows;
public function __construct() {
$this->rows = collect();
}
/**
* #param array $row
*
* #return User|null
*/
public function model(array $row)
{
$user = new User([
'name' => $row[0],
'email' => $row[1],
'password' => bcrypt(12345678),
]);
$this->rows->push($user);
return $user;
}
/**
* Returns Imported Data
*
* #return \Illuminate\Support\Collection
*/
public function getImportedData(): \Illuminate\Support\Collection
{
return $this->rows;
}
}
Your Import Function in Controller
public function import(UsersImport $usersImport)
{
Excel::import($usersImport, public_path('users.xlsx'));
$usersImport->getImportedData();
}
This one has happened to me before but I have no idea why and how to avoid it. So I have a static function in a Model which gets all the database rows and uses a foreach loop to read another table but I am unable to correctly read the row data:
public static function test()
{
$accounts = self::where( 'is_enabled', 1 )->get();
foreach ( $accounts as $account ) {
$map = AccountMap::where( 'account_id', $account->id )->first();
$location = Location::getLocation( $map->location_id );
$data = $location->getData();
}
}
So the above function gathers an array of items ($accounts) this is then passed into a foreach loop all is fine to this point but if i now use $account->id it is null. The id is shown in the Account object in its attributes folder.
A very similar function is used elsewhere in this model but it uses a passed id and this one works (however $account->id is null). The issue is not the database or column names:
public static function getThisLocation( $id )
{
$account = self::find( $id );
$map = AccountMap::where( 'account_id', $id )->first();
location = Location::getLocation( $map->location_id );
$data = $location->getData();
return $data;
}
*** EDIT ***
Account, AccountMap and Location are all Eloquent models
namespace App\Models;
use Eloquent;
use App\Notifications\AccountMessages;
use Kyslik\ColumnSortable\Sortable;
use Illuminate\Notifications\Notifiable;
/**
* #method static find(int $id)
*/
class Account extends Eloquent
{
use Sortable;
use Notifiable;
public $sortable = [
'id',
'name',
'lastupdate',
'url'
];
public static function test()
{
$accounts = self::where( 'is_enabled', 1 )->get();
foreach ( $accounts as $account ) {
$map = AccountMap::where( 'account_id', $account->id )->first();
$location = Location::getLocation( $map->location_id );
$data = $location->getData();
}
}
public static function getThisLocation( $id )
{
$account = self::find( $id );
$map = AccountMap::where( 'account_id', $id )->first();
location = Location::getLocation( $map->location_id );
$data = $location->getData();
return $data;
}
}
namespace App\Models;
use Eloquent;
use Kyslik\ColumnSortable\Sortable;
/**
* #method static where(string $string, int $id)
*/
class AccountMap extends Eloquent
{
use Sortable;
public $sortable = [
'id',
'account_id',
'location'
];
}
*** MORE EDIT ***
I have confirmed that using $account->attributes['id'] has worked but I've no idea why what I expected to work didn't ($account->id)
The problem must be something related to communication of your model and migration.
Add this dd() to your current test function:
public static function test()
{
$accounts = self::where( 'is_enabled', 1 )->get();
foreach ( $accounts as $account ) {
if ($account->id){
$map = AccountMap::where( 'account_id', $account->id )->first();
$location = Location::getLocation( $map->location_id );
$data = $location->getData();
} else {
dd($account)
}
}
}
Then Check the result and see is there the id filed on your response? If not, The id field doesn't exist on your self Model and it's Your problem's cause.
Finally, Check your model fields easily with :
public function testReturnOfSelfModel()
{
$data= self::all();
dd($data);
}
If you have id on this dd function, Your Model working properly. If not, you dont have id field.
Also, it is more professional to change Capitalize your model's first charachter. It sholud be Self, not self.
I'd suggest to setup two proper data Model (a migration would need to create these tables):
class Account extends Model {
protected $table = 'accounts';
public $timestamps = false;
/**
* The attributes that are mass assignable.
* #var array
*/
protected $fillable = [];
/**
* The attributes that should be hidden for arrays.
* #var array
*/
protected $hidden = [];
}
Unless defining protected $table it will definitely not know what to do.
It's rather unclear what you're even trying to accomplish with AcountMap, but it may need a relation defined; which eg. with return $this->belongsTo(Account::class); ...while simply adding lat & lng to class Account would be far less complex and perfectly fine, while it's only 1 location.
Laravel 5.8
PHP 7.4
I want to load the relationships conditionally like
http://127.0.0.1:8000/api/posts
and
http://127.0.0.1:8000/api/posts/1 are my end points now, I want to load comments like
http://127.0.0.1:8000/api/posts/?include=comments and
http://127.0.0.1:8000/api/posts/1/?include=comments
If the query parameter is there, only then it should load comments with posts or it should load only posts/post
I am doing this by referring a blog post
now, RequestQueryFilter
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
class RequestQueryFilter
{
public function attach($resource, Request $request = null)
{
$request = $request ?? request();
return tap($resource, function($resource) use($request) {
$this->getRequestIncludes($request)->each(function($include) use($resource) {
$resource->load($include);
});
});
}
protected function getRequestIncludes(Request $request)
{
// return collect(data_get($request->input(), 'include', [])); //single relationship
return collect(array_map('trim', explode(',', data_get($request->input(), 'include', [])))); //multiple relationships
}
}
and in helper
<?php
if ( ! function_exists('filter') ) {
function filter($attach)
{
return app('filter')->attach($attach);
}
}
?>
in PostController
public funciton show(Request $request, Post $post) {
return new PostResource(filter($post));
}
but when I am trying to retrieve
http://127.0.0.1:8000/api/posts/1/?include=comments getting no comments, with no error in log
A work around will be PostResource
public function toArray($request)
{
// return parent::toArray($request);
$data = [
'id' => $this->id,
'name' => $this->title,
'body' => $this->content,
];
$filter = $request->query->get('include', '');
if($filter){
$data[$filter] = $this->resource->$filter;
}
return $data;
}
I want to load the relationships conditionally like
Lazy Eager Loading using the load() call
The Lazy Eager Loading accomplishes the same end results as with() in Laravel, however, not automatically. For example:
?include=comments
// Get all posts.
$posts = Post::without('comments')->all();
if (request('include') == 'comments')) {
$posts->load('comments');
}
return PostResource::collection($posts);
Alternativelly, you could require the include query string to be an array:
?include[]=comments&include[]=tags
// Validate the names against a set of allowed names beforehand, so there's no error.
$posts = Post::without(request('includes'))->all();
foreach (request('includes') as $include) {
$posts->load($include);
}
return PostResource::collection($posts);
The call without() is only required in case you defined your model to automatically eager load the relationships you want to conditionally load.
With all data filtered in Controller, just make sure to display only loaded relations in your PostResource
public function toArray($request) {
$data = [...];
foreach ($this->relations as $name => $relation)
{
$data[$name] = $relation;
}
return $data;
}
I would create a custom resource for the posts with
php artisan make_resource
command.
E.g. PostResource.
The toArray function of the resource must return the data.
PostResource.php
public function toArray($request){
$data =['title' => $this->resource->title,
'body' => $this->resource->body,
'images' => new ImageCollection($this->whenLoaded('images')),
];
$filter = $request->query->get('filter', '');
if($filter){
$data['comments'] => new CommentCollection($this->resource->comments);
}
return $data;
}
Also, for collections, you need to create a ResourceCollection.
PostResourceCollection.php
class PostResourceCollection extends ResourceCollection
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request
* #return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}
In your controller:
PostsController.php
//show one post
public function show(Post $post, Request $request)
{
/**this response is for API or vue.js if you need to generate view, pass the resource to the view */
return $this->response->json( new PostResource($post));
}
//list of posts
public function index(Request $request)
{
$posts = Post::all();
/**this response is for API or vue.js if you need to generate view, pass the resource to the view */
return $this->response->json( new PostResourceCollection($posts));
}
Partial Solution
It will need a small change in resource class
public function toArray($request)
{
// return parent::toArray($request);
$data = [
'id' => $this->id,
'title' => $this->title,
'body' => $this->body,
'comments' => new CommentCollection($this->whenLoaded('comments')),
'images' => new ImageCollection($this->whenLoaded('images')),
];
return $data;
}
and it will load comments and images if loaded and that depends on the include query parameter, if that is not included, it will not load the relationship.
However,
In post collection
return [
'data' => $this->collection->transform(function($post){
return [
'id' => $post->id,
'title' => $post->title,
'body' => $post->body,
'comments' => new CommentCollection($post->whenLoaded('comments')),
'images' => new ImageCollection($post->whenLoaded('images')),
];
}),
];
will results in
"Call to undefined method App\Models\Customer::whenLoaded()",, if anyone suggests a complete solution, it will be a great help, if I will able to do, it I will update here.
I'm trying to use Moltin Cart in my Laravel 4 app:
I installed Moltin Cart through composer,
then added the Service Provider ('Moltin\Cart\CartServiceProvider')
and added the aliases ('Cart' => 'Moltin\Cart\Facade').
Now I want only logged in users to access the cart so I added
$this->beforeFilter('auth', array('only' => 'postAddToCart', 'getCart', 'getRemoveItem'));
in my storeController.
But I get this error when I try to access
Declaration of Moltin\Cart\Storage\LaravelSession::insertUpdate() must be compatible with Moltin\Cart\StorageInterface::insertUpdate(Moltin\Cart\Item\Line $item)
My Store Controller is :
<?php
class StoresController extends \BaseController {
public function __construct()
{
parent::__construct();
$this->beforeFilter('csrf', array('on' => 'post'));
$this->beforeFilter('auth', array('only' => 'postAddToCart', 'getCart', 'getRemoveItem'));
}
public function getIndex()
{
return View::make('stores.index')
->with('products', Product::take(4)->orderBy('created_at', 'DESC')->get());
}
public function getView($id)
{
return View::make('stores.view')
->with('product', Product::find($id));
}
public function getCategory($category_id)
{
return View::make('stores.category')
->with('products', Product::where('category_id', '=', $category_id)->paginate(6))
->with('category', Category::find($category_id));
}
public function getSearch()
{
$keyword = Input::get('keyword');
return View::make('stores.search')
->with('products', Product::where('title', 'LIKE', '%'. $keyword . '%')->get())
->with('keyword', $keyword);
}
public function postAddToCart()
{
$product = Product::find(Input::get('id'));
$qunatity = Input::get('qunatity');
Cart::insert(array(
'id' => $product->id,
'name' => $product->name,
'price' => $product->price,
'qunatity' => $qunatity,
'image' => $product->image
));
return Redirect::to('store/cart');
}
public function getCart()
{
return View::make('stores.cart')->with('products', Cart::contents());
}
public function getRemoveItem($identifier)
{
$product = Cart::item($identifier);
$product->remove();
return Redirect::to('store/cart');
}
}
The short answer:
Resume your installation assuming that moltin/cart and moltin/laravel-cart repositories are in sync.
The long answer:
As the error message states:
Moltin\Cart\StorageInterface::insertUpdate(Moltin\Cart\Item\Line $item)
Moltin\Cart\Storage\LaravelSession::insertUpdate()
don't have the same signature.
They should be in sync! The issue has nothing to do at all with your StoresController.
I checked:
https://github.com/moltin/cart/blob/master/src/Moltin/Cart/StorageInterface.php and
https://github.com/moltin/laravel-cart/blob/master/src/Moltin/Cart/Storage/LaravelSession.php
I find out that the signatures are OK as the time of my answer post.
namespace Moltin\Cart;
interface StorageInterface
{
/**
* Add or update an item in the cart
*
* #param Item $item The item to insert or update
* #return void
*/
public function insertUpdate(Item $item); // <<<< This is it!
...
}
namespace Moltin\Cart\Storage;
use Moltin\Cart\Item;
...
class LaravelSession implements \Moltin\Cart\StorageInterface
{
...
/**
* Add or update an item in the cart
*
* #param Item $item The item to insert or update
* #return void
*/
public function insertUpdate(Item $item) // <<<< This is it!
{
...
}
...
}
My guess is that you did your install when the repositories (knowing that moltin/cart is a dependency of moltin/laravel-cart) were not in sync for some reason.
I hope I can explain this clearly, apologies in advance if it is confusing. I have a goals table which hasOne of each of bodyGoalDescs, strengthGoalDescs and distanceGoalDescs as shown below
goals.php
class Goal extends BaseModel
{
protected $guarded = array();
public static $rules = array();
//define relationships
public function user()
{
return $this->belongsTo('User', 'id', 'userId');
}
public function goalStatus()
{
return $this->hasOne('GoalStatus', 'id', 'goalStatus');
}
public function bodyGoalDesc()
{
return $this->hasOne('BodyGoalDesc', 'id', 'bodyGoalId');
}
public function distanceGoalDesc()
{
return $this->hasOne('DistanceGoalDesc', 'id', 'distanceGoalId');
}
public function strengthGoalDesc()
{
return $this->hasOne('StrengthGoalDesc', 'id', 'strengthGoalId');
}
//goal specific functions
public static function yourGoals()
{
return static::where('userId', '=', Auth::user()->id)->paginate();
}
}
each of the three tables looks like this with the function details changed
class BodyGoalDesc extends BaseModel
{
protected $guarded = array();
public static $rules = array();
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'bodyGoalDescs';
//define relationships
public function goal()
{
return $this->belongsTo('Goal', 'bodyGoalId', 'id');
}
}
a goal has either a body goal, a strength goal, or a distance goal. I am having a problem with this method in the controller function
<?php
class GoalsController extends BaseController
{
protected $goal;
public function __construct(Goal $goal)
{
$this->goal = $goal;
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
$thisgoal = $this->goal->find($id);
foreach ($this->goal->with('distanceGoalDesc')->get() as $distancegoaldesc) {
dd($distancegoaldesc->DistanceGoalDesc);
}
}
}
when I pass through goal 1 which has a distance goal the above method dies and dumps the Goal object with the details of goal 1 and an array of its relations including an object with DistanceGoalDes.
when I pass through goal 2 it passes through exactly the same as if I had passed through goal 1
if I dd() $thisgoal i get the goal that was passed through
what I want ultimately is a method that returns the goal object with its relevant goal description object to the view but this wont even show me the correct goal details not too mind with the correct relations
this function is now doing what I want it to do, I am sure there is a better way (besides the fact that its happening in the controller right now) and I would love to hear it.
public function show($id)
{
$thisgoal = $this->goal->find($id);
if (!$thisgoal->bodyGoalDesc == null) {
$goaldesc = $thisgoal->bodyGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('bodygoaldesc', $goaldesc);
} elseif (!$thisgoal->strengthGoalDesc == null) {
$goaldesc = $thisgoal->strengthGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('strengthgoaldesc', $goaldesc);
} elseif (!$thisgoal->distanceGoalDesc == null) {
$goaldesc = $thisgoal->distanceGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('distancegoaldesc', $goaldesc);
}
}