Is there a way to overwrite values of Http::fake([]) in Laravel during testing. I've noticed that if I set a value during a faker, eg. Http::fake(['url1.com' => Http::response('OK'), 'url2.com' => Http::response('Not Found', 404),]), if for some reason I need to change the value of say url1.com to something else such as ['message' => 'Success'], if I "update" the value by calling Http::fake(['url1.com' => Http::response(['message' => 'Success']) again at a later point, I'd expect the response when I call Http::get('url1.com') to return ['message' => 'Success'] but it instead always returns OK which was the original value set.
Same way if I later call Http::fake(['url2.com' => Http::response(['message' => 'Object found.'])]), I would expect the response when I call Http::get('url2.com') to be ['message' => 'Object found.'] but it'll always return Not found which was the original value set.
You can use achieve this by swapping the Http client
Http::fake(['https://potato.com' => Http::response('Yummy!', 200)]);
dump(Http::get('https://potato.com')->body()); // Yummy!
at some point in your test, you can reset the Http Facade using Facade Swap
Http::swap(app(\Illuminate\Http\Client\Factory::class));
now you can change the fake value to whatever you want
Http::fake(['https://potato.com' => Http::response("That's what the dcotor ordered.", 200)]);
dump(Http::get('https://potato.com')->body()); // That's what the doctor orderd.
Related
So, I have built a very detailed collection in Laravel to give me very specific and clean data in a format that works within my frontend. Now, forgetting that this will be a LOT of data, I needed to add paginate. As this is just going to be infinite scroll, I wanted to use cursorPaginate
Unfortunately, the code below does not allow it. The standard error of Method Illuminate\Support\Collection::cursorPaginate does not exist
How would I be best to refactor this to give me the data required AND give me cursorPaginate? I am completely open to changing some of it, I just do not know where best to start.
Thanks in advance!
return Activity::get()->groupBy('batch_uuid')->map(function ($batch) {
return [
'description' => $batch->first()->description,
'uuid' => $batch->first()->batch_uuid,
'event' => $batch->first()->event,
'created_at' => $batch->first()->created_at,
'subject' => $batch->first()->subject_type::find($batch->first()->subject_id),
'activities' => $batch->map(function ($activity) {
return [
'item' => $activity->causer_type::find($activity->causer_id),
];
}),
];
})->sortByDesc('created_at')->values();
```
You should watch this video from Laravel Daily. First method mentioned in this video he uses LengthAwarePaginator but you can try CursorPaginator for your purpose.
Given this on the model:
public $validate = [
'amount' => array(
'rule' => array('comparison', '>=', 0),
'message' => 'You must buy over 0 of this item!'
)
];
How can I validate param #2 of the below?
public function buy(int $item, int $amount) {
Validation seems to be built only for POST, which I'd like to opt out of here.
First things first, modifying the database with GET requests is an anti-pattern for many different reasons. Even if you assume a friendly user agent (which you never should!), browsers can behave quirky and do unexpected stuff like for example sending GET request multiple times (that is perfectly valid as GET is not ment to modify data), which they usually won't for POST/PUT/DELETE.
I would strongly suggest to change your endpoint to handle POST requests instead.
That being said, you can generally validate whatever you want, the validation mechanisms first and foremost just validate data, they don't know or care where it stems from. You can hand over whatever data you want to your model, and let it validate it:
$data = array(
'item' => $item,
'amount' => $amount,
);
$this->ModelName->set($data);
if ($this->ModelName->validates()) {
// data is valid
} else {
// data is invalid
$errors = $this->ModelName->validationErrors;
}
Moreover you can use CakePHP's validation methods completely manually too:
App::uses('Utility', 'Validation');
$isValid = Validation::comparison($amount, '>' 0);
This example of course doesn't make too much sense, given that $isValid = $amount > 0 would do the same, however it should just show that you can validate anything everywhere without models being involved.
See also
Cookbook > Models > Data Validation > Validating Data from the Controller
Cookbook > Models > Data Validation > Core Validation Rules
I have my route set as
Route::any('/{brand?}/{type?}/{city?}', 'SearchController#index')->name('search');
I want to send from my controller query strings (Form GET params)
After searching I ended up with this but it does not work properly
return redirect()->route('search', [$brand->name, $type->name, 'search_model_from' => $request->search_model_from, 'search_model_to' => $request->search_model_to]);
which returns back
localhost:8000/toyota/avalon/2018?search_model_to=2019
I want to return
localhost:8000/toyota/avalon/?search_model_from=2018&search_model_to=2019
What I am trying to achieve in general is SEO friendly search functionality
Maybe you should try to assign city as null like that :
return redirect()->route('search', [
'brand' => $brand->name, 'type' => $type->name,
'city' => '', 'search_model_from' => $request->search_model_from,
'search_model_to' => $request->search_model_to
]);
I'm not sure but this could happen because you have defined 3 optional parameters in the route and as you are sending just two of them, this might takes the next (in this case 'search_model_from') as the third parameter for url.
Maybe if you cast and set a default value to the optional parameters in your Controller, you won't have that trouble, like this:
public function index(string $brand='', string $type='', string $city='' , $other_parameters)
I send a request to a server and got a response with a body and a cookies property
{body:[row1,...,rowN], cookies:sessionData}
in the next step i want to transform the data to match my needs
in (1) there is the res object that includes the above structure, res is at (2) no longer valid of course, because it's another scope. Is there a rx-way to deal with it and get cookies later or have I implement a structure in the first mapping (1) where I include the cookies? in the streamed data?
this.sendRequest("find",params) // send request with some query parameters
.map((res:Library.Response) => JSON.parse(res.body)) // (1) get the parsed body
.map((data) => this.filterFindings(data)) // get only the good ones
.map((data) => this.addCookies(data, res.cookies) // (2) want to add the cookies from res
You can nest your call to keep the response in scope:
this.sendRequest(...).pipe(
switchMap(res => of(res).pipe(
map(res => JSON.parse(res.body)),
//...
map(data => addCookies(data, res.cookies))
)
);
Background:
I'm attempting to make good RESTful APIs in cakephp, and delegate front end work to a front end templating language Handlebars. As elicited here (http://www.dereuromark.de/2014/01/09/ajax-and-cakephp/) , using the JsonView and making an extensionful api is a good approach.
Problem:
Allowing only ajax by using $this->request->onlyAllow('ajax'); is returning method not allowed. I want to enforce this so my APIs are not directly called from the browser.
Could you (the community) validate my approach to building such APIs.
Code:
//At the controller
public function joinWithCode() {
//$this->request->onlyAllow('ajax'); //returns 405 method not allowed
//$this->request->onlyAllow('post'); //works and does not allow access from browser
$this->response->type('json');
$data = array(
'content' => 'something',
'error' => 'something else',
);
$this->set(compact('data'));
$this->set('_serialize', 'data');
}
//routes.php
Router::parseExtensions('json');
Router::connect('/Classrooms/join', array('controller' => 'classrooms', 'action' => 'joinWithCode'));
The post attempt from the postman extension: