Yii2: Model column alias - yii2

I have some silly column names in my database, is there an easy way to alias a column name so it's always used for example:
public function columnAlias(){
return ['id'=>'ID', 'foo'=>'Bar'];
}
$model->id === $model->ID
$model->foo === $model->Bar

If it's only for accessing the attributes on the model you can write a get function.
So adding:
public function getId() {
return $this->ID;
}
public function getFoo() {
return $this->Bar;
}
will enable you to access ID and Bar like
$model->id;
$model->foo;
This works because of Yii2's use of the magic method __get: https://github.com/yiisoft/yii2/blob/master/framework/base/Component.php#L134

Related

Yii2: Convert hasMany() relation into hasOne()

I need to be able to convert a hasMany() relation, which queries and return an array into a hasOne() relation which returns object|null.
Use case:
public function getItems() : \yii\db\ActiveQuery {
return $this->hasMany(Item::class, ['parent_id' => 'id']);
}
I want to create a relation which returns one specific Item object (or null if it does not exist).
I would like to do something like this:
public function getPrimaryItem() : \yii\db\ActiveQuery {
return $this->getItems()->andWhere(["primary"=>true])->toHasOne();
}
Please do not tell me to call ->one() on the original query, because that is not going to solve the problem. I need to be able to:
call $model->primaryItem and receive either Item or null
call $model->getPrimaryItem() and receive the relation's ActiveQuery
You can toggle it by multiple property of \yii\db\ActiveQuery
public function getPrimaryItem() : \yii\db\ActiveQuery {
$query = $this->getItems();
$query->multiple = false;
//Your logics
$query->andWhere(["primary"=>true])
return $query;
}

hasOne with null-able in laravel not working

I have a customer table which has a field called 'policy_id', where policy_id points to policy table. It is a null-able field, ie. Some customers may not have a policy.
I have a relationship code like this in Customer.php
public function policy() {
return $this->hasOne('App\Models\Policy', "id", "policy_id");
}
But when I issue a search request I am getting error like this:
Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\Models\Policy]
If I modify the function like this:
public function policy() {
if ($this->getAttribute('policy_id')) {
return $this->hasOne('App\Models\Policy', "id", "policy_id");
} else {
return null
}
}
But I am getting an error like this:
Call to a member function getRelationExistenceQuery() on null
Here is my search code:
$c = new Customer();
return Customer::doesntHave('policy')->orWhere(function (Builder $query) use ($req) {
$query->orWhereHas('policy', function (Builder $query) use ($req) {
$p = new Policy();
$query->where($req->only($p->getFillable()))
->orWhereBetween("policy_period_from", [$req->policy_period_start_from, $req->policy_period_start_to])
->orWhereBetween("policy_period_to", [$req->policy_period_end_from, $req->policy_period_end_to])
->orWhereBetween("payment_date", [$req->payment_date_from, $req->payment_date_to]);
});
})->where($req->only($c->getFillable()))->get();
Am I missing something or are there any other ways to do this?
PS: While debugging the above search code is returning successfully, but the exception happening from somewhere inside Laravel after the prepareResponse call.
Thanks in advance.
return $this->hasOne('App\ModelName', 'foreign_key', 'local_key');
Change the order, put the foreign_key policy_id in front of id
In your Customer Model, you need to use belongsTo method:
public function policy() {
return $this->belongsTo('App\Models\Policy', "policy_id", "id");
}
And In your Policy Model, use hasOne:
public function customer() {
return $this->hasOne('App\Models\Customer', "policy_id", "id");
}
First of all, you placed the wrong params.
$this->belongsTo('App\Models\Policy', "FK", "PK");
public function policy() {
return $this->belongsTo('App\Models\Policy','policy_id', 'id');
}
And for null value of policy_id you can use withDefault();
public function policy() {
return $this->belongsTo('App\Models\Policy','policy_id', 'id')->withDefault([
'name' => 'test'
]);;
}
there's a number of problems there but can you perhaps specify the namespace and the class of both your models - Customer and Policy.
By default, the models you create with php artisan make:model will use the \App namespace e.g. \App\Customer and \App\Policy.
Just double check that.
Also, with regards to the relationship, if the Laravel conventions have been followed you could just:
In the Customer model
public function policy() {
return $this->belongsTo(Policy::class);
}
In the Policy model
public function customer() {
return $this->hasOne(Customer::class);
}
of if a multiple customers can be under one policy
public function customers() {
return $this->hasMany(Customer::class);
}
Good luck

Schema getColumnType nort working

Trying to get Column type in my json (laravel project), but not working ?, can anyone se whats wrong?
protected function getType()
{
return Schema::getColumnType($this->builder->getModel()->getTable() , $this->getUpdatableColums());
}
enter code here
protected function getRecords(Request $request)
{
// return $this->builder->limit($request->limit)->orderBy('id', 'asc')->get($this->getDisplayableColums());
return $this->builder
->limit($request->limit)
->orderBy('id', 'asc')
->get($this->getDisplayableColums())
->getType();
}
In your getType method you seem to be passing an array instead of a string
protected function getType()
{
return Schema::getColumnType($this->builder->getModel()->getTable() , $this->getUpdatableColums());
}
The laravel 5.5 docs say "string getColumnType(string $table, string $column)"
https://laravel.com/api/5.5/Illuminate/Database/Schema/Builder.html#method_getColumnType
You might be able to change your getType method to expect a column name. And do a loop in your code
foreach ($this->getUpdatableColumns() as $column) {
$this->getType($column);
}

Eloquent saves missing attributes as empty strings instead of NULLs

When I try to save a model with a missing attribute to a not-NULL db field, I don't want the application to be quiet about that, I want it to scream in vein. But it's being just fine with the empty strings that eloquent saves.
Why does MyModel::create([]) succeed??
class BaseModel extends Eloquent {
public static function boot()
{
parent::boot();
static::creating(function($model) {
static::setNullWhenEmpty($model);
return true;
});
}
private static function setNullWhenEmpty($model)
{
foreach ($model->toArray() as $name => $value) {
if (empty($value)) {
$model->{$name} = null;
}
}
}
}
Credit: Set fields to null instead of empty value to avoid problems with nullable foreign keys

Simple LINQ to SQL extension method

How would I write a simple LINQ to SQL extension method called "IsActive" which would contain a few basic criteria checks of a few different fields, so that I could reuse this "IsActive" logic all over the place without duplicating the logic.
For example, I would like to be able to do something like this:
return db.Listings.Where(x => x.IsActive())
And IsActive would be something like:
public bool IsActive(Listing SomeListing)
{
if(SomeListing.Approved==true && SomeListing.Deleted==false)
return true;
else
return false;
}
Otherwise, I am going to have to duplicate the same old where criteria in a million different queries right throughout my system.
Note: method must render in SQL..
Good question, there is a clear need to be able to define a re-useable filtering expression to avoid redundantly specifying logic in disparate queries.
This method will generate a filter you can pass to the Where method.
public Expression<Func<Listing, bool>> GetActiveFilter()
{
return someListing => someListing.Approved && !someListing.Deleted;
}
Then later, call it by:
Expression<Func<Filter, bool>> filter = GetActiveFilter()
return db.Listings.Where(filter);
Since an Expression<Func<T, bool>> is used, there will be no problem translating to sql.
Here's an extra way to do this:
public static IQueryable<Filter> FilterToActive(this IQueryable<Filter> source)
{
var filter = GetActiveFilter()
return source.Where(filter);
}
Then later,
return db.Listings.FilterToActive();
You can use a partial class to achieve this.
In a new file place the following:
namespace Namespace.Of.Your.Linq.Classes
{
public partial class Listing
{
public bool IsActive()
{
if(this.Approved==true && this.Deleted==false)
return true;
else
return false;
}
}
}
Since the Listing object (x in your lambda) is just an object, and Linq to SQL defines the generated classes as partial, you can add functionality (properties, methods, etc) to the generated classes using partial classes.
I don't believe the above will be rendered into the SQL query. If you want to do all the logic in the SQL Query, I would recommend making a method that calls the where method and just calling that when necessary.
EDIT
Example:
public static class DataManager
{
public static IEnumerable<Listing> GetActiveListings()
{
using (MyLinqToSqlDataContext ctx = new MyLinqToSqlDataContext())
{
return ctx.Listings.Where(x => x.Approved && !x.Deleted);
}
}
}
Now, whenever you want to get all the Active Listings, just call DataManager.GetActiveListings()
public static class ExtensionMethods
{
public static bool IsActive( this Listing SomeListing)
{
if(SomeListing.Approved==true && SomeListing.Deleted==false)
return true;
else
return false;
}
}
Late to the party here, but yet another way to do it that I use is:
public static IQueryable<Listing> GetActiveListings(IQueryable<Listing> listings)
{
return listings.Where(x => x.Approved && !x.Deleted);
}
and then
var activeListings = GetActiveListings(ctx.Listings);