I have a Laravel project with some model which have been pointed to external databases (from Magento). On the constructor of this models I want to check a session variable in order to change the model connection to the user selection. One of this checks must be if the user selected some external platform, for connecting to this, if not I wanna redirect to the selection page. I am trying with this to avoid session expiration and manual route writing (without platform selection).
How can I redirect the user to certain page in the model constructor?
Main Model
class MagentoModel extends Model
{
protected $platform;
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->platform = app('selectedPlatform');
if ($this->platform->id < 1) {
return redirect()->route('index');
// Maybe I have to use Redirect::route('index');
}
}
}
Certain model extending MagentoModel
class Customer extends MagentoModel
{
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->connection = $this->platfom->connection_key;
$this->table = config('customersTable');
}
}
It throws an error right now:
Trying to get property 'connection_key' of non-object
I supose the parent constructor (MagentoModel) is not being executed before the line $this->connection = $this->platfom->connection_key;. Is possible my OOP comprehension is not right just in this case.
Related
I am trying to add a custom attribute "role" to my User model. My current implementation is like this:
User extends Authenticatable
{
protected $appends = array('role');
public $getRoleAttribute()
{
$role = DB::table('acl_user_has_roles')->where('user_id', $this->id)
->value('role');
return $role;
}
}
This implementation largely works. The concern is, this role attribute is referenced many times in the life time of $user instance. Whenever it is reference, the getRoleAttribute() function will be called, then database queries will be executed. It seems a bit unnecessary to me, so I am trying find a way to only run these queries once, preferably when model instance is contructed:
I tried to override model constructor as described in answer to another similar question:
public $role;
public function __construct(array $attributes = array())
{
parent::__construct($attributes);
$this->role= $this->role();
}
protected function role()
{
$role = DB::table('acl_user_has_roles')->where('user_id', $this->id)
->value('role');
return $role;
}
When I tried to reference the role attribute like this:
$user = User::find(1);
echo $user->role;
I get nothing.
if I simply set the role attribute to some dummy text:
$this->role = "Dummy Role";
instead of:
$this->role();
Then I can get this "Dummy Role" text.
What am I missing here?
I am using Laravel 4.2.
I have two models: User and Video, both of these models are having one-to-many relationship i.e. User -> HasMany-> Video.
Recently, I got a requirement to display the list of users along with sum of file-size of total videos uploaded by each user and allow users to be order by the sum of file size ascending or descending.
I've made following changes in User model:
class User extends Eloquent {
protected $hidden = array('videosSum');
protected $appends = array('videos_size');
public function videosSum() {
return $this->hasOne('Video')
->selectRaw('sum(file_size) as sum, user_id')
->groupBy('user_id');
}
public function getVideosSizeAttribute()
{
// if relation is not loaded already, let's do it first
if ( ! array_key_exists('videos_size', $this->relations)){
$this->load('videosSum');
}
$related = $this->getRelation('videosSum');
return $this->attributes['videos_size'] = isset($related->sum) ? (int) $related->sum : 0;
}
}
And using like:
User::where('id', '!=', Auth::user()->id);
I am getting the desired result.
But the problem is, I don't want the videos_size attribute everywhere, where the User model gets called. I want to set it dynamically.
I tried User::$appends = ['videos_size'] but it gives protected property cannot be set outsize of class error.
I also tried to make a method in User model which set the $appends if called, but it is also not working.
Can anybody help me how to enable the appends property dynamically?
Laravel doesn't support this off the bat.
my friend and I wrote this extention:
Dynamically hide certain columns when returning an Eloquent object as JSON?
basically you have to override your models.php toArray() method as appended attributes get calculated when you ask for the model in json or array form.
you can add to the trait that's in that link and use it or just put these methods in your respective model class.
public static function getStaticAppends() {
return self::$_appends;
}
public static function setStaticAppends(array $value) {
self::$_appends = $value;
return self::$_appends;
}
public static function getDefaultAppends() {
return with(new static)->getAppends();
}
public function getAppends(){
return $this->appends;
}
public function toArray() {
if (self::getStaticAppends()) {
$this->appends = self::getStaticAppends();
}
return parent::toArray();
}
I have one question, that seems to be logical, but I can't find answer for it.
Let's say I have Model Task:
class Task extends Eloquent {
protected $fillable = array('is_done');
}
So, I have one property is_done, but when working on frontend and backend part of application, I would like to have isDone as model property.
Is there a way to say it to framework, to somehow repack it for me? So that I am able to use isDone, throughout application, and that Model takes care of converting it to is_done, when it comes to saving/updating.
This would help me, so I don't have to think about names specified in database (like when using alias in traditional SQL clauses).
Is this possible at all? Does it make sense?
To prevent writing a getter/setter methods for every single attribute of the model, you can override the magic methods from the Eloquent class to access them in camelCase style:
class Model extends Eloquent {
public function __get($key)
{
$snake_key = snake_case($key);
return parent::__get($snake_key);
}
public function __set($key, $value)
{
$snake_key = snake_case($key);
parent::__set($snake_key, $value);
}
public function __isset($key)
{
$snake_key = snake_case($key);
return parent::__isset($snake_key);
}
public function __unset($key)
{
$snake_key = snake_case($key);
parent::__unset($snake_key);
}
}
Would a getter method for your attribute help you? If yes:
<?php
class Task extends Eloquent {
public function isDone()
{
return $this->getAttribute('is_done');
}
}
If not, and you really need to access $Task->isDone: try to overwrite the $key in magic _get() method for $key == 'isDone' (and maybe other attributes) and return the parent::_get() with $key:
<?php
class Task extends Eloquent {
public function __get($key)
{
if($key == 'isDone')
$key = 'is_done';
return parent::__get($key);
}
}
And perhaps, your Eloquent needs an attribute mapper for the attribute magic methods ;)
I'm finding out about how CI scopes things a bit late. I've been creating models like this:
$this->load->model('user');
$this->user->load ($user_id);
Then I'd pass around the $this->user object to be able to access all the various things I needed from that object, update properties and such.
I downloaded a Phil Sturgeon CI app callend PyroCMS and I see that he mostly returns data from his object's methods, much like a straight-up procedural function.
So, are models really only supposed to be used at namespaces in CI?
I'm finding that using them the way I am, with a just-now-discovered scope issue, I'm over-writing my models.
Of course the solution is the name it when loading, but that means I have to track and be wary of what name each one of them is using, which is going to be a problem.
Is this how others use the CI models, mainly returning things from them instead of using them as full featured objects?
I found Phil Sturgeon responded to this question: Codeigniter models are just utility classes? with essentially what I need to know. I can still use the loaded model by using the php $object = new Class syntax. I will do this:
class Companies
{
private $_users;
public function __construct ()
{
$this->load->model ('users');
$this->_users = new Users;
}
}
With the private and the new I think I'm safe finally. Probably I should go ahead and do that outside of the model, and not in the constructor, then pass it in as a dependency. I had given up on DI.
I think I've talked myself off the ledge.
After 2 years with CI, here's how I've begun to use the models:
// Singleton class to lookup Users and perform other
// tasks not related to one specific user
class User_model extends MY_Model {
public static $CI;
public function __construct()
{
parent::__construct();
self::$CI =& get_instance();
}
public function getByEmail($email)
{
$data = $this->db->where('email', $email)->get('users')->first_row();
if ($data)
{
$user = new User;
return $user->load($data);
}
}
public function getAllUsers()
{
$data = $this->db->get('users')->result();
foreach ($data as &$row)
{
$user = new User;
$row = $user->load($row);
}
return $data;
}
//... other functions that makes sense in a singleton class
}
// Actual user object. Instantiate one for every user you load...
class User {
public function __construct($id)
{
$data = User_model::$CI->db->where('id', $id)->first_row();
$this->load($data);
}
public function load($data)
{
foreach ($data as $k => $v)
{
$this->$k = $v;
}
return $this;
}
}
I want to change a specific record in the database using codeigniter. The url should be like this mysite.com/users/edit/10.
Here the user having id=10 is being edited
users is the controller name and edit is a method.
Usually I do in this way
//code of the rest of controller
.....
function edit(){
$uid =$_REQUEST['uid'];
//database update code
}
...
Where a form is being posted deliberately to change the record
You're not clear at all on what you want, I just can give you some pointers.
In CI, you don't need (don't have to) use superglobals to access url parameters. It has a native system to manage uri segments, which became automatically accessible without the need to call them; they're available as arguments of the method you're accessing.
So, in a url like yours, mysite.com/users/edit/10, you'll have
Controller:
class Users extends CI_Controller {
public function edit($uid)
{
// $uid is automatically passed to this method and is already available
// here you do your operations
//for. ex.
$this->load->model('user_model');
$this->user_model->update_user($uid);
}
}
Model:
class User_model extends CI_Model {
function __construct()
{
parent::__construct();
}
function update_user($id)
{
$this->db->where('id',$id);
$fields = array('field1' => 'value1','field2' => 'value2'...);
$this->db->update('users',$fields);
}
}
If you provide further information I could expand my answer.