How to reuse the same function in multiple policy files - laravel

This function will be used by many policies. How to avoid writing this inside each policy file?
public function checkRoleAndPermission($name)
{
$content = 'Location';
$permission = Permission::where([['content', $content], ['name', $name]])->first();
if(empty($permission))
return false;
return auth()->user()->hasRole($permission->roles);
}

The best practice would be to create an BasePolicy and extend all others from it
Example
class BasePolicy
{
public function checkRoleAndPermission($name)
{
$content = 'Location';
$permission = Permission::where([['content', $content], ['name', $name]])->first();
if(empty($permission))
return false;
return auth()->user()->hasRole($permission->roles);
}
}
class PostPolicy extends BasePolicy
{
public function update(User $user, Post $post, $rolePermission)
{
$this->checkRoleAndPermission($rolePermission);
...
}
}
```

Create a class with the above function 'checkRoleAndPermission'.
Wherever need, extend the class and reuse the function like below.
Class A:
public class A{
public function checkRoleAndPermission($name)
{
$content = 'Location';
$permission = Permission::where([['content', $content], ['name', $name]])->first();
if(empty($permission)) return false;
return auth()->user()->hasRole($permission->roles);
}
}
Class B:
use A;
public class B extends A{
$this->checkRoleAndPermission('name'); // it will call class A's checkRoleAndPermission() function
}

Related

How to use Laravel Cache::remember with a callback function

I would like to reference a private function as the third parameter to the Cache::remember function.
Instead of this (try{}catch() was removed for a cleaner code):
class ApiController extends Controller
{
public function index(){
$data = Cache::remember('dataKey', 60, function () {
return Model::multipleMethodsHere()->get();
});
return response()->json($data,200);
}
}
I'd like to do this:
class ApiController extends Controller
{
public function index(){
$data = Cache::remember('dataKey', 60, $this->getIndex());
return response()->json($data,200);
}
private function getIndex(){
return Model::....->get();
}
}
I got this error if I try to reference a private function.
Argument 3 passed to Illuminate\\Cache\\Repository::remember() must be an instance of Closure, instance of Illuminate\\Database\\Eloquent\\Collection given
Is it possible ? If yes, how should I do ?
Based on comments in the discussion to the OP, re-strategize the Cache:remember to be a part of the getIndex function like:
class ApiController extends Controller
{
public function index(){
$data = $this->getIndex();
return response()->json($data,200);
}
private function getIndex(string $dataKey = 'dataKey', int $time = 60){
return Cache::remember($dataKey, $time, function () {
return Model::....->get();
})
}
}

How to get model relations in Laravel?

I would like to get the model relations, in array;
My model look like:
class User extends Model
{
public function profile() {
return $this->haOne(Profile::class);
}
public function settings() {
return $this->morphOne(Settings::class, 'settingsable');
}
public function addresses() {
return $this->hasMany(Addresses::class);
}
}
And my code:
$user = User::with(['profile', 'settings', 'addresses'])->find(1);
$user->getRelations(); // return ['profile', 'settings', 'addresses'];
If I have more then 10 relation, I don't want to list all.
I would like to get like this:
$relations = ['profile', 'settings', 'addresses'];
Is this posible?
You could try adding a scope to the model, and so, you have to only write them once.
class User extends Model
{
public function profile() {
return $this->haOne(Profile::class);
}
public function settings() {
return $this->morphOne(Settings::class, 'settingsable');
}
public function addresses() {
return $this->hasMany(Addresses::class);
}
public function scopeWithRelations(Builder $query){
return $query->with([...]);
}
}
$users = User::withRelations()->get();
This way you only have to write them once there, and everywhere in the code you'll use the scope.
Not exactly 100% what you're asking, but this could be a solution.

laravel Notification Undefined index: user_id

I going to do massage notification, I already make the notifications steps,
but gives me this error
when I do dd($notifiable); I found all data
Undefined index: user_id OR
Undefined index: name
public function store(Request $request)
{
$chating=new chats();
$chating->chat = $request->input('chat');
$chating->user_id = Auth::id();
$chating->employee_id = $request->input('employeeid');
$chating->save();
$user_id=$request->input('employeeid');
auth()->user()->notify(new SendMassages($user_id));
return redirect()->back();
}
database notifications table coulmn data {"user_id":5,"name":"Ibrahim"}
Model
protected $user_id;
protected $name;
public function __construct($user_id)
{
$this->user_id = $user_id;
}
public function via($notifiable)
{
return ['database'];
}
public function toDatabase($notifiable)
{
return [
'user_id' => $this->user_id,
'user'=>$notifiable
];
}
View:
{{ $notification->data['name'] }}
Model:
class SendMassages extends Notification
{
use Queueable;
public $user;
public $user_id;
public function __construct($user_id)
{
$this->user_id = $user_id;
}
public function via($notifiable)
{
return ['database'];
}
public function toDatabase($notifiable)
{
// dd($notifiable);
return [
'user_id' => $this->user_id,
'user'=>$notifiable
];
}
}
It seems that you have problem with encapsulation in your code. First you have to make the property of your model into public if you want the quick and not-safe way but if you want the OOP way, You must write setters to do that logic for you.
First and not-safe approach :
class YourModel {
public $user_id;
.
.
.
}
The OOP way:
Class {
public function setUserId(int $userId)
{
$this->user_id = $userId;
}
.
.
.
}
if you are willing to get the exact answer please copy your controllerclass and model in here.

Magento2: Calling a protected class, compile error: Incorrect dependency

I'm getting the following error for a custom module on compile in Magento 2.1.3
Incorrect dependency in class NAMESPACE\MODULE\Block\SOMEBLOCK in /home/www/app/code/namespace/module/Block/Someblock.php
\Magento\Framework\Filesystem already exists in context object
Briefly, the block code looks like this;
namespace Namespace\Module\Block;
use Magento\Framework\App\Filesystem\DirectoryList;
class Someblock extends \Magento\Framework\View\Element\Template {
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
\Magento\Framework\Filesystem $filesystem,
array $data = []
)
{
$this->_fileSystem = $filesystem;
parent::__construct($context, $data);
}
}
The issue is that the code is injecting \Magento\Framework\Filesystem in the construct when it already exists in the inherited parent class.
For non private classes I know we can call those within the block class with;
$this->someclass
But how do we call private ones? I've tried this;
namespace Namespace\Module\Block;
use Magento\Framework\App\Filesystem\DirectoryList;
class Someblock extends \Magento\Framework\View\Element\Template {
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
//\Magento\Framework\Filesystem $filesystem,
array $data = []
)
{
//$this->_fileSystem = $filesystem;
parent::__construct($context, $data);
}
public function dosomething() {
$fileSystem = $this->_fileSystem;
}
}
But I get $_filesystem is undefined.
Here is the constructor from the parent class \Magento\Framework\View\Element\Template
public function __construct(Template\Context $context, array $data = [])
{
$this->validator = $context->getValidator();
$this->resolver = $context->getResolver();
$this->_filesystem = $context->getFilesystem();
$this->templateEnginePool = $context->getEnginePool();
$this->_storeManager = $context->getStoreManager();
$this->_appState = $context->getAppState();
$this->templateContext = $this;
$this->pageConfig = $context->getPageConfig();
parent::__construct($context, $data);
}
Any feedback gratefully received
Got it, the answer was right in front of me! The parent constructor was;
public function __construct(Template\Context $context, array $data = [])
{
$this->validator = $context->getValidator();
$this->resolver = $context->getResolver();
$this->_filesystem = $context->getFilesystem();
$this->templateEnginePool = $context->getEnginePool();
$this->_storeManager = $context->getStoreManager();
$this->_appState = $context->getAppState();
$this->templateContext = $this;
$this->pageConfig = $context->getPageConfig();
parent::__construct($context, $data);
}
The variable is;
$this->_filesystem
NOT
$this->_fileSystem
Which I had.
You need to try this one,
namespace Namespace\Module\Block;
use Magento\Framework\App\Filesystem\DirectoryList;
class Someblock extends \Magento\Framework\View\Element\Template
{
public $myfileobj;
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
array $data = []
)
{
parent::__construct($context, $data);
}
public function dosomething()
{
$this->myfileobj = $this->getFilesystem();
}
}
You can used $this->myfileobj in another place as well.

Laravel MVC concept

I am still used to MVC concept but i understand the basic concept of it.
I found this code on a "PHP" blog.
<?php
class Todo_Controller extends Base_Controller
{
public function action_list() {
$todos = Todo::all();
return View::make("list")
->with("todos", $todos);
}
public function action_view($id) {
$todo = Todo::where_id($id)->first();
return View::make("view")
->with("todo", $todo);
}
public function action_delete($id) {
$todo = Todo::where_id($id)->first();
$todo->delete();
return View::make("deleted");
}
public function action_new() {
return View::make("add");
}
public function action_add() {
$todo = new Todo();
$todo->title = Input::get("title");
$todo->description = Input::get("description");
$todo->save();
return View::make("success");
}
}
That is a controller but I notice action_list(), action_view() and action_delete() are running SQL but it is doing it in a controller.
Why is that? shouldn't that be in the model? Isn't the purpose of a model to do anything data related?
The reason why I am asking this is because I have seen a lot of laravel tutorials both paid and unpaid ones doing this and I am asking myself, why mix the business logic with the data schema?
You can use the repository pattern to extract the data querying from your controller.
class TodoRepository {
public function get_todo($id)
{
return Todo::find($id);
}
public function get_all_todos()
{
return Todo:all();
}
public function create_todo($todo)
{
return Todo::create([
'title' => $todo['title'],
'description' => $todo['description']
]);
}
public function delete_todo($todo)
{
return Todo::find($todo)->delete();
}
}
Then you inject the repository into your controller. That way if you change databases, or ditch eloquent then you just write a new repository with the same interface and you simply change out the injection.
class Todo_Controller extends Base_Controller
{
private $todos;
public function __construct(TodoRepository $todos)
{
$this->todos = $todos;
}
public function action_list() {
return View::make("list")
->with("todos", $this->todos->get_all_todos());
}
public function action_view($id) {
return View::make("view")
->with("todo", $this->todos->get_todo($id));
}
public function action_delete($id) {
$this->todos->delete_todo($id);
return View::make("deleted");
}
public function action_new() {
return View::make("add");
}
public function action_add() {
$todo = $this->todos->create_todo(Input->get('title', 'description');
return View::make("success");
}
}
This was your controller doesn't care how you get_all_todos or delete_todo, it simply asks the repository to get/modify the data then it returns the result.

Resources