Call to a member function links() on array in Laravel 5.6 - php

I am using pagination in Laravel 5.6 to build an application. I am using Laravel DB instead of Eloquent. However, when I add a pagination link on view, it shows an error Call to a member function links() on array. This is because I am using an array, the default is an object with a collection. The output I am getting looks like
array:12 [▼
"current_page" => 1
"data" => array:3 [▶]
"first_page_url" => "http://127.0.0.1:8000/posts?page=1"
"from" => 1
"last_page" => 3
"last_page_url" => "http://127.0.0.1:8000/posts?page=3"
"next_page_url" => "http://127.0.0.1:8000/posts?page=2"
"path" => "http://127.0.0.1:8000/posts"
"per_page" => 3
"prev_page_url" => null
"to" => 3
"total" => 9
]
When I use normal pagination i.e. without converting to an array, the output is
LengthAwarePaginator {#264 ▼
#total: 9
#lastPage: 3
#items: Collection {#251 ▶}
#perPage: 3
#currentPage: 1
#path: "http://127.0.0.1:8000/posts"
#query: []
#fragment: null
#pageName: "page"
}
The problem I face here is adding other data to collection
I can't use the default output return by pagination() method. Can someone please suggest how to solve this issue?

Using the below, I am getting the required output.
Step 1: Include LengthAwarePaginator in the file
use Illuminate\Pagination\LengthAwarePaginator;
Step 2: Create an object of LengthAwarePaginator
$paginate = new LengthAwarePaginator(Array, countOfArray, perPage, currentPage, [
'path' => request()->url(),
'query' => request()->query()
]);
I kept currentPage value as null.
Return $paginate to view.
return view('home', ['data' => Array, 'page' => $paginate]);

Related

How to validate an array of datetimes in Laravel?

I have a form that submits an array named prazos, and I want to make sure each item is a valid datetime or null. Following the answers to this question and the Laravel docs, I have this in my Controller:
use Illuminate\Support\Facades\Validator;
// ...
$rules = array([
'prazos' => 'required|array',
'prazos.*' => 'nullable|date'
]);
$validator = Validator::make($request->all(), $rules);
$data = $validator->valid()['prazos'];
foreach($data as $id => $prazo) {
// use $data to update my database
// ...
}
The issue is, the validator is not actually stopping invalid content. If I try to submit "loldasxyz" or other gibberish, I get an error from the database. What am I doing wrong?
Note: previously I had been using validators with the syntax $data = $request->validate($rules), but for some reason it didn't work for the array-type data ($data came back empty). I'm not sure if there is some difference in how those different methods work.
Edit: this is what the parameter bag in $request looks like when I test it (the indices are ids, which is why they start at 1):
#parameters: array:3 [▼
"_token" => "Rf6mAp4lqhpZzQRxaxYsees1M0NfrFKpbGe4Hy28"
"_method" => "PUT"
"prazos" => array:5 [▼
1 => "2021-03-22 21:21"
2 => "2021-03-03 11:27"
3 => "jhbkjhg"
4 => null
5 => "2021-03-02 14:21"
]
]
And this is what the validated $data comes out as:
array:5 [▼
1 => "2021-03-22 21:21"
2 => "2021-03-03 11:27"
3 => "jhbkjhg"
4 => null
5 => "2021-03-02 14:21"
]
I wish it would tell me the third value is invalid.
Heres what youre looking for:
https://laravel.com/docs/8.x/validation#rule-date-equals
The field under validation must be equal to the given date. The dates will be passed into the PHP strtotime function in order to be converted into a valid DateTime instance.

Can you filter data on a retrieved relationship without creating a new attribute?

I have one to many relationship between users and posts.
I want to know if I eager load in the posts can I modify the collection without a new attribute getting created on the User model.
$user = User::with('posts')->get();
// Filter the posts on the user using business logic.
// Below is an example. I DO NOT want to do this logic in the db/query builder.
// Arbitrary business rule that is not easily possible to calculate in DB
$shouldGetTestPost = true;
$user->posts = $user->posts->filter(function($post) use ($shouldGetTestPost) {
if ($shouldGetTestPost && $post->name = 'test') {
return true;
}
return false;
});
dd($user);
If I run the above code laravel will create a new attribute called posts and assign the collection to that attribute instead of modifying the relationship.
e.g.
// I've removed irrelevant model data
App\User {#1145
#table: "users"
#attributes: array:6 [
"id" => 1
"email" => "test#test.com"
"password" => "secret"
"updated_at" => "2019-02-11 18:56:35"
"created_at" => "2019-02-11 18:56:35"
// Below is new
"posts" => Illuminate\Database\Eloquent\Collection {#1217
#items: array:1 [
0 => App\Post {#1269
#table: "posts"
#attributes: array:24 [
"id" => 1
"name" => 'test'
"user_id" => 1
]
}
]
}
]
#original: array:5 [...]
#relations: array:1 [
"posts" => Illuminate\Database\Eloquent\Collection {#1264
#items: array:2 [
0 => App\Post {#1269}
1 => App\Post {#1234
#table: "posts"
#attributes: array:24 [
"id" => 1
"name" => 'test'
"user_id" => 1
]
}
]
}
]
]
Another interesting thing that happens is that in #relations the data is removed from theitems array but the reference still remains. See 0 => App\Post {#1269}
Is this intended for laravel? I'm aware that laravel prioritises attributes over relations but it seems odd that it wouldn't change the relations array.
How would I only change the relations collection and not create a new attribute?
The setRelation method can be used to override what's stored in a relation.
$model->setRelation($relation, $value)
https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Concerns/HasRelationships.html#method_setRelation
However, there's very few situations where this would be useful so I still believe this is an XY problem. You can constrain the eager loading query by passing a closure as the second argument to with() which would be the solution to conditionally retrieving related items.

Laravel morphTo Returns Null

I am using Laravel 5.4 and having trouble figuring out why my morphTo relationship always returns null no matter what I do. The inverse of the relationship is fine, but when I try to retrieve the owner of the polymorphic relation, it is null.
class Opportunity extends Model {
public function Organization() {
return $this->morphTo('Organization');
}
}
class Account extends model {
public function Opportunities() {
return $this->morphMany('App\Opportunity', 'Organization');
}
}
class Department extends model {
public function Opportunities() {
return $this->morphMany('App\Opportunity', 'Organization');
}
}
$org = App\Opportunity::findOrFail(1)->Organization;
The full namespace is stored in the database and the _type and _id actually have the appropriate organization type and id in the columns (i.e., 'App\Account' and '456'). So, I know the database record and the returned Opportunity object have the correct Organization in the columns (I can see it in the database correctly), but no matter what I do, if I try to retrieve Organization it is null.
Here is the output. You will notice the Organization is in the attributes, but the relation is null and I cannot get it to return even adding ->with('Organization') to the query. It doesn't even seem to be executing the query to get the owner
#primaryKey: "ID"
+timestamps: true
#guarded: []
#hidden: []
#visible: []
#with: []
#dissociateRelations: []
#connection: null
#keyType: "int"
+incrementing: true
#perPage: 15
+exists: true
+wasRecentlyCreated: true
#attributes: array:13 [
"StageID" => 12
"TypeID" => 1
"OriginID" => 20
"Description" => "Interested in scanner fi6140"
"UserID" => 3
"SolutionValue" => ".00"
"MarginValue" => ".00"
"created_at" => "2010-09-16 11:19:00.000"
"updated_at" => "2015-09-01 12:32:00.000"
"_migrationID" => "4299"
"Organization_type" => "App\Account"
"Organization_id" => 456
"ID" => 1
]
#original: array:13 [
"StageID" => 12
"TypeID" => 1
"OriginID" => 20
"Description" => "Interested in scanner fi6140"
"UserID" => 3
"SolutionValue" => ".00"
"MarginValue" => ".00"
"created_at" => "2010-09-16 11:19:00.000"
"updated_at" => "2015-09-01 12:32:00.000"
"_migrationID" => "4299"
"Organization_type" => "App\Account"
"Organization_id" => 456
"ID" => 1
]
#dateFormat: null
#events: []
#observables: []
#relations: array:3 [
"Organization" => null
"Projects" => Illuminate\Database\Eloquent\Collection {#3463
#items: []
}
"Tickets" => Illuminate\Database\Eloquent\Collection {#3443
#items: []
}
]
#touches: []
#forceDeleting: false
change your morphto to this base on document to prevent confusing laravel to detect column type and column id
class Image extends Model
{
protected $fillable = [
"link",
"imageable_id",
"imageable_type",
];
public function imagable()
{
return $this->morphTo(__FUNCTION__, 'imageable_type', 'imageable_id');
}
}
So, it looks like I may have discovered my problem, but I do not know why. When the owner is queried by
App\Opportunity::findOrFail(1)->Organization
it looks like Eloquent is looking for organization_type and organization_id (with lowercase) and not Organization_type and _id. However, my migration uses $table->morphs('Organization') and so the columns in the database are created with the uppercase. When I change that to lowercase in the database, my results get returned. Not sure how to change that behavior though, and it seems to have been introduced after upgrading from 5.2
Edit: there was a change introduced in 5.3 that snake cases the _type and _id that seems to be the root cause of my experience
https://github.com/laravel/framework/pull/15334
After losing two half-days exploring all the solutions found on the net, I emptied the cache and everything works ...
php artisan cache:clear

Send $variable to a view in Laravel 5

I have an $alerts variable array.
Look like this
array:3 [▼
0 => array:3 [▼
"status" => 200
"message" => "Success"
"data" => []
]
1 => array:3 [▼
"status" => 200
"message" => "Success"
"data" => []
]
2 => array:3 [▼
"status" => 404
"error_code" => 35
"message" => "invalid json - api not supported"
]
]
I want to send it from my controller to my view.
I've tried this
controller
return Redirect::to('/account/'.$id)
->with('alerts',$alerts)
Route
My route : http://localhost:8888/account/1007
View
I tried accessing like this
{!!$alerts!!}
Then, I tried accessing it like this, but I kept getting
Undefined variable: alerts
As per the Laravel documentation on redirects, when redirecting using with() it adds the data to the session, and not as a view variable. Therefore, you will need to access it like:
#foreach (session('alerts') as $alert)
<p>{{ $alert['message'] }}</p>
#endforeach
Try this:
Session::flash('alerts', $alerts);
return route('ROUTENAME', $id);
Just change ROUTENAME, in the name of the route (if defined in routes.php).
For example:
Route::get('account/{id}', ['as' => 'account.show', 'uses' => 'AccountController#show']);
In this example, ROUTENAME would be 'account.show'.
In your view you can access it by doing:
Session::get('alerts');
Info:
- http://laravel.com/docs/5.1/session#flash-data
Sometimes you may wish to store items in the session only for the next request. You may do so using the flash method.
You haven't posted the code that actually loads the view. When you return a Redirect->with(...) all you're doing is passing the variable to the next request. In your controller that serves the account/{id} route you need to return view('viewname', ['alerts' => session('alerts')])

Laravel htmlentities() expects parameter 1 to be string, array given

I'm trying to use https://github.com/skmetaly/laravel-twitch-restful-api package to get twitch integration to my website.
That's the error that i get.
ErrorException in helpers.php line 469:
htmlentities() expects parameter 1 to be string, array given (View: /var/www/rafdev.ovh/html/msvixen/resources/views/twitch.blade.php)
My controller
$code = Input::get('code');
if ($code !== null)
{
$token = TwitchApi::requestToken($code);
} else
{
$token = null;
}
$data = TwitchApi::streamsFollowed($token);
return view('twitch', ['token' => $token, 'data' => $data]);
my view
#extends('master')
#section('content')
<h1>Twitch.TV</h1>
{{ $token }}
{{ $data }}
#endsection
After using dd()
array:9 [▼
0 => array:11 [▼
"_id" => 17733016640
"game" => "World of Warcraft"
"viewers" => 15551
"created_at" => "2015-11-15T22:27:13Z"
"video_height" => 1080
"average_fps" => 60.2769481401
"delay" => 0
"is_playlist" => false
"_links" => array:1 [▶]
"preview" => array:4 [▶]
"channel" => array:22 [▶]
]
1 => array:11 [▶]
2 => array:11 [▶]
3 => array:11 [▶]
4 => array:11 [▶]
5 => array:11 [▶]
6 => array:11 [▶]
7 => array:11 [▶]
8 => array:11 [▶]
]
so it works, but when i try to display data - its back to the htmlentities() error
This is happening because $data is returned as an array.
When TwitchApi::streamsFollowed($token); is called, the Facade calls the method in Skmetaly\TwitchApi\Services\TwitchApiService.
This in turn creates an instance of Skmetaly\TwitchApi\API\Users and calls the streamsFollowed() method there.
This method makes a call to /streams/followed which returns a data set such as the example below. It's automatically converted to an array rather than JSON using the Guzzle HTTP Client's json() method.
{
"_links": {
"self": "https://api.twitch.tv/kraken/streams/followed?limit=25&offset=0",
"next": "https://api.twitch.tv/kraken/streams/followed?limit=25&offset=25"
},
"_total": 123,
"streams": [...]
}
In order to display the streams you'd need to iterate over the streams array within $data.
If you were to modify your controller slightly
return view('twitch', ['token' => $token, 'streams' => $data->streams]);
You'd then be able to iterate over the streams in your view.
#foreach($streams as $stream)
{{ $stream }}
#endforeach
Update: You'll notice that each stream is also an array. What this means is you need to choose which of the keys in each array you'd like to display. Let's assume that inside one of the streams there is a key called broadcaster which contains a string; you could modify the above as follows.
#foreach($streams as $stream)
{{ $stream['broadcaster'] }}
#endforeach
Having now read the streams example response documentation it would appear that the contents of a stream varies depending on whether or not the stream is online. NB: This is assuming the data structure is the same as you've not posted the contents of a stream in your question.
This means that offline, {{ $stream['broadcaster'] }} would work, but when online it wouldn't and you'd get the same error. What you'll likely need to do is use an #if #else block in your #foreach to determine if the stream is null before trying to echo part of the information.
You could also filter the offline streams in the controller by removing null values from data.

Categories