Few things I would like to point out about it is, your relationship should not be conditional, after making the default relationship what you want to make you can define scope instead and manage stuffs or use withDefault return something in failure case.
About the error calling a member function on null:- below is another example
<?php
class MyClass{
function bar(){
echo "something";
}
}
class MyAnotherClass{
function foo(){
if (1>2) {
$obj = new MyClass();
$obj->x = $x;
$obj->y = $y;
$obj->save();
return $obj;
} else {
return null;
}
}
}
$myAnotherObj = new MyAnotherClass();
$myClass = $myAnotherObj->foo();
$myClass->bar()
?>
Instead of doing it, I would prefer throwing an exception and handling it, so that I will get specific reason for failure, in Laravel rescue helper function you can choose to use.
<?php
class MyClass{
function bar(){
echo "something";
}
}
class MyAnotherClass{
function foo(){
if (1>2) {
$obj = new MyClass();
$obj->x = $x;
$obj->y = $y;
$obj->save();
return $obj;
} else {
throw new Exception("could not create my class object", 100); // Better to create custom exception class here
}
}
}
$myAnotherObj = new MyAnotherClass();
try {
$myClass = $myAnotherObj->foo();
$myClass->bar();
} catch(Exception $e) {
echo $e->getMessage();
}
?>
if for me the data is not so important I will think of creating an empty object
<?php
class MyClass{
function bar(){
echo "something";
}
}
class MyAnotherClass{
function foo(){
$obj = new MyClass();
if (1>2) {
$obj->x = $x;
$obj->y = $y;
$obj->save();
}
return $obj;
}
}
$myAnotherObj = new MyAnotherClass();
$myClass = $myAnotherObj->foo();
$myClass->bar()
?>
but if you are making an operation with that object properties, then the properties will be null instead of object, so based on the how discipline you will be when using it, you can take decision.
How I would have like to handled your situation?
Exception class
<?php
namespace App\Exceptions;
use Exception;
class SubTypeNotFound extends Exception {
public function report()
{
\Log::debug('Could not find this subtype');
}
}
?>
Model class
<?php
class Mains extends Model
{
public function subA()
{
return $this->hasOne(SubTypeA::class);
}
public function subB()
{
return $this->hasOne(SubTypeB::class);
}
public function scopeSub($query, $type)
{
return $query
->when($type === 'a',function($q){
return $q->with('subA');
})
->when($type === 'b',function($q){
return $q->with('subB');
}),function($q){
throw SubTypeNotFound();
});
}
}
?>
while retrieving it
try {
$sub = Mains::sub('a')->get();
} catch(SubTypeNotFound $e) {
return $e->getMessage();
}
If you have $this->sub_type you can avoid using the type parameter.