How paginate result of http response with laravel livewire - php

I want to populate a table with calling HTTP request and fetch a JSON fine,
I set up live wire like this which can properly populate the table:
public function render()
{
$this->response = Http::timeout(30)->get('http://127.0.0.1:8000/api/lines')->body();
return view('livewire.line-index', ['lines' =>json_decode($this->response)])->layout('layouts.app', ['header' => 'Line Management']);
}
but when I add paginate like this:
public function render()
{
$this->response = Http::timeout(30)->get('http://127.0.0.1:8000/api/lines')->body();
return view('livewire.line-index', ['lines' =>json_decode($this->response)->paginate(25)])->layout('layouts.app', ['header' => 'Line Management']);
}
I see this error:
Call to a member function paginate() on array

Solution:
need to convert array to the collection and then creating a macro for using pagination on
collection.
public function render()
{
$this->response = Http::timeout(30)->get('http://127.0.0.1:8000/api/lines')->body();
$collection = collect(json_decode($this->response));
return view('livewire.line-index', ['lines' =>$collection->paginate(20)])->layout('layouts.app', ['header' => 'Line Management']);
}
For creating a macro you need to update the AppServiceProvider.php file:
<?php
namespace App\Providers;
use Illuminate\Support\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
/**
* Paginate a standard Laravel Collection.
*
* #param int $perPage
* #param int $total
* #param int $page
* #param string $pageName
* #return array
*/
Collection::macro('paginate', function($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
}
}
Reference: https://gist.github.com/simonhamp/549e8821946e2c40a617c85d2cf5af5e

Related

How to paginate a result array in CakePHP 3

I have a find() method in my if else statement that queries the database and returns the data as an array. The if part works fine. The problem is in the else part. When I try to access the index interface in the browser, am getting this error.
Unable to locate an object compatible with paginate.
RuntimeException
From what I have gathered so far, the paginate() method works with objects not arrays. Am stuck on how to come to my desired outcome. Am new to CakePHP, a not so advanced/complicated response would be appreciated. Thanks
/**
* Assets Controller
*
*
* #method \App\Model\Entity\Asset[] paginate($object = null, array $settings = [])
*/
class AssetsController extends AppController
{
/**
* Index method
*
* #return \Cake\Http\Response|void
*/
public function index()
{
$this->loadModel('Users');
$username = $this->request->session()->read('Auth.User.username');
$userdetail = $this->Users->find('all')->where(['username' => $username])->first();
$school = $userdetail->school_unit;
$roleid = $userdetail->role_id;
if ($roleid == 1) {
$this->paginate = [
'contain' => ['SchoolUnits', 'AssetConditions', 'AssetCategories', 'AssetGroups', 'AssetStatus']
];
$assets = $this->paginate($this->Assets);
$this->set(compact('assets'));
$this->set('_serialize', ['assets']);
} else {
$results = $this->Assets->find('all')->contain(['SchoolUnits', 'AssetConditions', 'AssetCategories', 'AssetGroups', 'AssetStatus'])->where(['school_unit_id' => $school])->first();
$assets = $this->paginate($this->$results);
$this->set(compact('assets'));
$this->set('_serialize', ['assets']);
}
}

Laravel override renderer view

I would like that as soon as an ajax request is sent where there is view ('view') instead of returning the raw view its returns a JSON
Like that:
/**
* #param \Illuminate\Contracts\View\View $view
* #return \Illuminate\Http\JsonResponse
*/
protected function ajaxResponse (View $view)
{
return response()->json([
'id' => $view->getData()['page'],
'title' => $view->getData()['title'],
'content' => $view->renderSections()['content'],
'replacepage' => null,
]);
}
But I absolutely don't know how to do it I don't want to repeat myself in each controller
I have tried to replace View with mine but it does not work as I would like everything to work but I cannot recover the section of my page
<?php
namespace App\Extensions\View;
use Illuminate\View\View;
class AjaxView extends View
{
/**
* Get the contents of the view instance.
*
* #return string
* #throws \Throwable
*/
protected function renderContents()
{
if(request()->ajax()) {
echo $this->getResponse($this->getData());
exit;
}
return parent::renderContents();
}
/**
* #param array $data
* #return false|string
*/
public function getResponse (array $data = [])
{
return json_encode([
'id' => $data['page'],
'title' => (!empty($data['title']) ? $data['title'] . ' - ' . config('app.name') : null),
'content' => $this->renderSections()['content'],
'replacepage' => null
]);
}
}
This returns:
Perhaps you can do it this way:
In app/Http/Controllers/Controller.php, add method response();
protected function view($viewPath, $content, $status = 200, array $headers = [])
{
if(request()->ajax()) {
return response()->json($content, $status, $headers);
}
return view($viewPath, $content);
}
Your controller methods can then use like this:
public function create()
{
// logic
return $this->view('view_path', $data);
}
I have change your function by
protected function ajaxView(string $viewPath, array $content = [], int $status = 200, array $headers = [])
{
$view = view($viewPath, $content);
if(request()->ajax()) {
dd($view->getData());
return response()->json([
'id' => $this->view->getData()['page'],
'title' => $this->view->getData()['title'],
'content' => $this->view->renderSections()['content'],
'replacepage' => null,
], $status, $headers);
}
return $view;
}
But the dd() record array is empty if i put my dd() outside of my if the record is not empty

Laravel get data from db array not working

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));
} // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Laravel 5 cannot update relationship

I've been trying for countless hours now, but still having issues updating a models relationship, the closest I've got to is a 'Method fill does not exist.' error.
Listing model:
class Listing extends Model
{
protected $fillable = [
'uid', 'start_date',...........
];
public function locations()
{
return $this->hasMany('App\ListingLocation');
}
}
Location (relationship to listing - hasMany):
class ListingLocation extends Model
{
protected $fillable = [
'listing_id', 'location',
];
public function listing()
{
return $this->belongsTo('App\Listing');
}
}
This returns my model and relationship, which I can view with dd($listing)
$listing = Listing::with('locations')->findOrFail($id);
This will update my listing model, which I can see the changes after calling dd($listing) again
$listing->fill($array);
However when I attempt to fill the relationship as per below, I get 'Method fill does not exist.'
$listing->locations->fill($array['locations']);
How can I update the relationship successfully before calling $listing->push();?
Change your location to a single record, not a collection
For example:
$listings->locations->first()->fill($array['locations']);
to fill every record use foreach
#foreach($listings->locations as $location)
$location->fill(do_something);
#endforeach
I ended up creating a new class to extend hasMany which allowed me to use sync as per alexweissman at https://laracasts.com/discuss/channels/general-discussion/syncing-one-to-many-relationships.
Extract from forum:
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* #link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/HasMany.php
*/
class HasManySyncable extends HasMany
{
public function sync($data, $deleting = true)
{
$changes = [
'created' => [], 'deleted' => [], 'updated' => [],
];
$relatedKeyName = $this->related->getKeyName();
// First we need to attach any of the associated models that are not currently
// in the child entity table. We'll spin through the given IDs, checking to see
// if they exist in the array of current ones, and if not we will insert.
$current = $this->newQuery()->pluck(
$relatedKeyName
)->all();
// Separate the submitted data into "update" and "new"
$updateRows = [];
$newRows = [];
foreach ($data as $row) {
// We determine "updateable" rows as those whose $relatedKeyName (usually 'id') is set, not empty, and
// match a related row in the database.
if (isset($row[$relatedKeyName]) && !empty($row[$relatedKeyName]) && in_array($row[$relatedKeyName], $current)) {
$id = $row[$relatedKeyName];
$updateRows[$id] = $row;
} else {
$newRows[] = $row;
}
}
// Next, we'll determine the rows in the database that aren't in the "update" list.
// These rows will be scheduled for deletion. Again, we determine based on the relatedKeyName (typically 'id').
$updateIds = array_keys($updateRows);
$deleteIds = [];
foreach ($current as $currentId) {
if (!in_array($currentId, $updateIds)) {
$deleteIds[] = $currentId;
}
}
// Delete any non-matching rows
if ($deleting && count($deleteIds) > 0) {
$this->getRelated()->destroy($deleteIds);
$changes['deleted'] = $this->castKeys($deleteIds);
}
// Update the updatable rows
foreach ($updateRows as $id => $row) {
$this->getRelated()->where($relatedKeyName, $id)
->update($row);
}
$changes['updated'] = $this->castKeys($updateIds);
// Insert the new rows
$newIds = [];
foreach ($newRows as $row) {
$newModel = $this->create($row);
$newIds[] = $newModel->$relatedKeyName;
}
$changes['created'][] = $this->castKeys($newIds);
return $changes;
}
/**
* Cast the given keys to integers if they are numeric and string otherwise.
*
* #param array $keys
* #return array
*/
protected function castKeys(array $keys)
{
return (array) array_map(function ($v) {
return $this->castKey($v);
}, $keys);
}
/**
* Cast the given key to an integer if it is numeric.
*
* #param mixed $key
* #return mixed
*/
protected function castKey($key)
{
return is_numeric($key) ? (int) $key : (string) $key;
}
}
You can then override Eloquent's hasMany method in your model class:
/**
* Overrides the default Eloquent hasMany relationship to return a HasManySyncable.
*
* {#inheritDoc}
*/
public function hasMany($related, $foreignKey = null, $localKey = null)
{
$instance = $this->newRelatedInstance($related);
$foreignKey = $foreignKey ?: $this->getForeignKey();
$localKey = $localKey ?: $this->getKeyName();
return new HasManySyncable(
$instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey
);
}
/**
* Get all of a user's phone numbers.
*/
public function phones()
{
return $this->hasMany('App\Phone');
}
A sync method will now be available to any hasMany relationships you have on this model:
$user->phones()->sync([
[
'id' => 21,
'label' => "primary",
'number' => "5555551212"
],
[
'id' => null,
'label' => "mobile",
'number' => "1112223333"
]
]);

three different table in one views laravel 5.2

Hi I would like to display three different table in one views using laravel 5.2. but it seems i am having problem on it.
my HomeController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use DB;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class HomeController extends Controller
{
public function index()
{
$about = DB::select('select * from about');
$teams = DB::select('select * from teams');
$services = DB::select('select * from services');
return view('master', ['about' => $about], ['teams' => $teams], ['services' => $services]);
}
}
in my views:
#foreach ($about as $abt)
<h4>{{$abt->title}}</h4>
<span class="semi-separator center-block"></span>
<p>{{$abt->description}}</p>
#endforeach
#foreach ($teams as $team)
<div class="creative-symbol cs-creative">
<img src="assets/images/new/{{$team->icon}}" alt="">
<span class="semi-separator center-block"></span>
<h4><b>{{$team->title}}</b></h4>
<p>{{$team->description}}</p>
</div>
#endforeach
i cant display the third one which is the $services. pls help me.
when i add the third one it will display an error
In Laravel 5.1, I found the following code in /vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:
if (! function_exists('view')) {
/**
* Get the evaluated view contents for the given view.
*
* #param string $view
* #param array $data
* #param array $mergeData
* #return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
function view($view = null, $data = [], $mergeData = [])
{
$factory = app(ViewFactory::class);
if (func_num_args() === 0) {
return $factory;
}
return $factory->make($view, $data, $mergeData);
}
}
This is the function you are attempting to call. Notice how many arguments there are (there are 3). You are attempting pass in 4. I think what you're trying to do is something like this:
return view('master', [
'about' => $about,
'teams' => $teams,
'services' => $services
]);
This is now calling the same function, but only passing two arguments.
Please change this:
return view('master', ['about' => $about], ['teams' => $teams], ['services' => $services]);
to this:
return view('master', ['about' => $about, 'teams' => $teams, 'services' => $services]);

Categories