Skip to content

Instantly share code, notes, and snippets.

@shanginn
Last active August 8, 2024 13:40
Show Gist options
  • Save shanginn/aadddec758efb595be2e8be6a69b99c4 to your computer and use it in GitHub Desktop.
Save shanginn/aadddec758efb595be2e8be6a69b99c4 to your computer and use it in GitHub Desktop.
Get available relationships trait for Eloquent model (Laravel 5.*)

GetRelationships Trait

This trait will allow you to get defined relationships on the model. I wish Laravel have a way to get this without any additions(except for trait), but there is no way.

Here we have 2 versions of the trait: for PHP7 and for PHP5.

Both method uses Reflections to collect information about the model.

PHP7

With PHP7 version you'll only need to add return class for the relationship method like this:

//...
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Shanginn\Crudroller\Eloquent\Concerns\GetRelationships; // Don't forget to change namespace

class ExampleModel extends Model
{
  use GetRelationships;

  public function exampleRelation() : belongsTo
  {
    return $this->belongsTo(AnotherModer::class);
  }
//...

That's it!

##PHP5

With PHP5 you need to add docBlock comment with the @Relation tag.

//...
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Shanginn\Crudroller\Eloquent\Concerns\GetRelationships; // Don't forget to change namespace

class ExampleModel extends Model
{
  use GetRelationships;
  /**
   * Example relation
   *
   * @return BelongsTo
   * @Relation
   */
  public function exampleRelation()
  {
    return $this->belongsTo(AnotherModer::class);
  }
//...

Info

Return format is a little different for the two:

PHP7-version will return associative array with keys set to relationships functions names and values set to classes ot those relationships.

Ex.

[
  "category" => "Illuminate\Database\Eloquent\Relations\BelongsTo",
  "currency" => "Illuminate\Database\Eloquent\Relations\HasMany"
]

PHP5-version will return only relationships functions names, because I'm using PHP7 and too lazy to write regular expression to parse this value from the docBlock.

Ex.

[
  0 => "category",
  1 => "currency"
]
<?php // PHP7 version
namespace Shanginn\Crudroller\Eloquent\Concerns;
use ReflectionClass;
use ReflectionMethod;
use Illuminate\Database\Eloquent\Relations\Relation;
trait GetRelationships
{
/**
* Available relationships for the model.
*
* @var array
*/
protected static $availableRelations = [];
/**
* Gets list of available relations for this model
* And stores it in the variable for future use
*
* @return array
*/
public static function getAvailableRelations()
{
return static::$availableRelations[static::class] ?? static::setAvailableRelations(
array_reduce(
(new ReflectionClass(static::class))->getMethods(ReflectionMethod::IS_PUBLIC),
function ($result, ReflectionMethod $method) {
// If this function has a return type
($returnType = (string) $method->getReturnType()) &&
// And this function returns a relation
is_subclass_of($returnType, Relation::class) &&
// Add name of this method to the relations array
($result = array_merge($result, [$method->getName() => $returnType]));
return $result;
}, []
)
);
}
/**
* Stores relationships for future use
*
* @param array $relations
* @return array
*/
public static function setAvailableRelations(array $relations)
{
static::$availableRelations[static::class] = $relations;
return $relations;
}
}
<?php // PHP5 version
namespace Shanginn\Crudroller\Eloquent\Concerns;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use ReflectionClass;
use ReflectionMethod;
trait GetRelationships
{
/**
* Available relationships for the model.
*
* @var array
*/
protected static $availableRelations = [];
/**
* Gets list of available relations for this model
* And stores it in the variable for future use
*
* @return array
*/
public static function getAvailableRelations()
{
return isset(static::$availableRelations[static::class]) ?
static::$availableRelations[static::class] :
static::setAvailableRelations(
array_reduce(
(new ReflectionClass(static::class))->getMethods(ReflectionMethod::IS_PUBLIC),
function ($result, ReflectionMethod $method) {
// If this method has a comment
($doc = $method->getDocComment()) &&
// And it contains @Relation keyword
strpos($doc, '@Relation') &&
// Add name of this method to the relations array
array_push($result, $method->getName());
return $result;
}, []
)
);
}
/**
* Stores relationships for future use
*
* @param array $relations
* @return array
*/
public static function setAvailableRelations(array $relations)
{
static::$availableRelations[static::class] = $relations;
return $relations;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment