The function below returns an array with the name of the fields, but I also want to include the data that's in the fields.
How would I do that? I am a newbie to CakePHP.
function init_form($models)
{
foreach($models as $model=> $value)
{
$this->model = new $value;
$columns = $this->model->schema();
//Extract field names from array
$j = 0;
foreach($columns as $col => $val) {
$arr[$value][$j] = $col;
$j++;
}
if(!empty($model))
{
$arr['associated_table'][$value]=$model;
}
}
return $arr;
}
FYI:
I am trying to follow this tutorial
http://bakery.cakephp.org/articles/Gkelly/2006/11/09/report-creator-component
I got it to display the fields name. I am just unable to get the data out.
Thanks
Check out the find() method for retrieving data from your Model.
I am not familiar with the Component you are using. However, considering you have access to the Model with $this->model, you can use it's find() method just as you are schema() - $this->model->find().
Related
Respected Sir/Ma'am, I have different product and I want to create a dynamic $input in controller to save product information into database
Example
$imput['name'] = $request->get('name');
$imput['price'] = $request->get('price');
$imput['description'] = $request->get('description');
To create above input dynamically in controller I try to use foreach loop and pass Input key and value from Frontend side
Example
[["name", "biryani"], ["size", "full"], ["price", "200"], ["description", "chicken + rice"], ["url",
…],…]
0: ["name", "biryani"]
1: ["size", "full"]
2: ["price", "200"]
3: ["description", "chicken + rice"]
4: ["url",…]
5: ["modelName", "chickenBiryani"]
Code i write in controller
(where i do mistake , this code not working also please give answer which I mention in below code comment , Thank You)
public function upload($productInfo)
{
$input=[];
foreach ($productInfo as $data) {
// return $productInfo -- this return data
// return $data -- this return throw error , why this happen
foreach ($data as $val) {
// return $val -- this return data
if ($val[0] == 'modelName') {
$modelName = '\\App\\' . $val[1];
} else {
$input[$val[0]] = $val[1];
}
}
}
$model = new $modelName;
$model::create($input);
return response()->json(['msg' => 'Profile Image Upload Succeessfully']);
}
Please help me sir i am new in Laravel
In your code, you declared $input = [], but using $imput in the loop. That means $input will always be an empty array.
Secondly, Model::create() accepts a single associative array, not multidimensional array e.g:
[
"name" => "Name",
"user_id" => 23
]
Finally, you might need to fletch out your code to eliminate that double loop. But I'm not sure what you're trying to achieve, so can't suggest edits
I would like to ask how it's possible to create a dynamic attribute on the model class. Let's suppose I have a table structure like below code.
Schema::create('materials', function (Blueprint $table) {
$table->increments('id');
$table->string('sp_number');
$table->string('factory');
$table->text('dynamic_fields')->comment('All description of the material will saved as json');
$table->timestamps();
});
I have a column in my table structure named "dynamic_fields" that will hold a JSON string for the fields. An example of JSON structure below.
[
{
"name":"COLOR WAY",
"value":"ASDFF12"
},
{
"name":"DESCRIPTION",
"value":"agg2sd12"
},
{
"name":"REF NUM",
"value":"121312"
}
]
I want to access a field from my dynamic fields, like for example "COLOR WAY".
In my model I want to access the "COLOR WAY" field on the dynamic field like this way
$material->color_way;
Can anybody show me how to do it?
If you know that there will only be certain dynamic fields ahead of time, you could opt to create accessor methods for them. For example, you could add this to your model:
// Dynamic fields must be cast as an array to iterate through them as shown below
protected $casts = [
'dynamic_fields' => 'array'
];
// ...
public function getColorWayAttribute()
{
foreach ($this->dynamic_fields as $field) {
if ($field['name'] === 'COLOR WAY') {
return $field['value'];
}
}
return null;
}
This will allow you to do:
$colorWay = $material->color_way;
Alternatively, if the combinations your dynamic_fields are not limited, there could be a large number of them or you want there to be more flexibility to be able to add more and have them accessible, you could override the getAttribute method of Laravel's model class.
// Dynamic fields must be cast as an array to iterate through them as shown below
protected $casts = [
'dynamic_fields' => 'array'
];
// ...
public function getAttribute($key)
{
$attribute = parent::getAttribute($key);
if ($attribute === null && array_key_exists('dynamic_fields', $this->attributes)) {
foreach ($this->dynamic_fields as $dynamicField) {
$name = $dynamicField['name'];
if (str_replace(' ', '_', mb_strtolower($name)) === $key) {
return $dynamicField['value'];
}
}
}
return $attribute;
}
This approach calls Laravel's implementation of getAttribute which first checks if you have an actual attribute defined, or if you have an accessor defined for the attribute (like in my first suggestion), then checks if a method exists with that name on the base model class and then finally attempts to load a relation if you have one defined.
When each of those approaches fails (null is returned), we then check to see if there's a dynamic_fields attribute in the model. If there is, we loop through each of the dynamic fields (assuming your dynamic_fields is cast as an array), we then convert the name of the defined dynamic field to lowercase and replace spaces with underscores. We then finally check to see if the name we have just derived matches the key provided and if it does, we return the value. If it doesn't, the original $attribute will be returned, which will be null.
This would allow you to get any of your dynamic fields as if they were defined as attributes in the class.
$colorWay = $material->color_way;
$description = $material->description;
$refNum = $material->ref_num;
Please note: I have not tested this code, there could well be an issue or two present. Give it a try and see if it works for you. Also note that this will only work for getting dynamic fields, setting them will require overriding another method.
Try to use this code in your model:
protected $casts = [
'dynamic_fields' => 'array',
];
public function setAttribute($key, $value)
{
if (!$this->getOriginal($key)) {
$this->dynamic_fields[$key] = $value;
}
parent::setAttribute($key, $value);
}
public function getAttribute($key)
{
if (!$this->getOriginal($key)) {
return $this->dynamic_fields[$key]
}
parent::getAttribute($key);
}
In this example, you can get Dynamic Column form Dynamic Model. as well as its Models Relation too
1) first you have to define a table Scope in Model.
private $dynamicTable='';
public function scopeDefineTable($query,$tableName)
{
if( $tableName )
{
$this->dynamicTable= $tableName;
}
else
{
$this->dynamicTable= "deviceLogs_".date('n')."_".date('Y');
}
$query->from( $this->dynamicTable );
$this->table=$this->dynamicTable; # give dynamic table nam to this model.
}
public function scopeCustomSelect( $query ,$items=[])
{
$stu_class_col=['id as stu_class_id','std_id']; // Required else retional model will not retun data. here id and std_id is primary key and foreign key.
$stu_doc_col=['id as stu_doc_id','std_id'];// Required else retional model will not retun data. here id and std_id is primary key and foreign key.
foreach ( $items as $col)
{
if( Schema::hasColumn('student_information', $col ))
{
$stu_info_col[]= $col ;
}
elseif ( Schema::hasColumn('student_class',$col))
{
$stu_class_col[]= $col ;
}
elseif ( Schema::hasColumn('student_image',$col))
{
$stu_doc_col[]= $col ;
}
}
// converting array to string for bind column into with relation...
$stu_class_col_string = implode(',',$stu_class_col);
$stu_doc_col_string = implode(',',$stu_doc_col);
return $colQuery = $query->select($stu_info_col)
->with(["student_class:$stu_class_col_string", "studentImage:$stu_doc_col_string"]);
}
using this you can get data from Rational Model too...
from Controller
$studentInfo = Student::whereHas("student_class",function($q) use($req){
$q->where("std_session",$req->session_code);
$q ->where("std_class",$req->class_code);
$q ->where("std_section",$req->std_section); })
->customSelect($fields['dataList'])
->get();
here I am not using dynamic Model Scope. only Dynamic SustomSelect scope..
I am attempting to log specific actions users are taking on my site and have a listener check if certain entities are being updated, and if so, my goal is to log the fields they are editing, but not all the fields (some are not important or too long).
I have a problem saving the changeset to my database which is why I want to filter for important fields. This works to save the changeset, but when there are several nested arrays within the changeset, the array is not saved correctly (it cuts off after 3 or so arrays within arrays). I am using the array type in postgres. In my postupdate event I have:
if ($entity instanceof ListingQuery) {
$entityManager = $eventArgs->getEntityManager();
$ul = new UserLog();
$uow = $entityManager->getUnitOfWork();
$changeset = $uow->getEntityChangeSet($entity);
$ul = new UserLog();
$ul->setLog($changeset);
$ul->setUser($entity->getUser());
$entityManager->persist($ul);
$entityManager->flush();
}
I've been looking over the docs, but am not really sure how to iterate over the $changeset. It's a multidimension array that can have a variable amount of arrays within based on the number of fields updated. Userlog is a simple entity I have for saving the $changeset and the log field is an array.
I created a function that takes the $changeset and loops through the first three levels of the array, but its not saving the name of the field and only saves the values before and after. How do I access the field names changed in the $changeset?
I think I have a solution that works well. It adds the entity type so it does not match the changeset exactly from Doctrine2, but I think works for my purpose. I found a bunch of other posts form people trying to log specific changes in Doctrine with mixed results so please post if anyone else has a better solution.
public function looparray($arr, $type) {
$recordset[] = array($type);
$keys[] = array_keys($arr);
foreach ($keys as $key) {
if (!is_array($key)) {
if (array_key_exists($key, $arr)) {
$recordset[] = array($key => $arr[$key]);
}
} else {
foreach ($key as $key1) {
if (!is_array([$key1])) {
$recordset[] = array($key1 => $arr[$key1]);
} else {
if (!is_array([$key1])) {
$recordset[] = array($key1 => $arr[$key1]);
} else {
$recordset[] = array($key1 . ' changed ' => $key1);
}
}
}
}
}
return $recordset;
}
I'm trying to save a long form in Codeigniter's Datamapper. I'm able to save the form if I pass the value like this
$t->brandName = $this->input->post('brandName');
$t->specialNotes = $this->input->post('specialNotes');
$t->name = $this->input->post('name');
Now if I call save method it works
$t->save();
Since the form is big I tried to add object values in foreach
$a = get_object_vars($t);
foreach ($a['stored'] as $k => $val){
$t->$k = $this->input->post("$k");
}
however if I call the $t->save() it doesn't work.
I'm not sure what $a['stored'] represents, but it's nothing that's default in Datamapper.
Why don't you do it the opposite way, looping through the post keys?
foreach ($_POST as $key => $val)
{
$t->$key = $this->input->post($key);
}
$t->save();
Note: Any columns that don't exist will just be ignored by Datamapper.
I actually wrote a Datamapper extension for this:
class DM_Data {
function assign_postdata($object, $fields = NULL)
{
// You can pass a different field array if you want
if ( ! $fields)
{
$fields = $object->validation;
}
foreach ($fields as $k => $data)
{
$rules = isset($data['rules']) ? $data['rules'] : array();
if ( ! isset($_POST[$k])) continue;
// Cast value to INT, usually for an empty string.
if (in_array('integer', $rules))
{
$object->$k = (integer) $_POST[$k];
}
// Do other manipulation here if desired
else
{
$object->$k = $_POST[$k];
}
}
return $object;
}
}
You can use $t->assign_postdata()->save(), and optionally pass an array of fields to update to the function (in the datamapper validation format). However, I forget why I use that... but I removed some of the custom stuff. This should be useful for you if you are doing this a lot. It definitely saves me time.
I want to copy a record with all his relations.
I'm trying with:
$o = Doctrine::getTable('Table')->Find(x);
$copy = $object->copy();
$relations = $o->getRelations();
foreach ($relations as $name => $relation) {
$copy->$relation = $object->$relation->copy();
}
$copy->save();
This code doesn't works, but I think it's on the way.
I never could get the deep copy function to operate correctly.
I manually coded a deep copy function for one of my models like this
public function copyAndSave ()
{
$filters = array('id', 'created');
$survey = $this->copy();
$survey->Survey_Entries = new Doctrine_Collection("Survey_Model_Entry");
$survey->Assignment_Assignments = new Doctrine_Collection("Assignment_Model_Assignment");
$survey->Survey_Questions = new Doctrine_Collection("Survey_Model_Question");
$survey->save();
foreach ($this->Survey_Questions as $question)
{
$answers = $question->Survey_Answers;
$newQuestion = $question->copy();
$newQuestion->survey_surveys_id = $survey->id;
$newQuestion->save();
$newAnswers = new Doctrine_Collection("Survey_Model_Answer");
foreach($answers as $answer)
{
$answer = $answer->copy();
$answer->save();
$answer->survey_questions_id = $newQuestion->id;
$newAnswers->add($answer);
}
$newQuestion->Survey_Answers = $newAnswers;
$survey->Survey_Questions->add($newQuestion);
}
return $survey->save();
}
You can read about copy() here. It takes an optional parameter $deep:
$deep
whether to duplicates the objects targeted by the relations
So
$copy = $object->copy(true);
should do it.
Sorry if I'm resurrecting this thread...
I found myself in search of a solution recently where I needed to copy a record and retain the references of the original. A deep copy $record->copy(true) copies the references, which was no good for me. This was my solution:
$record = Doctrine_Core::getTable('Foo')->find(1);
$copy = $record->copy();
foreach($record->getTable()->getRelations() as $relation) {
if ($relation instanceof Doctrine_Relation_Association) {
$ids = array();
foreach ($relation->fetchRelatedFor($record) as $r) {
$ids[] = $r->getId();
}
$copy->link($relation->getAlias(), $ids);
}
}
if ($copy->isValid()) {
$copy->save();
}
Hope this helps :)
This is how i done, but some fix is needed.
$table = $entidade->getTable();
$relations = $table->getRelations();
foreach($relations as $relation => $data) {
try {
$entity->loadReference($relation);
} catch(Exception $e) {
die($e->getMessage());
}
}
I am using Symfony1.4.1 and that uses Doctrine 1.2.1 (I think).
I have been trying to make a function that did all the above myself, when I found one that already exists.
Try this in any function and look at the results:
$tmp=$this->toArray(TRUE);
var_dump($tmp);
$this->refreshRelated();
$tmp=$this->toArray();
var_dump($tmp);
$tmp=$this->toArray(TRUE);
var_dump($tmp);
exit();
I am going to try two different things:
A/ put $this->refreshRelated() into the constructor of all my model objects.
B/ write a function that takes an array depicting the object graph that I want populated. Calling the function refereshRelatedGraph($objectGraphArray). With the right structure of the array (having all the appropriate relation names at each level), I could control which relations get populated and which don't. One use for this is to populate only children, not parent relations. The other is for when a ERD/Schema/ObjectGraph has an element that is 'owned' by more than one object (many to many, other special circumstances that I have), I could control which side of the relationships get pre(non lazy) loaded.