I need a policy to create trees in a tournament.
So, In my treeController#store, I have:
if (Auth::user()->cannot('generateTree', new Tree(),$tournament)) {
throw new AuthorizationException();
}
And my corresponding policy is :
TreePolicy.php:
public function generateTree(Tree $tree, Tournament $tournament )
{
dd($tournament);
return ($tournament->user_id == Auth::user()->id);
}
And I get a :
Type error: Argument 1 passed to App\Policies\TreePolicy::generateTree() must be an instance of App\Tree, instance of App\User given, called in /laravel/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php on line 382
What am I missing???
EDIT : In response to #andonovn,
I tried it with :
public function store(User $user, Tree $tree, Tournament $tournament)
{
dd($tournament);
}
And
if (Auth::user()->cannot('generateTree', Tree::class,$tournament)) {
throw new AuthorizationException();
}
--> it gives me a 403
Or
$this->authorize('store', $tournament,Tree::class);
--> it doesn't enter the dd();
The only way I found it to work is putting the Policy content in the controller which is not so nice:
if ($tournament->user_id != Auth::user()->id){
throw new AuthorizationException();
}
EDIT 2 : I solve it with that:
In controller :
if (Auth::user()->cannot('store', [Tree::class,$tournament])) {
throw new AuthorizationException();
}
In policy
public function store(User $user, Tournament $tournament)
{
return ($tournament->user_id == $user->id);
}
I believe the first argument of generateTree() must be the authenticated user. Try changing it to public function generateTree(User $user, Tree $tree, Tournament $tournament )
Edit:
Also change the cannot method to Auth::user()->cannot('generateTree', [Tree::class, $tournament]) (combine the 2nd and 3rd parameters in array, seems like Laravel is always expecting 2 arguments where the 2nd one can be array)
Related
I'm writing some tests for my model when it was created/updated/deleted. When I test it manually, it worked. But when I test in test file, asserting a event dispatch always fail.
This is my test function:
public function test_booted_method_ran()
{
$model = AcCard::factory()->create();
$this->expectsEvents('eloquent.created: \App\Models\AcCard');
}
This test case always fails. I've tried to inspect expectsEvents and added dd() to check event list:
public function expectsEvents($events)
{
$events = is_array($events) ? $events : func_get_args();
$this->withoutEvents();
$this->beforeApplicationDestroyed(function () use ($events) {
$fired = $this->getFiredEvents($events);
dd($fired); // Added this code line
$this->assertEmpty(
$eventsNotFired = array_diff($events, $fired),
'These expected events were not fired: ['.implode(', ', $eventsNotFired).']'
);
});
return $this;
}
And result is an empty array.
What I tried
I tried to add this code lines above model creating
AcCard::flushEventListeners();
AcCard::boot();
AcCard::booted();
But it doesn't work.
Good afternoon I am adding data in via POST method in PLATFORM API can I make this method work like adding or updating data.
So that when the data is already there for the object, it will simply update the pinOrder field.
My input:
{
"chat": "/api/chats/01FVKRYXMMTHKJ2EZB02F4FZ3Z",
"pinOrder": 3
}
Insert or update (upsert) is not available in Api Platform. However, you can achieve this behavior with a custom (or decorated) Data Persister.
https://api-platform.com/docs/core/data-persisters/
In the persist method of the data persister you could manually check if an item matching your criteria does already exist and, if yes, update this one instead of persisting a new one.
You can use PRE_WRITE event. For exemple, an order item quantity.
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => [
'updateExistingItemQuantity', EventPriorities::PRE_WRITE,
],
];
}
public function updateExistingItemQuantity(
ViewEvent $event
): void {
$item = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$item instanceof MyItemObject || Request::METHOD_POST !== $method) {
return;
}
// find duplicateItem
if ($duplicateItem) {
$duplicateItem->setQuantity("UPDATED QUANTITY");
// save $duplicateItem
$event->setControllerResult($duplicateItem);
}
}
I am trying to open different views based upon a request value. For example, if the value of $request is set to one, then view one should open. If the $request value is two, then view two should open.
My code is working fine, but right now, I will have to repeat code for each view. How can I do it without repeating the if condition?
Scenario
public function printreports(Request $request)
{
$reports = $request->get('reports');
if ($reports === 1) {
return view('teachers.report1', compact('anything'));
}
if ($reports === 2) {
return view('teachers.report2', compact('anything'));
}
}
For large amount of files with similar name pattern:
$viewName = sprintf('teachers.report%d', $request->get('reports', 1))
if (!\View::exists($viewName)) {
___ throw an error or return default view ____
}
return view($viewName, compact('anything'));
I have a intermediary table in which I want to save sbj_type_id and difficulty_level_id so I have setup this:
$difficulty_level = DifficultyLevel::find(5);
if ($difficulty_level->sbj_types()->sync($request->hard, false)) {
dd('ok');
}
else {
dd('not ok');
}
Here is my DifficultyLevel.php:
public function sbj_types() {
return $this->belongsToMany('App\SbjType');
}
and here is my SbjType.php:
public function difficulty_levels() {
return $this->hasMany('App\DifficultyLevel');
}
In the above code I have dd('ok') it's returning ok but the database table is empty.
Try to change
return $this->hasMany('App\DifficultyLevel');
to
return $this->belongsToMany('App\DifficultyLevel');
The sync() method takes an array with the id's of the records you want to sync as argument to which you can optionally add intermediate table values. While sync($request->hard, false) doesn't seem to throw an exception in your case, I don't see how this would work.
Try for example:
$difficulty_level->sbj_types()->sync([1,2,3]);
where 1,2,3 are the id's of the sbj_types.
You can read more about syncing here.
I have a recursive relationship (sections and sub sections)
defined as this in ReportSection model:
function sub_sections() {
return $this->hasMany('App\ReportSection', 'parent_id');
}
and I'm trying to iterate through it like so:
$section = Section::find($id);
\DB::beginTransaction();
try {
foreach(ReportForm::unlockedForm($section->form_id)->get() as $report) {
foreach($report->sections()->where('section_id', $section->id)->get() as $reportSections) {
\Log::info($reportSections);
foreach($reportSections as $rSection) {
\Log::info($rSection);
foreach($rSection->sub_sections as $subSection) {
The line \Log::info($reportSections); gives {"id":3,"report_form_id":1,"name_en":"DDD","name_fr":"DDD","created_at":"2016-11-29 07:47:24","updated_at":"2016-11-29 07:47:32","section_id":118,"parent_id":1,"order":99,"hidden":0} as expected
but the iterating through it somehow gives a boolean \Log::info($rSection); gives 1
The last line foreach($rSection->sub_sections as $subSection) { gives the error 'Trying to get property of non-object'
Why would iteration through a relationship collection give a boolean? What am I doing wrong?
Edit: changed sub_sections() to sub_sections but the error is still present
You should call the attribute name not the method:
foreach($rSection->sub_sections as $subSection)
{}
Ok after taking a break I was able to figure out that the problem was I was iterating through the same collection twice.
Instead of
foreach(ReportForm::unlockedForm($section->form_id)->get() as $report) {
foreach($report->sections()->where('section_id', $section->id)->get() as $reportSections) {
foreach($reportSections as $rSection) {
It should have been
foreach(ReportForm::unlockedForm($section->form_id)->get() as $report) {
foreach($report->sections()->where('section_id', $section->id)->get() as $rSection) {