Does laravel Event::queue() works in local environment? - php

Does Event::queue('event.name') works in local environment?
Provided that it works locally, as I understand we still have to flush the event using Event::flush('event.name'). But I am not able to make it work. The usual Event::fire('event.name') works just fine.
This is my controller store method
public function store(){
$input = Input::all();
if ($this->validator->isValidForCreation($input)){
$owner = $this->admin->createOwner($input);
Event::queue('event.name', [$input]);
return Redirect::route('admin.index')->with('success', 'Owner successfully created.');
}
return Redirect::back()->withInput()->withErrors($this->validator->getErrors());
}
Where should I use the Event::flush('event.name') in my code? I tried flushing it in a route closure (just for testing) after storing the user, but it didn't trigger the event and the code inside the event handler wasn't executed. Should I flush it inside the store function before redirecting to other route?

Related

Is there a way to act as a user inside of Laravel without hitting the database?

I'm writing unit tests for an API using PHPUnit and Laravel. Most functions I'm testing require that the user is authenticated before the function can be ran. The user data is stored in one table, and their permissions are stored inside of another table. I can fake the user object inside of Laravel, but I need to be able to also pull the corresponding permissions from the other table without having to hit the database like the dingo router currently is doing.
Currently running Laravel 5.8 and PHPUnit 8.1.5. I currently have the users object that I generated from a Laravel factory saved to a text file. I am able to pass that to a function called "actingAsApi" (found on Github, code below) and that allows me to authenticate as that user. However, the function is still going out and getting all permissions for that user from the database. I'm trying to mock or fake the permissions object it is pulling somewhere so that it doesn't need to hit the database at all. I also tried using the built in Passport functions for Passport::actingAs, and those did not work either as they were still hitting the DB (and not really working anyways).
actingAsApi (inside of TestCase.php)
protected function actingAsApi($user)
{
// mock service middleware
$auth = Mockery::mock('Dingo\Api\Http\Middleware\Auth[handle]',
[
Mockery::mock('Dingo\Api\Routing\Router'),
Mockery::mock('Dingo\Api\Auth\Auth'),
]);
$auth->shouldReceive('handle')
->andReturnUsing(function ($request, \Closure $next) {
return $next($request);
});
$this->app->instance('Dingo\Api\Http\Middleware\Auth', $auth);
$auth = Mockery::mock('Dingo\Api\Auth\Auth[user]',
[
app('Dingo\Api\Routing\Router'),
app('Illuminate\Container\Container'),
[],
]);
$auth->shouldReceive('user')
->andReturnUsing(function () use ($user) {
return $user;
});
$this->app->instance('Dingo\Api\Auth\Auth', $auth);
return $this;
}
Test inside of my Test file
public function testActAs() {
$user = 'tests/users/user1.txt';
$this->actingAsApi($user);
$request = new Request;
$t = new TestController($request);
$test = $t->index($request);
}
I expect the actingAsApi function to allow me to also pass in the mock permissions data that corresponds to my mock user object data from the file, but instead it is hitting the database to pull from the permissions table.
EDIT:
So i've been playing around with doing mock objects, and i figured out how to mock the original controller here:
$controlMock = Mockery::mock('App\Http\Controllers\Controller', [$request])->makePartial();
$controlMock->shouldReceive('userHasPermission')
->with('API_ACCESS')
->andReturn(true);
$this->app->instance('App\Http\Controllers\Controller', $controlMock);
but now I can't figure out how to get my call from the other controllers to hit the mocked controller and not a real one. Here is my code for hitting an example controller:
$info = $this->app->make('App\API\Controllers\InfoController');
print_r($info->getInfo('12345'));
How can i make the second block of code hit the mocked controller and not standup a real one like it does in its constructor method?
Finally came on an answer, and it is now fixed. Here's how I did it for those wondering:
$request = new Request;
$controlMock = m::mock('App\API\Controllers\InfoController', [$request])->makePartial();
$controlMock->shouldReceive('userHasPermission')
->with('API_ACCESS')
->andReturn(true);
print_r($controlMock->getInfo('12345'));
Basically, I was trying to Mock the original API controller, and then catch all of the calls thrown at it. Instead, I should've been mocking the controller I'm testing, in this case the InfoController. I can then catch the call 'userHasPermission', which should reach out to the Controller, but I am automatically returning true. This eliminates the need for hitting the database to receive permissions and other info. More information on how I solved it using Mockery can be found here: http://docs.mockery.io/en/latest/cookbook/big_parent_class.html. As you can see, this is referred to as a 'Big Parent Class'. Good luck!

Is AWS MySQL caching data? Laravel 5

I'm making a simple API endpoint that returns an access code for an event.
If the event does not have access code, then it gets assigned one and saved in the database. Then, it checks if it's currently public or private. If private, return access code, if public, return empty string.
This is the endpoint controller:
public function getAc($eventId) {
// Pull event
$event = $this->eventService->api->getEventForce($eventId);
// If no access code for the event, generate one and update event record accordingly
if ($event->access_code == null) {
$access_code = $this->generateAccessCode();
DB::update('update events set access_code = ? where id = ?', [$access_code, $eventId]);
// Load updated event from DB.
$event = $this->eventService->api->getEventForce($eventId);
}
// Is the event currently private? return access code
if ($event->privacy=='private') {
return $event->access_code; // HERE: value comes back from the API but on MySQL Workbench it's still null.
}
// Is it public ? return empty string.
else {
return '';
}
}
My problem is that even though everything works as expected. When access_code is created it does come back from the api.
However when I check the record on MySQL Workbench (that connects to AWS Instance) it's still null! event though I pulled it from the database as a non-null value using the API endpoint.
Little confused with your code. From debugging I'd suggest checking your API for this issue. From what I can see you're doing this:
Ask API for event with ID 1
Check if event has a parameter
If no parameter, update using local DB
So I'm left asking, if the problem is with the API, why are you updating using the local instance of the DB? Furthermore could this be resolved using events? (I'm going to call your class something other than event so not to get confusing)
For instance:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Party extends Model {
public $table = 'parties';
public $fillable = [];
public static function boot() {
parent::boot();
static::creating(function($party) {
//create some fancy access code
$access_code = 'heyyyy';
//Check not manually set
if (!isset($party->attributes['access_code']) || is_null($party->attributes['access_code'])) {
$party->access_code = $access_code;
}
}
}
}
Now every time you create an event or 'party' using Party::create(); or $party = new Party; $party->save(); the creating event will pick up the save and also assign the access_code if you haven't set it manually like $party->access_code = 'you can\'t come';.
That's my thought anyway. However in your immediate case I think you need to ask yourself some more questions like:
Does the DB object from the instance of Laravel I'm using have access to the database to save said object?
Do I need to call the API in order to update my entity/model?
If the instance of Laravel I'm using from the \DB::update call have the same credentials as my API?
If this is a command or job, do my code changes affect it? Do I need to restart a supervisor/cron command to re-instance my code?
Who wrote this API? Is it reliable enough to use? And does it have documentation?

How to pass data from cron to Controller laravel php

How how can i transfer data from cron(sheduler) to Controller which make json in laravel
this is my route:
Route::get("/data",'DataController#Data');
and this is my function Data in controller:
public function Data(){
return response()->json(['data'-> User::all()],200);
}
And how can i make cron which will make query to mysql for User, save in variable and pass to my controller?
Update:
I try to use Cache:
in my command(which will be run by crontab)
public function handle()
{
$data = User::All();
Log::info('Data: ' . $data);
Cache::put('data',$data);
Log::info('Done!');
Log::info('Data: ' . Cache::get('data'));
}
problem is fact that First info() printf me good data but when i try to get from cache i got nothink, i try to storage data to File
CACHE_DRIVER=file (from .env)
i run page on windows, and storage folder has permissions to create files
What you are trying to do makes no sense at all. The scheduler is being run through a CLI interface, which has nothing to do with the Controllers.
I would highly recommend you to not mix the Scheduler and Controllers, but instead create Helper-classes for methods, that you might have to reuse.
If you want to run the Controller anyway, you can run it with something like:
(new App\Http\Controllers\DataController())->Data()
Disclaimer: I'm not completely sure on how the response and request classes behaves, when you call a Controller outside of the normal Request-lifecycle.

Laravel Auth User add custom data

We are currently working on an application with a Google Login with Laravel with Socialite. We have a Auth user who gets a permission number ex. 264. We have made a function which returns an array with all binary numbers this permission number is made off.
Because calling this function every single time a page loads may be kinda heavy, we thought of adding this once when the Auth::user() is created. We thought of adding a custom constructor in the Model, but we can't make it work.
function __construct($attributes = array()) {
parent::__construct($attributes);
$this->permissionsArray = PermissionHelper::permissionConverter($this->permissions);
}
But we can't get it to work, $this doesn't have values when calling this function.
TLDR;
Directly after making the Auth user I want to call the permissionConverter function and save the data to the user so we can use it more often. Any suggestions on how to do this?
EDIT: I checked all answers out today, succeeded with one of them, but I assumed Laravel put the authenticated user in the SESSION or something. I found out it doesn't and it gets all the data from the database every request. We couldn't do what we requested for unfortunately. So I just had to refactor the script and make it as efficient as possible (although it became a bit less readable for less experienced programmers).
Thanks for the help :D
Maybe you can use this solution ? https://stackoverflow.com/a/25949698/7065748
Create a on the User Eloquent model a boot method with
class User extends BaseModel {
public static function boot() {
static::creating(function($model) {
$model->permissionsArray = PermissionHelper::permissionConverter($model->permissions);
});
// do the same for update (updating) if necessary
}
}
Can't you just use this method ?
If new user:
$user = new User(); // or User:create(['...']) directly
$user->name = 'toto';
// and all other data
or
$user = Auth::user();
then
$user->permissionsArray = PermissionHelper::permissionConverter($user->permissions);
$user->save();

Why do I have to reload Auth::user() when doing integration testing

This is a follow up of How to wait for a page reload in Laravel integration testing
What I am doing is to edit a user's profile and then redisplay the view.
My profile action: (UserController)
public function profile(){
return view('user/profile');
}
The view contains code like
{{ Auth::user()->firstname }}
now during my test, the old (unchanged) user data is displayed.
The test:
protected function editUserProfile()
{
$this->visit('/user/profile');
$firstName = $this->faker->firstname;
$lastname = $this->faker->lastname;
$this->within('#userEditForm', function() use ($firstName, $lastname) {
$this->type($firstName, 'firstname');
$this->type($lastname, 'surname');
$this->press('Save')
->seePageIs('/user/profile')
->see($firstName) # here the test fails
->see($lastname);
});
}
When I change the UserController like this:
public function profile(){
Auth::setUser(Auth::user()->fresh());
return view('user/profile');
}
everything works fine.
Now I want to understand, why that is like this.
Why does the integration test behave differently to the browser in that case? Is there a better way to align that behavior so the tests do only fail if there is a "real problem"? Or is my code just bad?
You're probably using update (int $uid) for the request?
The most likely explanation is that Laravel only uses a single application instance during the test. It's taking the input you give it, building a request object, and then sending it to the controller method. From here it can render the view and check that it contains your text.
In the authentication implementation once you call Auth::user() it doest one of two things:
If no user is loaded it attempts to retrieve it from storage.
If a user is already loaded it returns it.
Your update method (I'm guessing) is retrieving a new instance of the user from storage and updating it, not the cached one.
For example:
\Auth::loginUsingId(1234);
\Auth::user()->email; // 'user#example.com'
$user = \App\User::find(1234);
$user->email; // 'user#example.com';
$user->update(['email' => 'user2#example.com']);
$user->email; // 'user2#example.com'
\Auth::user()->email; // 'user#example.com'

Categories