$this->setTable() does not work in Model - php

I am new to laravel. I want to change table name to given string in the constructor in model. The code below is what I tried, but it seems not working.
Any suggestion or advice would be appreciated.
Thank you
Model
class Custom extends Model
{
protected $guarded = ['id', 'ct'];
const UPDATED_AT = null;
const CREATED_AT = 'ct';
public function __construct(array $attributes = [], string $tableName = null) {
parent::__construct($attributes);
$this->setTable($tableName);
}
}
Controller
$tableName = 'some string';
$custom = new Custom([], $tableName);
$result = $custom->create($data);

You are only passing one parameter on the constructor function, but it expects 2 params. So, either pass two param, or make the constructor like this-
public function __construct($table = null, $attr = [])
{
$this->setTable($table);
parent::__construct($attributes);
}
But I don't understand why would you do that? The standard practice is create one model per table. You should do that either.

There is no Model::create method. This is magical shenanigans via Model::__call. Calling $custom->create(...) will forward the call to Builder::create which calls Builder::newModelInstance, which in turns calls Model::newInstance. This code does not know about the original model at all, it only knows about the $data attributes. (It is usually called in a static context, like Model::create(...), without an origin instance.)
The easiest workaround for you would be to create a new class deriving from Custom, and have it declare the $table property. This would require one model per table.
class Custom2 extends Custom {
public $table = 'some string';
}

Related

Find class attributes in a trait but ONLY the class' attributes

I am trying to isolate the attributes of an originating class in an included trait. IE The trait should make an array of the names of all the attributes of the class but not the attributes of the trait for use within the trait.
I have tried doing this by extending a class. I have tried using static methods as per PHP: Is it possible to get the name of the class using the trait from within a trait static method? and I am getting nowhere.
I am about to use known attributes in the trait and simply remove them from the attribute array (as I know their names). This is a rather ugly solution but it will work.
Anyone see a better way to do this?
trait FooTrait
{
public $classVariables;
public function classAttributes()
{
$callingClass = get_class($this);
$rawAttributes= $this->$classVariables = get_class_vars($callingClass);
var_dump($rawAttributes);
var_dump($callingClass);
return $rawAttributes;
}
public function info()
{
var_dump($this->classVariables);
}
// manipulate $this -> classVaribales to do generic database operations
}
class Mine
{
use FooTrait;
protected $attrib1;
protected $attrib2;
protected $attrib3;
}
$needed = new Mine;
$needed->classAttributes();
$needed->info();
OUTPUT is attribute 1,2,3 and bar. How do I get just attribute 1, 2, 3?
EDIT: I edited a couple of attributes to try and make it more comprehensible.
UPDATE: This does not work if trait attributes are protected or private. As traits should not be directly referenced ... bit of a deal breaker.
The only way I could find to get the attributes of the trait WITHOUT those of the calling class was to name it as a literal. BUT that limits the scope and so cannot see the private and protected attributes.
I am giving up at this point and will use an array of the names of attributes used in the trait. Not a big problem just massively inelegant.
class ThisClass {
use ThisTrait;
public $classAttribute1 = 3;
public $classAttribute2 = 3;
public $classAttribute3 = 3;
}
trait ThisTrait {
public $traitTrait1 = 3;
public $traitTrait2 = 3;
public $traitTrait3 = 3;
public function classAttributes (){
$traitAttributes = get_class_vars("ThisTrait"); //NB String not variable
$traitAttributes = array_keys ($traitAttributes);
$className = get_class($this); //NB Var = gets class where this called
$classAttributes = get_class_vars($className);
$classAttributes = array_keys($classAttributes);
$classOnly = array_diff($classAttributes, $traitAttributes);
return $classOnly;
}
}
$thisClass = new ThisClass ();
$result = $thisClass -> classAttributes();
var_dump($result);
=========================================
array (size=3)
0 => string 'classAttribute1' (length=15)
1 => string 'classAttribute2' (length=15)
2 => string 'classAttribute3' (length=15)

Robust method for getting the related class instance before saving in the edit form

Using a standard ModelAdmin with two objects with a simple has_one relationship. I wish to access the relating object after clicking "Add HasManyDataObject" while editing a MyDataObject. Included is a real hack that I'm not happy with, but works. Another hack is to scrape the ID out of the URL. Both not good.
class MyModelAdmin extends ModelAdmin {
static $managed_models = array('MyDataObject');
static $url_segment = 'mymodeladmin';
static $menu_title = 'MyModelAdmin';
static $model_importers = array();
}
class MyDataObject extends DataObject {
private static $db = array('Name' => 'Varchar(255)');
private static $has_many = array('HasManyDataObjects' => 'HasManyDataObject');
function getCMSFields() {
$fields = parent::getCMSFields();
Session::set('MyDataObjectID',$this->ID);
Session::save();
return $fields;
}
}
class HasManyDataObject extends DataObject {
private static $db = array('Name' => 'Varchar(255)');
private static $has_one = array('MyDataObject' => 'MyDataObject');
function getCMSFields() {
$fields = parent::getCMSFields();
$myDataObject = MyDataObject::get()->ByID(Session::get('MyDataObjectID'));
return $fields;
}
}
I would expect something to work like this...
$myDataObject = $this->MyDataObject();
...but no.
The frustrating thing is that it does indicate the object as a read only field in the edit form, so it must be available somehow!
All answers greatly appreciated.
I've come across this time and time again. As you've found out, the reason you cannot access the primary model object, is because until your secondary model is saved, then there is no relation between each of these models' DB tables. Ergo, SilverStripe cannot give you the model's instance if it hasn't yet been saved for it to create a DataObject subclass instance out of.
The workaround is as you've discovered, to "scrape" the URL for the primary model's ID and save that state somewhere, e.g. a session or HTML5 localStorage. There are slightly less hacky ways of pulling that ID out though by querying the current controller's SS_HTTPRequest instance using getURL(). You may also get some mileage out of params() - dump it out to see what you have access to. Let the framework aid you in your hacks :-)
Good luck.
There is an old forum thread here that deals with the same problem with various solutions:
http://www.silverstripe.org/community/forums/data-model-questions/show/21517?start=8
Some inject the ParentID via the GridFieldEditForm and some get it from the current Controller params.
Adding and using the following function returns the "parent" object...
public static function GetParentObject($class) {
$obj = null;
$controller = Controller::curr();
if ($controller->request->Param('ModelClass') == $class)
$obj = $class::get()->ByID($controller->request->Param('ID'));
if ($obj)
return $obj;
$url = $_SERVER['REQUEST_URI'];
$start = $class.'/item/';
$end = '/';
$startpos = strpos($url,$start);
$id = null;
if ($startpos != false) {
$startpos += strlen($start);
$endpos = strpos($url,$end,$startpos);
$id = substr($url,$startpos,$endpos - $startpos);
}
return $class::get()->ByID($id);
}

Accessing a database value in a models constructor in Laravel 5.2

I'm attempting to fetch, convert and save a value in a models' constructor in Laravel 5.2. The reason being that it's saved in the database as hex, and I need to convert it to binary pretty often, and would like to do it once and save the result in a class attribute. But I can't seem to be able to fetch the value from $this in the constructor.
Here's a excerpt of what I'm working with, guid is a field in my table.
class Person extends Model {
private $bGuid = null;
public function __construct(array $attributes = []) {
parent::__construct($attributes);
$this->ad = Adldap::getProvider('default');
$this->bGuid = hex2bin($this->guid);
}
public function getName(){
$query = $this->ad->search()->select('cn')->findBy('objectGUID', $this->bGuid);
return $query['attributes']['cn'][0];
}
}
The $this->ad attribute executes as expected, but $this->bGuid does not. Some debugging shows that $this->guid when referenced in the constructor returns null. While if referenced in the getName() method directly works just fine.
My intermediate solution is creating a new function and just call $this->getbGuid(), thus making me a bit more satisfied with the DRY-ness, but it still has to convert it each time it is called.
I would appreciate it if anyone could tell me what's going wrong, so I could improve the code :)
Try to override another method from Model: newFromBuilder().
This is the one that is executed once the data is retrieved from the DB, not the __construct() one:
class Person extends Model {
private $bGuid = null;
public function newFromBuilder($attributes = [], $connection = null)
{
$model = parent::newFromBuilder($attributes, $connection);
$model->bGuid = hex2bin($model->guid);
return $model;
}
}
Note, that inside the overridden method you refer to the object as $model (instead of $this), and it has to return the $model object at the end.

How to hydrate a custom property in DataMapper PHP constructor based on FK relationship

So I have two objects.
class Product extends DataMapper
{
var $has_many = array('productrating');
public $averageRating = null;
function __construct($id = NULL)
{
parent::__construct($id);
echo "my id: " . $this->id;
}
}
and
class ProductRating extends DataMapper
{
var $table = "product_ratings";
var $has_one = array('product');
function __construct($id = NULL)
{
parent::__construct($id);
}
}
What I would eventually like to accomplish is populate the Product->$averageRating property with, you guessed it, the average rating based on the FK relationship with ProductRatings.
My first thought was to access the relationship, do the math based on the number of ProductRating rows and populate the property inside the constructor. But I'm having issues even accessing the object inside the constructor. This leads me to believe I'm probably going about this the wrong way. How can this be accomplished with DataMapper?
I know the math could be done in the View pages, but I would really like to keep this in the Model if possible.
Ideally I would like this property to be set in the constructor but it was easy enough to add a "getAverageRating" function to the Product class. Accessing the object in this function worked as expected.
public function getAverageRating()
{
$ratings = array();
foreach($this->productrating as $rating)
{
array_push($ratings, $rating->rating);
}
if(count($ratings) > 0)
{
return array_sum($ratings) / $this->productrating->count();
}
return null;
}

Dynamically build a class member variable

I am trying to setup my php (Zend Framework) project through injection dependence. So far when I instanciated a model, I would pass the table and the view (database view) to my model like that:
$table = new My_Table();
$view = new My_View();
$model = new My_Model($table, $view);
All my models extends a Same class that take care of the construction, message handling and getters for forms to interact with the model.
Now I have to inject a model into a model and I was looking for a passive static way of doing this. In my model's parent class I have added a static method inject which is called in the application bootstrap. I pass two string in the form of key => value where the key is the name of the variable that have to be created in the model and the value is the string that represents the class to be instanciated.
My_Model::inject('dependentModel', 'My_Other_Model')
The issue arise when I try to use the key as a new member variable through the following code :
protected function _initDependency()
{
$this->_table = null;
foreach (self::$_staticDependency as $key => $dependency) {
$varName = '_' . $key;
$this->{$$varName} = new $dependency();
}
}
I get the following message
Notice: Undefined variable: _dependentModel
What would be the best way to achieve that, knowing that I want to create my models ignorants of their dependencies?
Use arrays
class Foo {
private $_data = array();
protected function _initDependency()
{
$this->_table = null;
foreach (self::$_staticDependency as $key => $dependency) {
$varName = '_' . $key;
$this->_data[$varName] = new $dependency();
}
}
}
(As a side effect this also removes the variable-variables)
You can use __get(), __set(), __isset() and __unset() to simulate the property-behaviour.
Have you tried to consider any proper ORM like Doctrine2. You save yourself time to reinvent the wheel. Doctrine2 is easy to set up with ZF and there is a lot of information on the net in case you get stuck.

Categories