Is it possible to call method pop with callback (laravel collections)? - laravel

I have a collection that contains answers from guzzle HTTP client. The answers can be 404, 200 or 500.
I would like to pop objects form the collection that contains only 200 and 404 statuses and leave with the statuses 500. So, I would like something like:
$done = $res->pop(function ($item, $index) {
$statusCode = $item->getStatusCode();
return $statusCode === 404 || $statusCode === 200;
});
But it's impossible( Because the pop methods don't take callback. Any ideas how to make this elegantly?

I think filter would be a better solution if you still want to keep the responses with status 500 in the original array (documentation here):
$done = $res->filter(function ($item) {
return $item->getStatusCode() === 500;
});
// $done will contain only responses with 500 status code
// $res will not be touched
Otherwise you could use partition to actually split the data in two groups keeping the original array unaltered (documentation here):
list($status500, $status200_404) = $collection->partition(function ($item) {
return $item->getStatusCode() === 500;
});
// $status500 will contain only responses with 500 status code
// $status200_404 will contain only responses with 200 and 404 status code
// $res will not be touched

Related

How can I check if laravel count result is null or not

I have this code :
$status = htransaksi::find(auth()->user()->id)->where('Status','Open')->count();
if ($status != 0)
{
$idhtrans = htransaksi::select('id')->where('User_ID', auth()->user()->id)->where('Status', 'Open')->first();
$shopcart = DB::table('detiltransaksis')->join('Barangs', 'Barangs.id', '=', 'detiltransaksis.barang_Id')->where('htrans_Id', $idhtrans->id)->get();
return view('home')->with('barang', $barang)->with('jenis', $jenis)->with('shopcount',$shopcart);
}
else
{
return view('home')->with('barang', $barang)->with('jenis', $jenis);
}
This code checks, is there any item in your shopping cart? If there is an item then return that shopping cart and when there is no item it shows some error that say
Call to a member function where() on null
Anyone knows how to fix this?
I'm new to Laravel and sorry if this is such a newbie question.
Edit :
The error point to
$status = htransaksi::find(auth()->user()->id)->where('Status', 'Open')->count();
The issue is in this line:
$status = htransaksi::find(auth()->user()->id)->where('Status','Open')->count();
if htransaksi::find(auth()->user()->id) returns null then your code will call where on null hence the error:
Call to a member function where() on null
You can simply add a condition and do it separate:
$entryFound = htransaksi::find(auth()->user()->id);
if (empty($entryFound)) {
//this means its returning null then handle that condition here
}
//if entry is found then leave the code as is:
$status = $entryFound->where('Status','Open')->count();
if(Auth::check()) {
$status = htransaksi::where('user_id', Auth::id())->where('Status','Open')->count();
... your "normal logic"
} else {
$error_handling_user_not_logged_in();
}
The reason why I added the Auth::check() check is to make sure that the user is really logged in, feed free to remove it if you already know this because of middleware/request validation.
You code did not work because htransaksi::find(auth()->user()->id) returns a finished data set - if this dataset is empty PHP's where() function failed because you tried to search something which is NULL
As I see htransaksi::find(auth()->user()->id)->where('Status','Open')->count(); is incorrect. You cannot use where() function after find().
Let's try:
$status = htransaksi::where('User_ID',auth()->user()->id)->where('Status','Open')->count();

How can I set a response using a var?

In the laravel docs it has:
return response($content);
What format is $content?
I want to return it via a var like so:
$res = [null, 204];
return response($res);
But the above fails, just returns a 200.
How can I set a response using a var?
response method like this. response($contents, $statusCode) It's a method of instance Response Object. as you can see that method is getting two parameters. one is contents that you are trying to return to client side. it depending what Content-Type is set in header.
so you can try like this.
$contents = "something whatever";
$statusCode = 204;
return response($contents, $statusCode);
$content can be various things - null, a string, an array.
Status codes are set via a second parameter, not an array element. Passing it an array results in a JSON response, so you're creating a 200 status JSON response of [null,204] with your code.
You fundamentally need to do:
return response(null, 204);
What you can potentially do is generate a response as a variable:
$res = response(null, 204);
and then return $res; elsewhere.

The HTTP status code "0" is not valid

The HTTP status code "0" is not valid.
public function filter()
{
$institute = (new Institute)->newQuery();
$institute->with(['locations','courses' => function ($query) use ($request){
$query->with('trainers');
}]);
}
$data = $institute->get();
if(count($data) > 0)
{
return response()->json($data);
}
else
{
return response()->json(404,'No Data found');
}
}
Actually, I want to display error 404 message if there is no data,
my problem is when I try to check whether data is there or not I'm getting an error called InvalidArgumentException.Can anyone help on this please.
return response()->json(404,'No Data found');
The first argument of json should be data, then goes a status code. In this case the status code gets 0 value. Simply do it as follows:
return response()->json('No Data found', 404);
This error is thrown when you try and use 0 as your response exception code. In my case my App/Exceptions/Handler.php file was modified and I returned 0 as my HTTP code after formatting which is not allowed. Just make sure you are returning a valid HTTP code from your Exception handler at all times.
Another case can cause the same problem when you have a difference between code and database schema.
In laravel, I had this issue when trying to do an insert on a table where I had the field type incorrect. In my specific case, I was trying to insert a varchar into an integer field in my DB Schema.
Changed the Schema to varchar and I was all set!

Can I optimize this script updating ~6000 rows with a lot of data

I have ~5-6k $items that I need to update in the database. Each item needs a HTTP request to get the data from the page. In the HTTP GET request I get arrays that are massive (~500-2500) and I need to insert only those lines that are not in the database. It seems to take a lot of time with my current script (1 item every 2-4 minutes) on my vagrant scotch box.
Simplified example:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use GuzzleHttp\Client;
use App\Item;
use App\ItemHistory;
use Carbon\Carbon;
use DB;
class UpdateController extends Controller
{
public function getStart() {
// Don't cancel the script
ignore_user_abort(true);
set_time_limit(0);
$client = new Client();
$items = Item::where('updated_at', '<=', Carbon::now()->subDay())->get();
foreach($items as $item) {
$response = $client->request('GET', 'API_URL');
// get the body
$body = $response->getBody()->getContents();
$hugeArray = $body['history']; // can be from 100 to 5 000 lines and I use regex to get the "history" array from the body
$arrayCollection = collect($hugeArray);
foreach($arrayCollection->take(-100) as $row) { // I take the last 100 since each row = 1 hour, so I get items in the last 100 hours
$date = new \DateTime($row['created_at']);
if( ! ItemHistory::whereItemId($item->id)->whereSoldAt($date)->count()) { // Checking if it already exists
// I insert the new rows..
$history = new ItemHistory;
// ....
$history->save();
}
}
}
}
}
I actually crawl the data and use regex to find the arrays in the body response.
Am I doing something wrong? It takes quite a while until it moves onto the next $item.
I can provide a simplified answer - synchronous execution, object hydration, and bulk database querys.
Consider the following example:
$requests = function () use ($items) {
foreach ($items as $item) {
yield new GuzzleHttp\Psr7\Request($method, $uri);
}
};
$client = new GuzzleHttp\Client();
foreach ($requests() as $request) {
$client->sendAsync($request)
->then(
function(Psr7\Http\Message\ResponseInterface) {
// process the response into array;
return $arrayFromResponse;
})
->then(
function ($unfilteredArray) {
// filter the array as necessary
return $filteredArray;
})
->then(
function($filteredArray) {
// create the array for bulk insert / update
return $sqlArray;
})
->then(
function($sqlArray) {
// perform bulk db operations.
}
);
}
Synchronous Http queries - The above example highlight's some of Guzzle's asynchronous capabilities, while breaking out the processing steps. The code you linked above is synchronous. Perform a request, wait for a response, process response, rince & repeat. Asynchronous Http requests will ensure that data is being downloaded while other information is being processed. I should note that your results will vary, and depending on your particular use case, may see increased resource usage.
Object Hydration - aka what your ORM is doing when you perform a query and it returns an object instance (rather than an array), is time consuming and memory intensive. #orcamius (one of Doctrine's developers) wrote a fairly technical article on the subject. While this is not Eloquent specific, it does provide insight into operations that go on behind the scenes for all ORM's. The code snippet performs many of these (reference $itemHistory, $history, Item::where).
Bulk Database Operations - a widely known fact is that database operations are slow. This time is further increased when coupled with object hydration. It is much better to perform a single insert with 1000x records vs 1000x inserts. To do this, code will have to be modified from using the ORM to using the DB tables directly. Bulk inserts can be performed by DB::table('itemHistory')->insert($arrayOfValues) as seen in the docs
Update: Although not shown then() has a method signature of then(callable $fulfilled, callable $onError). If something goes awry with the request you could do something like
// promise returned from a request
$p->then(
function (Psr\Http\Message\ResponseInterface $response) use ($p)
if ($response->getResponseCode() >= 400) {
$p->cancel();
}
//perform processing
return $someArray;
},
function (RequestException $e) {
echo $e->getMessage() . "\n";
echo $e->getRequest()->getMethod();
})
->then(
function($someArray) use ($p) {
// filter or other processing
});
Additional information on Guzzle's Promises can be found within the Github Repo

CakePHP beforeFind

I am using cake's callback method, beforeFind which adds some conditions to each query dynamically. All went well at first and thought it will minimize development time.. until I made an ajax request which performs a find on some models.. It doesn't seem to work when this happens..
Basically I am adding some query conditions
public function beforeFind($query){
if(empty($this->aff)){
throw new Exception("Username cannot be null.");
}
//set active flag
$query["conditions"]["MsGa.active_flag"] = "active";
if(empty($query["conditions"]["OR"])){
$query["conditions"]["OR"] = array();
}
$query["conditions"]["OR"][] = array("FIND_IN_SET('".$this->aff."', MsGa.aff)");
$query["conditions"]["OR"][] = array("MsGa.aff" => "");
if(!empty($this->type)){
$query["conditions"]["MsGa.type"] = $this->type;
}
return $query;
}
Would it normally work in an ajax request, when a find is done on a model (ofcourse.. )? If not how so? Is it possible to explicitly invoke it?
[EDIT]
Here's the function that is called when the ajax request is initiated :
public function getResultsCount($data){
return $this->find("count", array(
"conditions" => $this->_setupConditions($data)
));
}
And
_setupConditions returns an array of query conditions...
The function which returns the result set :
public function getResults($data){
return $this->find("all", array(
"conditions" => $this->_setupConditions($data)
));
}
Whenever I initiate the ajax request and the query is executed, a certain count is returned. And when the actual result set is returned, there are less records then actually displayed by the count function. . So my thinking was that it might be that the beforeFind() is not being executed, since if I comment out this callback, the count and the number of records on the result set are equal. I am a bit baffled

Resources