I am building an application with cakephp 2.1 and mongodb 2.03 , I am using ishikaway's mongodb datasource
I need to set some default values that would be added to a model , I am doing it like so
<?php
class DynamicFormResponse extends AppModel{
public $useDbConfig = 'mongodb';
public $useTable = 'dynamicFormsResponse';
public $primaryKey = '_id';
public $validate=array();
public $mongoschema = array(
'created' => array('type' => 'datetime'),
'modified' => array('type' => 'datetime'),
'escalation'=>array(
'type'=>"integrer",
"default"=>0
),
"status"=>array(
"type"=>"string",
"default"=>"pending"
),
);
public function setSchema($schema) {
$this->_schema=$schema;
}
public function getSchema(){
return $this->_schema;
}
}
Obviously I cannot set default values directly in MongoDb like MySQL, and obviously since I am asking the question the above method is not working.
Any suggestions on how I can solve this ?
Ps:
This did not help CakePHP - Set Default Field Values in the Model
The documentation is not clear either
Full code available here
EDIT:
I have currently solved this problem by committing an MVC sin,
I am adding the default values in the controller before saving the data with the model
<?php
class DynamicFormResponse extends AppModel {
public $name="DynamicFormResponse";
public $useDbConfig = 'mongodb';
public $useTable = 'dynamicFormResponse';
public $primaryKey = '_id';
public $validate = array();
public function getDefaults(){
$defaultValues=array(
"escalation"=>0,
"status"=>"pending",
"department_id"=>NULL,
"user_agent"=>env("HTTP_USER_AGENT")
);
return $defaultValues;
}
...
...
class DynamicFormsController extends AppController {
...
...
public function getForm($id=null){
...
...
/**
* Set defaults values
*/
foreach ($this->DynamicFormResponse->getDefaults() as $fieldName => $defaultValue) {
if (empty($this-> request-> data[$this-> DynamicFormResponse -> alias][$fieldName]))
$this->request->data[$this-> DynamicFormResponse -> alias][$fieldName] = $defaultValue;
}
/**
* Data Validation
*/
if($this->DynamicFormResponse->save($this->request->data) == true ){
$this->set("ticket_id", $this->DynamicFormResponse->id);
$this->render('ticket_successfully_saved');
return;
}
Is there a better solution ? because that seems like a bad way to do it .
it's not really a mongoDB question but anyways, i suggest you to merge your userdata with your default values in beforeSave().
We declare default values in each Model like this:
public $defaultValues = array(
'report' => 't',
'reportinterval' => '7',
'type' => '0'
);
And merge it in beforeSave():
/**
* Extends beforeSave() to add default values
*
* #param array $options
* #return bool
*/
public function beforeSave($options = array()) {
// Add default values if not set already
foreach ($this->defaultValues as $fieldName => $defaultValue) {
if (empty($this->data[$this->alias][$fieldName]))
$this->data[$this->alias][$fieldName] = $defaultValue;
}
return parent::beforeSave($options);
}
Related
working with Laravel PHP, I have this model with a constructor where i set the attributes:
class NutritionalPlanRow extends Model
{
use HasFactory;
private $nutritional_plan_id;
private $aliment_id;
private $nomeAlimento;
public function __construct($plan = null,
$aliment = null,
array $attributes = array()) {
parent::__construct($attributes);
if($plan){
$this->nutritional_plan()->associate($plan);
$this->nutritional_plan_id = $plan->id;
}
if($aliment){
$this->aliment()->associate($aliment);
$this->aliment_id = $aliment->id;
$this->nomeAlimento = $aliment->nome;
}
}
/**
* Get the plan that owns the row.
*/
public function nutritional_plan()
{
return $this->belongsTo('App\Models\NutritionalPlan');
}
/**
* Get the aliment record associated with the NutritionalPlanRow.
*/
public function aliment()
{
return $this->belongsTo('App\Models\Aliment');
}
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = [];
/**
* Get the value of nomeAlimento
*/
public function getNomeAlimentoAttribute()
{
return $this->nomeAlimento;
}
/**
* Get the value of plan_id
*/
public function getNutritional_Plan_IdAttribute()
{
return $this->nutritional_plan_id;
}
/**
* Get the value of aliment_id
*/
public function getAliment_IdAttribute()
{
return $this->aliment_id;
}
}
Then I have a controller where I initialize the object:
public function addAlimentToPlan(Request $request){
$planId = $request->planId;
$alimentId = $request->alimentId;
$validatedData = Validator::make($request->all(), [
'planId' => ['required'],
'alimentId' => ['required'],
]);
if ($validatedData->fails()) {
return back()->withErrors($validatedData, 'aliment');
}
$plan = NutritionalPlan::find($planId);
$aliment = Aliment::find($alimentId);
$nutritionalPlanRow = new NutritionalPlanRow($plan, $aliment);
Log::info('Nome Alimento '.$nutritionalPlanRow->getNomeAlimentoAttribute());
$nutritionalPlanRow->save(); //
Toastr::success( 'Alimento aggiunto', '',
["positionClass" => "toast-bottom-right",
"closeButton" => "true"]);
return back();
}
The save operation return this error:
SQLSTATE[23502]: Not null violation: 7 ERRORE: null value in column "nomeAlimento" of relation "nutritional_plan_rows"
but logging the $nutritionalPlanRow->getNomeAlimentoAttribute() the attribure is enhanced.
Someone can help me?
Thank you.
In your constructor you have the following line:
$this->nomeAlimento = $aliment->nome;
You believe that this will fill the attribute in the eloquent model, but that is not happening. Normally such an assignment will pass the magic __set method on the model, but not during model/object construction.
You actually assign it to a property on the object, which is later accessible by your log function, but eloquent doesn't know about it. Therefore it is not sent to the database, resulting in a null error (no default value).
You may use the following to set the values in the constructor:
$this->setAttribute('nomeAlimento', $aliment->nome);
This calls the setAttribute function on the eloquent model, the attribute this becomes part of the model.
(Make sure to change also the other line in your constructor where you assign a value to the object)
I'm creating a Restful application, so I'm recieving a POST request that could seem like this
$_POST = array (
'person' => array (
'id' => '1',
'name' => 'John Smith',
'age' => '45',
'city' => array (
'id' => '45',
'name' => 'London',
'country' => 'England',
),
),
);
I would like to save my person model and set its city_id.
I know that the easiest way is to set it manually with $person->city_id = $request['city']['id]; but this way isn't helping me....this code is only an example, in my real code, my model has 15 relationships
Is there any way to make it in a similar such as $person->fill($request);?
My models look like:
City
class City extends Model {
public $timestamps = false;
public $guarded= ['id'];//Used in order to prevent filling from mass assignment
public function people(){
return $this->hasMany('App\Models\Person', 'city_id');
}
}
Person
class Person extends Model {
public $timestamps = false;
public $guarded= ['id'];//Used in order to prevent filling from mass assignment
public function city(){
return $this->belongsTo('App\Models\City', 'city_id');
}
public static function savePerson($request){//Im sending a Request::all() from parameter
$person = isset($request['id']) ? self::find($request['id']) : new self();
$person->fill($request);//This won't work since my $request array is multi dimentional
$person->save();
return $person;
}
}
This is a bit tricky, but you can override fill method in your model, and set deeplyNestedAttributes() for storing attributes thats will be looking for in the request
class Person extends Model {
public $timestamps = false;
public $guarded= ['id'];//Used in order to prevent filling from mass assignment
public function city(){
return $this->belongsTo('App\Models\City', 'city_id');
}
public static function savePerson($request){//Im sending a Request::all() from parameter
$person = isset($request['id']) ? self::find($request['id']) : new self();
$person->fill($request);//This won't work since my $request array is multi dimentional
$person->save();
return $person;
}
public function deeplyNestedAttributes()
{
return [
'city_id',
// another attributes
];
}
public function fill(array $attributes = [])
{
$attrs = $attributes;
$nestedAttrs = $this->deeplyNestedAttributes();
foreach ($nestedAttrs as $attr) {
list($relationName, $relationAttr) = explode('_', $attr);
if ( array_key_exists($relationName, $attributes) ) {
if ( array_key_exists($relationAttr, $attributes[$relationName]) ) {
$attrs[$attr] = $attributes[$relationName][$relationAttr];
}
}
}
return parent::fill($attrs);
}
}
In my practice app, I have a table called 'music' with 3 columns - id, title and artist. Whenever I try to insert the input values from the form to the database, a new record is added but only id has a value, title and artist are both null. Below is my model:
<?php namespace app\models;
/**
* This is the model class for table "music".
*
* #property integer $id
* #property string $title
* #property string $artist
*/
class MusicEntry extends \yii\db\ActiveRecord {
public $title;
public $artist;
public $id;
public static function tableName() {
return 'music';
}
public function rules() {
return [
[['title', 'artist'], 'required'],
[['id'], 'safe'],
];
}
} ?>
While my controller action looks like so:
public function actionMusicEntry() {
$model = new MusicEntry ();
if (isset ( $_POST ['MusicEntry'] )) {
$model->load($_POST);
if ($model->save()) {
Yii::$app->session->setFlash ( 'success', 'Model has been saved' );
$this->redirect ( [
'music-entry',
'id' => $model->id
] );
}
}
return $this->render ( 'music-entry', [
'model' => $model
] );
}
I've tried getting the value of artist and title after loading the model using $_POST and it has the values I inputted in the form. Given this, why is the input values saved as null in the database?
After further tweaking, I found the cause of the problem in the model. I had to remove the declaration for $artist and $title. I'm still not sure though why adding those variables caused such problem. Still looking into it.
I'm new to using Traits and having trouble saving the protected attributes of my trait within my eloquent model:
Here is my Route model:
namespace App\Models;
use Eloquent;
class Route extends Eloquent {
use CardTrait {
CardTrait::__construct as __CardConstruct;
}
public $timestamps = false;
protected $table = 'routes';
protected $primaryKey = 'id';
protected $visible = [
'name',
'description'
];
public function __construct(array $attributes = array())
{
$this->__CardConstruct($attributes);
}
//relationships follow
}
and here is the CardTrait trait:
namespace App\Models;
trait CardTrait {
protected $timesAsked;
protected $factor;
protected $nextTime;
public function __construct($attributes = array(), $timesAsked = 0, $factor = 2.5, $nextTime = null)
{
parent::__construct($attributes);
if (is_null($nextTime)) $nextTime = \Carbon::now()->toDateTimeString();
$this->factor = $factor;
$this->nextTime = $nextTime;
$this->timesAsked = $timesAsked;
public function answer($difficulty)
{
if($difficulty < 3)
$this->timesAsked = 1;
}
//other methods follow
}
In my controller I can use:
$route = new Route();
$route->name = "New Name";
$route->description = "New Description";
$route->answer(5);
$route->save();
name and description save fine, and although I have columns for timesAsked, factor and nextTime When I dd($route) I can see
protected 'timesAsked' => int 1
protected 'factor' => float 2.6
protected 'nextTime' => string '2015-04-15 21:36:53' (length=19)
so I know the methods of the Trait are working fine.
My question is how can I save these values with Eloquent so that these can be stored and retrieved from the database?
Thanks in advance.
Eloquent will store values in an internal attributes array. This is what is actually written to the database. It will not write values to the attributes array if they already exist as a data member on the model. Look into the __set and __get magic methods and how they are used in Illuminate/Database/Eloquent/Model
So long story short, remove the protected data members from the model.
This is a class for handling model in Codeigniter app
class MY_Model extends CI_Model {
const DB_TABLE = 'abstract';
const DB_TABLE_PK = 'abstract';
private function update() {
$this->db->update($this::DB_TABLE, $this, $this::DB_TABLE_PK);
}
public function save() {
if (isset($this->{$this::DB_TABLE_PK})) {
$this->update();
}
else {
$this->insert();
}}
And this is a model extended from above class:
class Projects extends MY_Model {
const DB_TABLE = 'projects';
const DB_TABLE_PK = 'project_id';
public $project_id;
public $project_name;
public $project_investment;
public $project_employment;
public $project_province;
public $project_city;
public $project_address;
public $project_estimate;
public $project_duration;
public $project_construction;
}
According to Codeigniter User Guide, i think there is a problem in 3rd parameter of Update query (It just send DB_TABLE_PK name ,in this case 'project_id' ) but since i'm new to OOP , don't know how to fix it .
Codeigniter User Guide :
$this->db->update('mytable', $data, "id = 4");
The function above doe not seem to have the complete WHERE statement for the update()
$this->db->update($this::DB_TABLE, $this, $this::DB_TABLE_PK);
will translate to
UPDATE $this::DB_TABLE SET $this WHERE $this::DB_TABLE_PK
and in your example above $this::DB_TABLE_PK is the name of the key ('project_id'), and not its value.
I would stick with
$this->db->where($this::DB_TABLE_PK, $pk)->update($this::DB_TABLE, $this);
Where $pk is the actual value of your PRIMARY KEY
guide clrearly says
$data_array = array();
$where_array = array();
$this->db->update('table_name', $where_array, $data_array());
so example
$data_array = array('name' => 'Alpha', 'gender' => 'male'); // change column name to "Alpha", and gender column to 'male'
$where_array = array('id' => '4', 'allowed' => '1'); // update row with $data_array where id = 4 and allowed = 1
$this->db->update('person', $where_array, $data_array());
I strongly recommend you to use profiler $this->output->enable_profiler(TRUE); put this anywhere in controller and under your page there will be "profiler" is shows post/get data queries, sessions and all usefull information while developing.
i fixed it :
private function update() {
$value=$this::DB_TABLE_PK;
$this->db->update($this::DB_TABLE, $this, $this::DB_TABLE_PK.' = '.$this->$value);
}