Created
October 14, 2012 23:36
-
-
Save andylolz/3890165 to your computer and use it in GitHub Desktop.
Fun extending the User model. This is my solution to the problem I posted here: http://gist.github.com/3885906 Thanks to Kindari on laravel IRC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| class Student extends User { | |
| public function reports() { | |
| // I know I said the relationship here is one-to-one..! | |
| // But I don't mind hacking this too much. | |
| return $this->has_many('Report', 'student_id'); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| class Teacher extends User { | |
| public function reports() { | |
| return $this->has_many('Report', 'teacher_id'); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| class User extends Eloquent{ | |
| // Sets the table name for this model. The default table name | |
| // is the plural of the model name, so this is as default. | |
| // | |
| // However, it is still required to be defined here because | |
| // of all the subclassing (otherwise Eloquent would start | |
| // looking for tables with the names of the subclasses) | |
| public static $table = 'users'; | |
| // Defines all of the properties that should be saved to the | |
| // database. Note that type_id is ommitted from here, as it | |
| // is just a handy variable we keep around but don't want saved. | |
| // | |
| // Though it's not required, it is still worth defining $accessible | |
| // for all classes, as it helps keep track of the current database | |
| // schema. | |
| public static $accessible = array( | |
| 'email', | |
| 'first_name', | |
| 'last_name', | |
| 'password', | |
| 'status', | |
| 'user_type_id' | |
| ); | |
| /**** BEGIN EXTRA-PRICKLY CODE! ****/ | |
| // Array to store mappings between subclass names and their | |
| // relevant user type IDs. | |
| // | |
| // This isn't really necessary - it's here as a per-request | |
| // cache, to avoid repeated calls to the UserType table | |
| public static $type_id = array(); | |
| // Override the default constructor | |
| public function __construct($attributes = array(), $exists = false) { | |
| if(is_subclass_of($this, 'User')) { | |
| $subclass = get_class($this); | |
| // Get the relevant user type ID for this subclass, and | |
| // store it in our per-request cache (the $type_id array) | |
| if(!array_key_exists($subclass, self::$type_id)) { | |
| self::$type_id[$subclass] = UserType::where_desc($subclass)->first()->id; | |
| } | |
| // We can infer the user_type_id of the subclass object, | |
| // so let's not require it to be specified when a new | |
| // instance is created. | |
| $attributes['user_type_id'] = self::$type_id[$subclass]; | |
| } | |
| parent::__construct($attributes, $exists); | |
| } | |
| // Override the default attribute setter | |
| // | |
| // We just need to do this to prevent the user type of a subclass | |
| // object being changed | |
| public function set_attribute($key, $value) { | |
| if($key == 'user_type_id' && is_subclass_of($this, 'User')) { | |
| $subclass = get_class($this); | |
| // Note that type_id[subclass] is set in the constructor, so we can | |
| // guarantee we have a key value | |
| if($value != self::$type_id[$subclass]) { | |
| throw new Exception("Can't set the user type of a User subclass."); | |
| } | |
| } | |
| parent::set_attribute($key, $value); | |
| } | |
| // Override the default query | |
| // | |
| // We append a WHERE clause to all queries to subclasses, specifying the | |
| // relevant user type ID. This is probably the most important bit. | |
| public function query() { | |
| if(is_subclass_of($this, 'User')) { | |
| return parent::query()->where('user_type_id', '=', self::$type_id[get_class($this)]); | |
| } | |
| return parent::query(); | |
| } | |
| // Downcast a User object to one of its subclasses | |
| public static function construct_from_user($user) { | |
| // Construct a new instance of the subclass | |
| $user_sub = new static; | |
| // One quick integrity constraint to ensure we're not | |
| // downcasting a user to an incompatible type | |
| if($user_sub->user_type_id && $user_sub->user_type_id != $user->user_type_id) { | |
| $err_msg = "That user is not of type " . get_class($user_sub) . "."; | |
| throw new Exception($err_msg); | |
| } | |
| // Ok, now just copy all the object properties over | |
| foreach($user as $k => $v) { | |
| $user_sub->$k = $v; | |
| } | |
| return $user_sub; | |
| } | |
| /**** END EXTRA-PRICKLY CODE! ****/ | |
| public function user_type() { | |
| return $this->belongs_to('UserType', 'user_type_id'); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment