I have a Model Eloquent called (TicketModel),
I add a global scope for take all tickets for a user , but sometimes , I want to use Ticket without this scope how can do it? how can ignore this scope
this is the model
<?php
class TicketModel extends Eloquent{
public $timestamps = false;
public static function boot()
{
static::addGlobalScope(new TicketScope);
}
}
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ScopeInterface;
class TicketScope implements ScopeInterface {
public function apply(Builder $builder)
{
$builder->where('user_id', '=', Auth::user()->id_user);
}
public function remove(Builder $builder){}
}
What about having a child class for the cases you need the scope?
Here's an example:
class TicketModel extends Eloquent
{
// Your model stuff here
}
class UserTicketModel extends TicketModel
{
public static function boot()
{
static::addGlobalScope(new TicketScope);
}
}
The idea is not to ignore the scope sometimes, it's to use it when you need it.
If you really want the model without the scope to be the exception, let a SimpleTicketModel inherit from TicketModel and override boot() method so that it does not use the scope, like this:
class TicketModel extends Eloquent
{
public static function boot()
{
static::addGlobalScope(new TicketScope);
}
}
class SimpleTicketModel extends TicketModel
{
public static function boot()
{
// Do nothing else
}
}
Related
In my AppServiceProvider.php I tried binding a singleton interface to a concrete class using the array syntax:
class AppServiceProvider extends ServiceProvider
{
public $singletons = [
MyClassInterface::class => MyClass::class,
];
}
The interface is then typehinted in a class.
This gives an error like:
TypeError: TheClassThatUsesTheService::__construct(): Argument #2 ($myClass) must be of type MyClassInterface, string given
The errors disspears if I make a manual singleton binding using a closure:
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(MyClassInterface::class, function () {
return new MyClass;
});
}
}
Should this not behave the same?
MyClass.php:
<?php
class MyClass extends Base implements MyClassInterface
{
public function get(): mixed
{
//
}
public function insert(): void
{
//
}
}
MyClassInterface.php:
<?php
interface MyClassInterface
{
public function get(): mixed;
public function insert(): void;
}
Base.php:
class Base
{
protected function service()
{
//
}
}
Is it OK to use properties/methods from parent classes in trait methods?
This code works, but is it good practice?
class Child extends Base{
use ExampleTrait;
public function __construct(){
parent::__construct();
}
public function someMethod(){
traitMethod();
}
}
trait ExampleTrait{
protected function traitMethod(){
// Uses $this->model from Base class
$this->model->doSomething();
}
}
I don't think it's good practice.
Instead you could have a method to fetch your model object, and have that method as an abstract signature in you trait:
trait ExampleTrait {
abstract protected function _getModel();
protected function traitMethod() {
$this->_getModel()->doSomething();
}
}
class Base {
protected $_model;
protected function _getModel() {
return $this->_model;
}
}
class Child extends Base {
use ExampleTrait;
public function someMethod() {
$this->traitMethod();
}
}
Or pass your model as a parameter to your trait method:
trait ExampleTrait {
protected function traitMethod($model) {
$model->doSomething();
}
}
class Base {
protected $_model;
}
class Child extends Base {
use ExampleTrait;
public function someMethod() {
$this->traitMethod($this->_model);
}
}
Both of these approaches let you utilize your IDE's type hinting.
I have some problem and little misunderstanding Laravel SP (ServiceProvider). I have abstract class Repository and her Interface:
abstract class Repository implements RepositoryInterface {
private $model;
private $parser;
public function __construct() {
$this->model = new $this->model_name();
} }
interface RepositoryInterface {
public function create(array $attributes);
public function update($id, array $attributes);
public function delete($id);
public function all();
public function find($id);
public function filter(array $parameters, $query=null);
public function query(array $parameters, $query=null); }
and some child UserRepository for example:
class UserRepository extends Repository implements UserRepositoryInterface {
protected $model_name = "App\Models\User";
public function __construct() {
parent::__construct();
}
public function activation($user_id) {
return "user";
}
public function deactivation($user_id) {
return "user";
} }
and simple ModelParser class:
class ModelParser {
protected $parameters;
protected $model;
public function __construct($model) {
$this->model = $model;
} }
This work fine, but I would pass ModelParser as DI in my construct of abstract Repository with parameter $model. I dont have idea. How should I do it ?
I use it like this:
class UserController extends Controller {
private $repository;
public function __construct(UserRepository $repository) {
$this->repository = $repository;
} }
Well it's kinda complicated since your ModelParser requires a $model as it's parameter. And because this $model may vary depends on its repository, it will be too complicated if we're trying to resolve it using Laravel service container binding.
There's an easier approach, we can make the ModelParser class's constructor receive an optional $model parameter. Then we can add an additional method to set this $model property like so:
namespace App\Models;
class ModelParser
{
protected $parameters;
protected $model;
// Make $model parameter optional by providing default value.
public function __construct($model = null) {
$this->model = $model;
}
// Add setter method for $model.
public function setModel($model)
{
$this->model = $model;
return $this;
}
}
And now you can inject the ModelParser into your abstract Repository class. Laravel will easily resolve this ModelParser parameter
namespace App\Models;
use App\Models\ModelParser;
use App\Models\RepositoryInterface;
abstract class Repository implements RepositoryInterface
{
private $model;
private $parser;
// Pass ModelParser instance to your constructor!
public function __construct(ModelParser $parser)
{
$this->model = new $this->model_name();
// Set the parser's model property.
$this->parser = $parser->setModel($this->model);
}
// Rest of your code.
}
And if you're extending the abstract Repository class, you still have to pass this ModelParser to the constructor like so:
namespace App\Models;
use App\Models\ModelParser;
use App\Models\UserRepositoryInterface;
class UserRepository extends Repository implements UserRepositoryInterface
{
protected $model_name = "App\Models\User";
public function __construct(ModelParser $parser)
{
parent::__construct($parser);
}
}
Actually, if you're not planning to pass another parameter or perform something else during the class instantiation, you can simply remove the __construct() method from UserRepository and rely on its parent (the abstract Repository).
Hope this help!
I can't seem to find the problem here. I'm using a trait to attach a global scope to all Eloquent queries on a model. Here is my model
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Club\traits\restrictToClubTrait;
class Product extends Model
{
public function category()
{
return $this->belongsTo('App\ProductCategory', 'product_category_id', 'id');
}
public function producer()
{
return $this->belongsTo('App\Producer', 'producer_id');
}
}
And here is the trait
<?php namespace App\Club\traits;
trait restrictToClubTrait
{
/**
* Boot the soft deleting trait for a model.
*
* #return void
*/
public static function bootRestrictToClubTrait()
{
dd('p');
static::addGlobalScope(new RestrictToClubScope);
}
}
That dd never gets hit, so the function must not be getting hit, I've poured over the docs but I don't see where I've gone wrong.
Traits should be "included" inside the class body. For more info here
use App\Club\traits\restrictToClubTrait;
class Product extends Model {
use restrictToClubTrait;
}
I'm adding validation to a BaseModel class which all eloquent models will eventually extend in my application.
The base class resembles:
class BaseModel extends Eloquent {
private $errors;
private $validator;
public function __construct()
{
$this->validator = new BaseValidator(get_class($this));
}
public static function boot()
{
parent::boot();
static::creating(function($model) {
return false;
});
static::saving(function($model)
{
return false;
});
}
a sample concrete that extends the base:
class News extends BaseModel {
protected $guarded = ['audience', 'deleted_at'];
protected $table = 'zbw_news';
//relations, scopes, etc
}
Whenever I create a new object through artisan tinker, the saving closure isn't being triggered (it returns true when it should return false). However, I can bind a closure directly on the model's static (instead of late static binding) and it works as expected:
\News::saving(function($model) { return false; });
Any ideas why the boot method isn't being called properly or what I'm doing wrong here?