MVCGrid w/Expander (parent) invoking an MVC Form(child) and loading child record - UPDATED - atk4

My multi-level MVCGrid/MVCForm/MVCGrid saga continues....
I am using nested MVCGrids with expander buttons that invoke MVCForms to perform different data operations. ALL mySQL tables in this process have an "id" data element and that is the primary key for each table. Each mySQL table also has a point to its parent when necessary using _id naming convention. All of the foreign-keys have been setup in mySQL to work this way as well.
The model for the parent is like this:
class Model_uidcontrol extends Model_Table {
public $entity_code='uidcontrol';
public $table_alias='uc';
function init(){
parent::init();
The model for the child is like this:
class Model_uiddetails extends Model_Table {
public $entity_code='uiddetails';
public $table_alias='ud';
function init(){
parent::init();
Each model has its own "id" and a pointer to its parent.
The expander column in the MVCGrid (parent) invokes this child function:
$um=$this->add('MVCForm');
$um->setModel('uiddetails')
->loadData(($_GET['uidcontrol_id']));
I have tried this in the child model:
$this->addRelatedEntity('uc','uidcontrol','uidcontrol_ID');
and this as well:
$this->addField('uidcontrol_id')
->refModel('Model_uidcontrol')
->caption('System Info')
->visible(true);
I've tried each technique separately and together to get child records to be coordinated with the proper parent.
debug() shows this
where
ud.id = '121'
ud.uidcontrol_id = '121'
OK, I understand the $GET and how it works and how that relates to dsql - at least I think I do.
What I can't figure out is how to tell MVCForm to use "ud.uidcontrol_id = '121 " that come
via the $GET when building the dsql for data loading and not use 'ud.id'
In the above example, there is a parent record "uidcontrol" with that id. I forced the 'id' of the child record to be 121 to see if it would pull data and display it in the form. OK, data displays as it should.
When I try this parent whose 'id' = 10, debug() produces this
ud.id = '10'
ud.uidcontrol_id = '10'
and no data is returned. There is a uidcontrol record with id = 10 but the dsql is trying to match to ud.id = 10 as well.
I can post more of what I am working to clarify what I am trying to do if that helps.
Ideally, I would like to tell MVCForm "Hey! Don't use the 'id' data element when building the dsql, use the one I am supplying instead. Problem is, I can't figure out how to do that... but I've learned a bunch along the way. Me thinks that I am probably "over thinking" something here.
Thanks for any suggestions!
Monday Feb 6th Notes:
var_dump($_GET); says:
'id' => string '10' (length=2) <=== uidcontrol.id
'uidcontrol_id' => string '10' (length=2) <=== uidcontrol.id
I write this:
$um->setModel('uiddetails')
->addCondition('uidcontrol_id',($_GET['id']))
->loadData(($_GET['id']));
And the SQL debug shows this being built:
where
ud.id = '10'
ud.uidcontrol_id = '10'
The issue is that I want ONLY " ud.uidcontrol_id = '10' ". Table uiddetails has its own id of 125 and a uidcontrol_id value of 10. As a result of that, the query doesn't return a record.

The loadData method only loads records by their id. To link the "child" model through his referenced record you must use setMasterField or addCondition to instruct the model to filter on the relationship.

Related

cakephp: Use save method , I want to update modified time when data no changed

Please help me solve this problem , thank you very much.
part 1 : data was changed , i use [ $this->abcModel->save($abc);], the abcTable's modified column was changed . ===> that is OK.
Part2 : data was no changed, i also want abcTable's modified column was changed,
How to do deal with ?
(if show me an example, will be more better to understand.)
using version: cakephp 3.3
Cakephp version : cakephp 3.3
$this->Model->touch($data);
[Rf.]
https://book.cakephp.org/3.0/en/orm/behaviors/timestamp.html
Let's Assume that you have a form with following fields.
Name: XYZ
Number :077777777
**save** button.
It has form action edit/update
Case 1: User make changes and save the form.
Case 2: User do not make any changes and saves the form.
In either case, you should call your controller edit(or update) function.
your NAME AND NUMBER fields will be available in your controller and can be accessed via
$this->request->getData() method.
Ideally, you will need two fields for timestamps as below:
'CREATED_ON' and 'UPDATED_ON'
you can use touch method as you mention but in an ideal world it will be better to write a behaviour to your model. it will update timestamp every time you create a new record or make changes/save to the record.
<?php
namespace App\Model\Behavior;
use Cake\ORM\Behavior\TimestampBehavior;
/**
* Modify built in CakePHP's Timestamp class's default config so no configuration is necessary for use in this project.
*/
final class CustomTimestampBehavior extends TimestampBehavior
{
/**
* Default config
*
* These are merged with user-provided config when the behavior is used.
*
* events - an event-name keyed array of which fields to update, and when, for a given event
* possible values for when a field will be updated are "always", "new" or "existing", to set
* the field value always, only when a new record or only when an existing record.
*
* refreshTimestamp - if true (the default) the timestamp used will be the current time when
* the code is executed, to set to an explicit date time value - set refreshTimetamp to false
* and call setTimestamp() on the behavior class before use.
*
* #var array
*/
protected $_defaultConfig = [
'implementedFinders' => [],
'implementedMethods' => [
'timestamp' => 'timestamp',
'touch' => 'touch',
],
'events' => [
'Model.beforeSave' => [
'CREATED_ON' => 'new',
'UPDATED_ON' => 'existing',
]
],
'refreshTimestamp' => true
];
}
and call it from your model table. Something like below:
public function initialize(array $config)
{
parent::initialize($config);
$this
->addBehavior('CustomTimestamp');
This way you don't need to call $this->model->touch($data) manually everytime. The behavior will take care of it whenever it creates or saves.
Ref: https://api.cakephp.org/3.0/class-Cake.ORM.Behavior.TimestampBehavior.html

How to create a lookup in CakePHP

I'm in the process of converting a 10 year old PHP application. After my boss hired a php consultant, he has set up a CakePHP application environment and we are learning as we go. (fun, I know). Also, I come from a javascript/sharepoint background and have not had a lot of php experience.
As a test, I created a basic address table with these fields: firstname, lastname, state, phonenumber. I've been using justice league members as names and other test data to populate my table. Baked it just fine, default bootstrap pages are working.
I decided I wanted to add a dropdown field called current status, and for now just to keep it simple I wanted the choices: alive, dead.I created the column in my address table.
I created a second table called statuses and pointed the status column in my first table to the status table, using the status id as the foriegn key.
Baked my new table and rebaked my old one.
The status drop down does not give my choices of dead or alive, If I click in the field I get an up or down arrow, and based on which one you click, it either increments or decrements by 1. So the first time I click it inserts a 0. If I go up or down, it adds or takes away one.
I'm not sure what I'm doing wrong, I'm guessing there is some additional code I need to add to the MVC?
ok, if this works, then a lot is working :-). Now to the following: set in the Status Model a query like this:
public function getStatus()
{
$opt = $this->Status->find('list', array(...));
return $opt;
}
Then get the list over to the Adress Controller like this:
$this->loadModel('Status');
$opt => $this->Status->getStatus();
$this->set('opt', $opt);
Now you are able to access the $opt in the view file.
Just delete this line in the view:
$opts = array('0' => __('dead'), '1' => __('alive'));
And it should work.
Keep it simple. Ad to your table this row (only to understand how it works): 'status' as typ "tinyint(1)". Then set this in your view file:
$opts = array('0' => __('dead'), '1' => __('alive'));
When you create the inputfield, do it like that:
echo $this->Form->input('Address.status', array('options' => $opts, 'label'
=> __('Status')));
This should work.

How to apply a condition to a specific table in every request on Entity Framework?

I have a many-to-many structure mapped to entity framework. This is a sample of what it looks like:
User UserTag Tag
------- -------- -------
IdUser(PK) IdUserTag(PK) IdTag(PK)
Name IdUser(FK) TagName
Desc IdTag(FK) Active
Now, I needed to exclude from any request of any method the viewing of Tags that were Active=false.
First, I tried doing it manually in every method, like:
public User GetById(int id)
{
var item = UserRepository.GetById(id); //This is just a repository that calls the EF context
//EF automatically maps it to the *UserTags* property
foreach(var tag in item.UserTags)
{
if(tag.Tag.Active == false)
item.UserTags.Remove(tag);
}
}
But it throws the following exception:
The relationship could not be changed because one or more of the foreign-key properties is non-nullable
So, I wanted to know if there's a way to conditionaly filter every request made to a specific table, whether it is select or a join request.
Try this in your GetById method:
var user.UserTags = dbContext.Entry(user)
.Collection(u => u.UserTags)
.Query()
.Where(ut => ut.Active == true)
.ToList();
The supplied code fails because it is attempting to remove items from the data entities not the list. If you want to pass the data entity around instead of the data model, you need to not use Remove. Something like the below (untested should work).
tags = item.UserTags.Where((ut) => ut.Active).ToList();
This line will get you a list of data entities that are active. However, you should really map all of this into a data model (see AutoMapper) and then you would not be removing items from the database.

Symfony Form customize array for entity type

In my Symfony2.6.6 project I have a category entity. I don't know how to say that properly but use the doctrine tree extension to create a tree with the category entity like:
Category 1
Child Category 1
Child Category 2
Category 2
Child Category 3
...
Now when creating the form type for creating a new Category I want to customize the array of the parent field.
The code I use
$builder->add('parent', 'entity', array('class' => 'AcmeBlogBundle:Category', 'property' => 'title'));
generates just an array with all the title as expected. But I want the array values to append a '-' for every level of the tree. Category 1 for example would be '- Category 1' and Child Category 1 would be '-- Child Category 1'. How can I do that?
Sorry if this has been asked before, I don't know how to search for that.
Okay, let's say you have property getLevel() which would return your current item's level. Then in your Category entity file, create a simple method, for example getIndentedTitle thar would return your pre-defined category based on its level.
public function getIndentedTitle() {
return sprintf(
'%s %s',
str_repeat('-', $this->getLevel()),
$this->getTitle()
);
}
The following code will add as many "-" symbols as your current category level and will append its title next to it.
Then in your form builder, you have to specify to use that method:
$builder->add('parent', 'entity', array('class' => 'AcmeBlogBundle:Category', 'property' => 'indentedTitle'));
More info on str_repeat.
Hope you got the idea.

What is the equivalent to getLastInsertId() in Cakephp?

If I do getLastInsertId() immediately after a save(), it works, but otherwise it does not. This is demonstrated in my controller:
function designpage() {
//to create a form Untitled
$this->Form->saveField('name','Untitled Form');
echo $this->Form->getLastInsertId(); //here it works
}
function insertformname() {
echo $this->Form->getLastInsertId(); //this doesnt echo at all
}
Please suggest a way to get the functionality I want.
CakePHP has two methods for getting the last inserted id: Model::getLastInsertID() and Model::getInsertID().
Actually these methods are identical so it really doesn't matter which method you use.
echo $this->ModelName->getInsertID();
echo $this->ModelName->getLastInsertID();
This methods can be found in cake/libs/model/model.php on line 2768
Just use:
$this->Model->id;
In Cake, the last insert id is automatically saved in the id property of the model. So if you just inserted a user via the User model, the last insert id could be accessed via $User->id
id - Value of the primary key ID of
the record that this model is
currently pointing to. Automatically
set after database insertions.
Read more about model properties in the CakePHP API Docs: http://api.cakephp.org/2.5/class-AppModel.html
Edit: I just realized that Model::getLastInsertID() is essentially the same thing as Model->id
After looking at your code more closely, it's hard to tell exactly what you're doing with the different functions and where they exist in the grand scheme of things. This may actually be more of a scope issue. Are you trying to access the last insert id in two different requests?
Can you explain the flow of your application and how it relates to your problem?
You'll need to do an insert (or update, I believe) in order for getLastInsertId() to return a value. Could you paste more code?
If you're calling that function from another controller function, you might also be able to use $this->Form->id to get the value that you want.
Try using this code in your model class (perhaps in AppModel):
function get_sql_insert_id() {
$db =& ConnectionManager::getDataSource($this->useDbConfig);
return $db->lastInsertId();
}
Caveat emptor: MySql's LAST_INSERT_ID() function only works on tables with an AUTO_INCREMENT field (otherwise it only returns 0). If your primary key does not have the AUTO_INCREMENT attribute, that might be the cause of your problems.
this is best way to find out last inserted id.
$this->ModelName->getInsertID();
other way is using
$this->ModelName->find('first',array('order'=>'id DESC'))
There are several methods to get last inserted primary key id while using save method
$this->loadModel('Model');
$this->Model->save($this->data);
This will return last inserted id of the model current model
$this->Model->getLastInsertId();
$this->Model-> getInsertID();
This will return last inserted id of model with given model name
$this->Model->id;
This will return last inserted id of last loaded model
$this->id;
Try to use this code. try to set it to a variable so you can use it in other functions. :)
$variable = $this->ModelName->getLastInsertId();
in PHP native, try this.
$variable = mysqli_insert_id();
This will return last inserted id of last loaded model
$this->id;
This will return last inserted id of model with given model name
$this->Model->id;
This will return last inserted id of the model current model
CakePHP has two methods for getting the last inserted id:
Model::getLastInsertID() and Model::getInsertID().
echo $this->ModelName->getInsertID();
echo $this->ModelName->getLastInsertID();
Below are the options:
echo $this->Registration->id;
echo $this->Registration->getInsertID();
echo $this->Registration->getLastInsertId();
Here, you can replace Registration with your model name.
Thanks
Use this one
function designpage() {
//to create a form Untitled
$this->Form->saveField('name','Untitled Form');
echo $this->Form->id; //here it works
}
You can get last inseted id with many ways.Like Model name is User so best way to fetch the last inserted id is
$this->User->id; // For User Model
You can also use Model function but below code will return last inserted id of model with given model name for this example it will return User model data
$this->User->getLastInsertId();
$this->User->getInsertID();
When you use save(), the last insert ID is set to the model’s $id property. So:
if ($this->Model->save()) {
printf('Last insert ID was %s', $this->Model->id);
}
Each time a save method is called on a model, cake internally calls Model::getLastInsertId() and stores the result into model class attribute id, so after calling save() it is not necessary to call Model::getLastInsertId() or inserId(), as tha value can be directly accessed like this
$id = $this->id;// within a model
$id = $this->{$this->modelName}->id;// in a controller
After insertion of data, we can use following code to get recently added record's id:
$last_insert_id=$this->Model->id;
each time you perform an insert operation on any model, cake internally fetchesthe last insert Id and Sets to Model->id attribute.
so one can access it directly by $Model->id;,
no need to query again for lastInsertId.
I think it works with getLastInsertId() if you use InnoDB Tables in your MySQL Database. You also can use $this->Model->id
$Machinedispatch =
$this->Machinedispatch->find('first',array('order'=>array('Machinedispatch.id DESC')));
Simplest way of finding last inserted row. For me getLastInsertId() this not works.
Actually you are using the getLastInsertId or getInsertId in a wrong manner.
getLastInsertId() is meant to work only after save() method.
It will even not work after a manual insert, as cake engine is storing the mysql_insert_id under $this->_insertID inside the save method which can be retrieved via the getLastInsertId or getInsertId.
Now in your case
$this->Model->id
OR
$this->Model->find('first',array('order'=>'id DESC'))
Will do.
This is interesting, I also stumbled upon this issue. What you asked perhaps how to get the last ID of a certain model regardless of it's state, whether it's just been inserted or not. To further understand what getInsertID does, we need to take a look at the source:
Link 1: http://api20.cakephp.org/view_source/model#line-3375
public function getInsertID() {
return $this->_insertID
}
Yup, that's the only piece of code inside that function. It means that cakephp caches any last inserted ID, instead of retrieve it from the database. That's why you get nothing if you use that function when you haven't done any record creation on the model.
I made a small function to get the last ID of a certain table, but please note that this should not be used as a replacement of getLastID() or getLastInsertID(), since it has an entirely different purpose.
Add the function lastID() to the AppModel as shown below so that it can be used system wide. It has it's limit, which can't be used on model with composite primary key.
class AppModel extends Model {
public function lastID() {
$data = $this->find('first',
array(
'order' => array($this->primaryKey . ' DESC'),
'fields' => array($this->primaryKey)
)
);
return $data[$this->name][$this->primaryKey];
}
}
Original Source : Class Model
In CakePHP you can get it by:
Model::getInsertID() //Returns the ID of the last record this model inserted.
Model::getLastInsertID() //Alias to getInsertID().
$this->Model->field('id', null, 'id DESC')

Resources