Related
Hi all you smart individuals i'm hitting a solid wall here with someone else code that i'm trying to fix a issue.
The issue is that when this query builder has got all the results there seems to be some coming back with null values and i'm not sure how to remove them before I paginate the data, I know how to do it if it was a collection however maybe some of you might be-able to help me.
so currently the logic goes into this pagination
$return = $tld->paginate($request->get('limit'))->toArray();
$tld being the eloquent builder.
Which then gets sent into this function that was created..
$return = $this->makePagination($return);
public function makePagination($object = [], $filters = []) {
return [
'data' => [
'items' => $object['data'],
'pagination' => [
'from' => $object['from'],
'to' => $object['to'],
'total' => $object['total'],
'per_page' => $object['per_page'],
'first_page' => [
'number' => 1,
'url' => $object['first_page_url']
],
'last_page' => [
'number' => $object['last_page'],
'url' => $object['last_page_url']
],
'next_page' => [
'number' => $object['current_page'] + 1,
'url' => $object['next_page_url']
],
'prev_page' => [
'number' => $object['current_page'] - 1,
'url' => $object['prev_page_url']
]
],
'params' => $filters
]
];
}
But then i'm getting a response like this with Null values and I would like to remove them before any of this pagination happens
{
"data": {
"items": [
{
"id": 13771,
},
null,
{
"id": 4125,
},
Side note if I run $tld->get() I can see all the results and there are null values in there so if anyone can show me how to remove the null values that would be a great help <3 you all if you can help me ...
Update
Ive also tried $tld->get()->filter(); and thats also not removing the null values I still get this response
[
{
"id": 13771,
},
null,
{
"id": 789,
}
]
I think I fixed it with a little hack
$filtered = collect(array_values(array_filter($tld->get()->toArray())));
return $this->paginate($filtered, $request->get('limit') ?? 15 , $page = null, $options = []);
and then created a collection paginator
public function paginate($items, $perPage = 15, $page = null, $options = [])
{
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
#Bob Hiller Please use whereNotNull in query to remove null entries.
$tld=$query->get();
$tld->filter(function ($value) { return !is_null($value); });
$return = $tld->paginate($request->get('limit'))->toArray();
In laravel 6 app I have collection defined as :
class PermissionCollection extends ResourceCollection
{
public static $wrap = 'permissions';
public function toArray($request)
{
return $this->collection->transform(function($permission){
return [
'id' => $permission->id,
'name' => $permission->name,
'is_checked' => !empty($permission->is_checked) ? $permission->is_checked : null,
'guard_name' => $permission->guard_name,
'created_at' => $permission->created_at,
];
});
}
}
I use it in a control, like :
$permissions = $user->permissions->all();
$userPermissionLabels= Permission
::get()
->map(function ($item) use($permissions) {
$is_checked= false;
foreach( $permissions as $nextPermission ) {
if($nextPermission->permission_id === $item->id) {
$is_checked= true;
break;
}
}
return [ 'id'=> $item->id, 'name'=> $item->name, 'is_checked' => $is_checked];
})
->all();
return (new PermissionCollection($userPermissionLabels));
and I got error :
Trying to get property 'id' of non-object
Looks like the reason is that collection->map returnes array of data, not objects.
If there is a way to fix it without creating new collection(using array) ?
MODIFIED :
I logged loging in my collection,
public function toArray($request)
{
return $this->collection->transform(function($permission){
\Log::info(' PermissionCollection $permission');
\Log::info($permission);
return [
'id' => $permission->id,
'name' => $permission->name,
'is_checked' => !empty($permission->is_checked) ? $permission->is_checked : null,
'guard_name' => $permission->guard_name,
'created_at' => $permission->created_at,
];
});
}
and I see in logs:
PermissionCollection $permission
array (
'id' => 1,
'name' => 'App admin',
'is_checked' => false,
)
local.ERROR: Trying to get property 'id' of non-object
The value is valid array, not null.
I mean I have already use this collenction in other part of the app, can I use it without creating a new one...
I think you get this error because you CollectionResource need to object of the Permission model, but in your case it is trying to get id from an array, after map function. Try to extend your model instead of returning an new array
relate as below issue
Verify duplicate values on the array in Laravel5.7
I am add two fields to data base.
// database/migrations/UpdateUsersTable.php
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('staff_no' , 10);
$table->string('staff_code');
$table->unique(['staff_no', 'staff_code']);
});
}
I want to verify if multi column unique in my database or post array value is duplicate or not?
Here is my codes :
this is my Controller
UsersController
public function MassStore(MassStoreUserRequest $request)
{
$inputs = $request->get('users');
//mass store process
User::massStore($inputs);
return redirect()->route('admin.users.index');
}
and this is my POST data (post data($inputs) will send like as below) :
'users' => [
[
'name' => 'Ken Tse',
'email' => 'ken#gamil.com',
'password' => 'ken12ken34ken',
'staff_no' => '20191201CT',
'staff_code' => 'IT-1azz',
],
[
'name' => 'Tom Yeung',
'email' => 'tom#gamil.com',
'password' => 'tom2222gt',
'staff_no' => '20191201CT', // staff_no + staff_code is duplicate, so need trigger error
'staff_code' => 'IT-1azz',
],
]
MassStoreUserRequest
public function rules()
{
return [
'users' => ['required','array'],
'users.*.name' => ['required'],
'users.*.email' => ['required','unique:users','email', 'distinct'],
'users.*.password' => ['required','string','min:8'],
'users.*.staff_no' => ['required','size:10'],
'users.*.staff_code' => ['required','string']
// how to set verify duplicate values(staff_no,staff_code unique) in here?
];
}
You can use distinct validation rule. So your code will look like-
public function rules()
{
return [
'users' => ['required','array'],
'users.*.name' => ['required'],
'users.*.email' => ['required','unique:users','email', 'distinct'],
'users.*.password' => ['required','string','min:8'],
'users.*.staff_no' => ['required','size:10'],
'users.*.staff_code' => ['required','string', 'distinct']
];
}
Change
`'users.*.staff_code' => ['required','string']` line to
'users.*.staff_code' => ['required','string', Rule::exists('staff')->where(function ($query) {
//condition to check if staff_code and staff_no combination is unique
return $query->where('staff_code', $request->('your_key')['staff_code'])->where('staff_no', $request->('your_key')['staff_no']) ? false : true; // You may need to make a loop if you can not specify key
}),]
I solve this problem myself.
https://laravel.com/api/5.7/Illuminate/Foundation/Http/FormRequest.html#method_validationData
main point is overrides method validationData(),make value "staff_no_code" to validation data.
Here is my codes :
MassStoreUserRequest
public function rules()
{
$validate_func = function($attribute, $value, $fail) {
$user = User::where(DB::raw("CONCAT(staff_no,staff_code )", '=', $value))
->first();
if (!empty($user->id)) {
$fail(trans('validation.alreadyExists'));
}
};
return [
'users' => ['required','array'],
'users.*.name' => ['required'],
'users.*.email' => ['required','unique:users','email', 'distinct'],
'users.*.password' => ['required','string','min:8'],
'users.*.staff_no' => ['required','size:10'],
'users.*.staff_code' => ['required','string']
// 'distinct' check when working with arrays, the field under validation must not have any duplicate values.
// $validate_func check DB exist
'users.*.staff_no_code' => ['distinct',$validate_func]
];
}
//make value "staff_no_code" to validation data
protected function validationData()
{
$inputs = $this->input();
$datas = [];
foreach ($inputs as $input ) {
$input['staff_no_code'] = $input['staff_no'] . $input['staff_code'];
$datas[] = $input;
}
return $datas;
}
I have custom request data:
{
"data": {
"checkThisKeyForExists": [
{
"value": "Array key Validation"
}
]
}
}
And this validation rules:
$rules = [
'data' => ['required','array'],
'data.*' => ['exists:table,id']
];
How I can validate array key using Laravel?
maybe it will helpful for you
$rules = ([
'name' => 'required|string', //your field
'children.*.name' => 'required|string', //your 1st nested field
'children.*.children.*.name => 'required|string' //your 2nd nested field
]);
The right way
This isn't possible in Laravel out of the box, but you can add a new validation rule to validate array keys:
php artisan make:rule KeysIn
The rule should look roughly like the following:
class KeysIn implements Rule
{
public function __construct(protected array $values)
{
}
public function message(): string
{
return ':attribute contains invalid fields';
}
public function passes($attribute, $value): bool
{
// Swap keys with their values in our field list, so we
// get ['foo' => 0, 'bar' => 1] instead of ['foo', 'bar']
$allowedKeys = array_flip($this->values);
// Compare the value's array *keys* with the flipped fields
$unknownKeys = array_diff_key($value, $allowedKeys);
// The validation only passes if there are no unknown keys
return count($unknownKeys) === 0;
}
}
You can use this rule like so:
$rules = [
'data' => ['required','array', new KeysIn(['foo', 'bar'])],
'data.*' => ['exists:table,id']
];
The quick way
If you only need to do this once, you can do it the quick-and-dirty way, too:
$rules = [
'data' => [
'required',
'array',
fn(attribute, $value, $fail) => count(array_diff_key($value, $array_flip([
'foo',
'bar'
]))) > 0 ? $fail("{$attribute} contains invalid fields") : null
],
'data.*' => ['exists:table,id']
];
I think this is what you are looking:
$rules = [
'data.checkThisKeyForExists.value' => ['exists:table,id']
];
I've searched around and couldn't find a definitive answer for this...
I have a package DevDojo Chatter and would like to extend it using my application. I understand I'd have to override the functions so that a composer update doesn't overwrite my changes.
How do I go about doing this?
UPDATE
public function store(Request $request)
{
$request->request->add(['body_content' => strip_tags($request->body)]);
$validator = Validator::make($request->all(), [
'title' => 'required|min:5|max:255',
'body_content' => 'required|min:10',
'chatter_category_id' => 'required',
]);
Event::fire(new ChatterBeforeNewDiscussion($request, $validator));
if (function_exists('chatter_before_new_discussion')) {
chatter_before_new_discussion($request, $validator);
}
if ($validator->fails()) {
return back()->withErrors($validator)->withInput();
}
$user_id = Auth::user()->id;
if (config('chatter.security.limit_time_between_posts')) {
if ($this->notEnoughTimeBetweenDiscussion()) {
$minute_copy = (config('chatter.security.time_between_posts') == 1) ? ' minute' : ' minutes';
$chatter_alert = [
'chatter_alert_type' => 'danger',
'chatter_alert' => 'In order to prevent spam, please allow at least '.config('chatter.security.time_between_posts').$minute_copy.' in between submitting content.',
];
return redirect('/'.config('chatter.routes.home'))->with($chatter_alert)->withInput();
}
}
// *** Let's gaurantee that we always have a generic slug *** //
$slug = str_slug($request->title, '-');
$discussion_exists = Models::discussion()->where('slug', '=', $slug)->first();
$incrementer = 1;
$new_slug = $slug;
while (isset($discussion_exists->id)) {
$new_slug = $slug.'-'.$incrementer;
$discussion_exists = Models::discussion()->where('slug', '=', $new_slug)->first();
$incrementer += 1;
}
if ($slug != $new_slug) {
$slug = $new_slug;
}
$new_discussion = [
'title' => $request->title,
'chatter_category_id' => $request->chatter_category_id,
'user_id' => $user_id,
'slug' => $slug,
'color' => $request->color,
];
$category = Models::category()->find($request->chatter_category_id);
if (!isset($category->slug)) {
$category = Models::category()->first();
}
$discussion = Models::discussion()->create($new_discussion);
$new_post = [
'chatter_discussion_id' => $discussion->id,
'user_id' => $user_id,
'body' => $request->body,
];
if (config('chatter.editor') == 'simplemde'):
$new_post['markdown'] = 1;
endif;
// add the user to automatically be notified when new posts are submitted
$discussion->users()->attach($user_id);
$post = Models::post()->create($new_post);
if ($post->id) {
Event::fire(new ChatterAfterNewDiscussion($request));
if (function_exists('chatter_after_new_discussion')) {
chatter_after_new_discussion($request);
}
if($discussion->status === 1) {
$chatter_alert = [
'chatter_alert_type' => 'success',
'chatter_alert' => 'Successfully created a new '.config('chatter.titles.discussion').'.',
];
return redirect('/'.config('chatter.routes.home').'/'.config('chatter.routes.discussion').'/'.$category->slug.'/'.$slug)->with($chatter_alert);
} else {
$chatter_alert = [
'chatter_alert_type' => 'info',
'chatter_alert' => 'You post has been submitted for approval.',
];
return redirect()->back()->with($chatter_alert);
}
} else {
$chatter_alert = [
'chatter_alert_type' => 'danger',
'chatter_alert' => 'Whoops :( There seems to be a problem creating your '.config('chatter.titles.discussion').'.',
];
return redirect('/'.config('chatter.routes.home').'/'.config('chatter.routes.discussion').'/'.$category->slug.'/'.$slug)->with($chatter_alert);
}
}
There's a store function within the vendor package that i'd like to modify/override. I want to be able to modify some of the function or perhaps part of it if needed. Please someone point me in the right direction.
If you mean modify class implementation in your application you can change the way class is resolved:
app()->bind(PackageClass:class, YourCustomClass::class);
and now you can create this custom class like so:
class YourCustomClass extends PackageClass
{
public function packageClassYouWantToChange()
{
// here you can modify behavior
}
}
I would advise you to read more about binding.
Of course a lot depends on how class is created, if it is created using new operator you might need to change multiple classes but if it's injected it should be enough to change this single class.