is there a isnull or ifnull function in doctrine? - doctrine

I am looking for a function in doctrine for converting null values to specified default values. So IsNull(A, B) should return B if A is null, A otherwice. Has doctrine such a function?

If you are talking about grabbing null values from an object, write a method in your entity
<?php
// Entities/SomeEntity.php
class Foo
{
private $a;
private $b;
// ...
// Your getters and setters are here
// ...
public function myNullFunction()
{
if($this->a === null AND $this->b !== null)
{
return $this->b;
}
elseif($this->b === null && $this->a !== null)
{
return $this->a;
}
else
{
// ... Do something if both are null
}
}
}
You can then use the function whenever you have loaded your object(s)
$foo = $some_repository->getFooObject();
// The function returning a value that is a or b
$bar = $foo->myNullFunction();

You can use the following project which contains some MSSQL functions for doctrine:
https://github.com/naprstek/doctrine-functions

Related

Laravel Eloquent, "inheritance" override fields from parent

Is there any way in Eloquent to have a model which has some sort of parent model, where both have an identical field, nullable on the child. And if I get the value $child->field I get the childs value if it's not null, otherwise I get the parent value? Something like this:
$parent = new Parent();
$parent->info = 'parent';
$parent->save();
$child = new Child();
$child->info = 'child';
$child->parent()->associate($parent);
$child->save();
echo $child->info
Prints 'child'
And opposite:
$parent = new Parent();
$parent->info = 'parent';
$parent->save();
$child = new Child();
$child->parent()->associate($parent);
$child->info = null;
$child->save();
echo $child->info
Prints 'parent'
It must be a pattern somewhere to have one table rows values 'overrule' another, I just can't seem to find what to search for.
You simply need a custom accessor on the model of your choice:
class Child
{
public function getInfoAttribute($value)
{
if ($value === null) {
return $this->parent->info;
}
return $value;
}
}
This will allow you to still access the property via $child->info.
Please be aware that this will not cast the attribute value according to the $casts array. If you need this casting logic as well, you should use a custom getter method instead of the magic accessor:
class Child
{
public function getInfo()
{
$info = $this->info;
if ($info === null) {
$info = $this->parent->info;
}
return $info;
}
}
If you need to multiple properties, you can either duplicate the code and put it into a trait to remove the clutter from your model. Or instead, you can try overriding the magic __get($key) method:
class Child
{
$parentInheritedAttributes = ['info', 'description'];
// solution 1: using normal model properties like $child->info
public function __get($key)
{
if (in_array($key, $this->parentInheritedAttributes)) {
$value = parent::__get($key);
if ($value === null) {
// this will implicitely use __get($key) of parent
$value = $this->parent->$key;
}
return $value;
}
return parent::__get($key);
}
// solution 2: using getters like $child->getInfo()
public function __call($method, $parameters)
{
if (\Illuminate\Support\Str::startsWith($method, 'get')) {
$attribute = \Illuminate\Support\Str::snake(lcfirst(substr($method, 3)));
in_array($attribute, $this->parentInheritedAttributes)) {
$value = $this->$attribute;
if ($value === null) {
$value = $this->parent->$attribute;
}
return $value;
}
}
}
}

Dropdown of available statuses

I'm trying to figue out what I"m doing wrong to get the error message. I have my User model that has a status_id field and it is a foreign key to my statuses table with an id and name field.
public function scopeAvailable($query, $current = null)
{
$options = $this->getAvailableOptions($current)->toArray();
return $query->whereIn('name', $options);
}
public function getAvailableOptions(string $current = null)
{
$options = collect(['Active', 'Inactive']);
switch ($current) {
case 'Active':
return $options->merge(['Fired', 'Suspended', 'Retired']);
case 'Injured':
return $options->merge(['Fired', 'Retired']);
case 'Suspended':
return $options->merge(['Suspended', 'Retired']);
}
return $options;
}
public function availableStatuses()
{
$status = $this->status ? $this->status->name : null;
return UserStatus::available($status)->get();
}
Type error: Argument 1 passed to App\Models\UserStatus::getAvailableOptions() must be of the type string or null, object given, called in /home/vagrant/projects/app/app/Models/UserStatus.php on line 45

Creating linq expression with a subtype restriction

I have this list of type IEnumerable<MyBaseType> for which I am trying to create an extra where-clause to retrieve a specific item in the list. The specific value does only exist on subtype MyFirstType and MySecondType. Not on MyBaseType.
Is it possible to create an expression kind of...
MyList.Where(b => (b is MyFirstType || (b is MySecondType)) && b.SpecificValue == message.SpecificValue);
Above is not working since b is of type MyBaseType and SpecificValue does not exist there. Also note that I do have another subtype MyThirdType that neither has the SpecificValue.
What does work doing what I want is this...
foreach (dynamic u in MyList)
{
if (u is MyFirstType || u is MySecondType)
{
if (u.SpecificValue == message.SpecificValue)
{
//Extracted code goes here
break;
}
}
}
Anyone have an idea how to create an linq expression for the above scenario?
Maybe there is a better solution but as I see it, this could work well enough... If you don't mind performance.
Well then, start by declaring an interface:
public interface IMySpecialType
{
object SpecificValue {get; set;} //you didn't specify what type this is
//all your other relevant properties which first and second types have in common
}
Then, make MyFirstType and MySecondType derive from this interface:
public class MyFirstType : MyBaseType, IMySpecialType
{
//snipet
}
public class MyFirstType : MySecondType, IMySpecialType
{
//snipet
}
Then, filter and cast:
MyList
.Where(b => (b is MyFirstType) || (b is MySecondType))
.Cast<IMySpecialType>()
.Where(b => b.SpecificValue == message.SpecificValue);
//do something
The direct translation of your code to a Linq where clause is
string messageValue = "foo";
var result = baseList.Where(item =>
{
dynamic c = item;
if(item is MyFirstType || item is MySecondType)
{
if( c.SpecificValue == messageValue)
return true;
}
return false;
});
This will require testing the type of the class though and using dynamic - so you might as well cast item to either MyFirstType or MySecondType directly.
An alternative would be using reflection to check if the property exists, using this approach you are not dependent on the actual types of your items as long as they do have the property you are interested in:
string messageValue = "foo";
var result = baseList.Where( item =>
{
var prop = item.GetType().GetProperty("SpecificValue");
if (prop != null && prop.GetValue(item, null) == messageValue)
return true;
else return false;
});
If modifying the class hierarchy is an option you can have you MyFirstType or MySecondType implement an interface that holds the property, then you can use OfType() in your Linq query:
interface ISpecific
{
string SpecificValue { get; set; }
}
class MyFirstType : MyBase, ISpecific
{
public string SpecificValue { get; set; }
}
...
string messageValue = "foo";
var result = baseList.OfType<ISpecific>()
.Where(item => item.SpecificValue == messageValue);
A far more easy way to do that would be to create an interface to mark all your classes having this property SpecificValue. Then it's a child play :
static void Main(string[] args)
{
List<MyBaseType> MyList = new List<MyBaseType>();
ISpecificValue message = new MyFirstType();
MyList.OfType<ISpecificValue>().Where(b => b.SpecificValue == message.SpecificValue);
}
}
class MyBaseType { }
interface ISpecificValue { string SpecificValue { get; set; } }
class MyFirstType : MyBaseType, ISpecificValue
{
public string SpecificValue;
}
class MySecondType : MyBaseType, ISpecificValue
{
public string SpecificValue;
}

Saving a custom object using IsloatedStorageSettings

I'm trying to save an object in IsolatedStorageSettings to save the high scores for my game, but whenever I try to save an updated copy of the object C# seems to think the object hasn't changed. I tried creating a custom Equals function for the HighScores class but that doesn't seem to help.
Any idea what I'm doing wrong?
Thanks
public bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
// If the key exists
if (isolatedStore.Contains(Key))
{
// If the value has changed
if (isolatedStore[Key] != value) //This keeps returning false
{
// Store the new value
isolatedStore[Key] = value;
valueChanged = true;
}
}
// Otherwise create the key.
else
{
isolatedStore.Add(Key, value);
valueChanged = true;
}
return valueChanged;
}
//This is located inside the HighScores class
public bool Equals(HighScores newHighScores)
{
for (int i = 0; i < highScores.Length; i++)
{
if (!highScores[i].Name.Equals(newHighScores.GetIndex(i).Name))
{
return false;
}
if (!highScores[i].Time.Equals(newHighScores.GetIndex(i).Time))
{
return false;
}
}
return true;
}
You haven't implemented the equality operators '==' and '!=' and these compare reference equality, you are going to have provide the implementation which maps on to your 'Equals' method
http://msdn.microsoft.com/en-us/library/ms173147%28v=vs.80%29.aspx
You should do isolatedStore.Save() to commit the changes

SingleOrDefault: How to change the default values?

SingleOrDefault returns null, but what if I want to assign values to represent the object that wasn't found?
you can do something like
myStrings.DefaultIfEmpty("myDefaultString").Single()
check out here
?? operator. If the left argument is null, evaluate and return the second argument.
myCollection.SingleOrDefault() ?? new[]{new Item(...)}
This will only work with reference types (or nullables), but it would do what you're looking for very simply.
You could roll your own.
public static T SingleOrDefault<T>(this IEnumerable<T> enumerable, T defaultValue) {
if ( 1 != enumerable.Count() ) {
return defaultValue;
}
return enumerable.Single();
}
This can be a bit expensive though because Count() requires you to process the entire collection and can be fairly expensive to run. It would be better to either call Single, catch the InvalidOperationException or roll a IsSingle method
public static bool IsSingle<T>(this IEnumerable<T> enumerable) {
using ( var e = enumerable.GetEnumerator() ) {
return e.MoveNext() && !e.MoveNext();
}
}
public static T SingleOrDefault<T>(this IEnumerable<T> enumerable, T defaultValue) {
if ( !enumerable.IsSingle() ) {
if( enumerable.IsEmpty() ) {
return defaultValue;
}
throw new InvalidOperationException("More than one element");
}
return enumerable.Single();
}
You could create your own extension methods -- SingleOrNew.
public static class IEnumerableExtensions
{
public static T SingleOrNew<T>( this IEnumerable<T> enumeration, T newValue )
{
T elem = enumeration.SingleOrDefault();
if (elem == null)
{
return newValue;
}
return elem;
}
public static T SingleOrNew<T>( this IEnumerable<T> enumeration, Func<T,bool> predicate, T newValue )
{
T elem = enumeration.SingleOrDefault( predicate );
if (elem == null)
{
return newValue;
}
return elem;
}
}

Resources