I would like to know which is the functionality of the $_table_columns array on a KOHANA model.
I ask this since the table's columns are loaded by introspection, what is the use of this array, is it for default values to the properties?
$_table_columns reflects your table column structure. So if your table has 3 columns (id, name, desc), $_table_columns will be setup to array('id' => '', 'name' => '', 'desc' => '').
By default $_table_columns is an empty array. When you extend ORM with your class and don't override $_table_columns, it will be automatically filled by ORM by calling SHOW FULL COLUMNS FROM table_name command. If you want to avoid this additional DB call, you can initialize $_table_columns on your own:
class Model_User extends ORM {
protected $_table_columns = array('id' => '', 'name' => '', 'desc' => '');
}
Check here for more details.
Related
I am a newbie in YII2 and started learning this on my own. Recently I was working on YII2 models. While learning some pre built model files I noticed that some model files are extends through yii\base\Model where as some from \yii\db\ActiveRecord.
So I want to know the reason when one should use active records and when model i.e. we can do the query in model too so why is there need of active records. Which are the tasks can be done by active records but not by models. In simple words I want to know specific work of both model and active records.
ActiveRecord is a Model that uses a database engine to store the model(s) data.
yii\base\Model is a Model that does not specify how the data is being stored.
Eg a Model could be without a data table and have the actual data stored inside the class code instead of a database. A good example is in the yii2-basic app - the User model here.
I has the data stored in the class code as:
private static $users = [
'100' => [
'id' => '100',
'username' => 'admin',
'password' => 'admin',
'authKey' => 'test100key',
'accessToken' => '100-token',
],
'101' => [
'id' => '101',
'username' => 'demo',
'password' => 'demo',
'authKey' => 'test101key',
'accessToken' => '101-token',
],
];
Active records use for working with data tables and forms, but yii\base\Models for only for forms.
My purpose is to update if the value exists, else inserts a new row in the database table after submitting the form.
The problem is, the function here adds new columns in db table instead of updating them.
Here's my function :
MyModel::updateOrCreate(array(
'myField' => 'myValue',
))
->where('myAutoIncrementalField', '=', '5')
->where('myPrimaryKey', '=', '8');
My database table is like that :
1. myPrimaryKey (not auto incremental and is fillable on model.)
2. myAutoIncrementalField (auto incremental and cannot be fillable on model.)
Thank you in advance.
This is how you use this method:
Model::updateOrCreate(
['primary_key' => 8],
['field' => 'value', 'another_field' => 'another value']
);
As 1st param pass an array of fields that are unique, or in your case, the primary key. Non-unique fields don't make sense here obviously just like passing anything along with the PK.
2nd param is an array of values that should be updated/created too, but being ignored in the unique/pk search.
You cannot use where functions with this method. You have to include the where clauses in the array.
MyModel::updateOrCreate(array(
'myField' => 'myValue',
'myAutoIncrementalField' => '5',
'myPrimaryKey' => '8'
));
I'm pulling data from several remote DataSources, restructuring to fit my models schema and finally passing the array to MyModel::saveAll();
I'd like to avoid importing duplicate records (ie, don't import if MyModel.external_id = 120 & MyModel.external_type = 'basecamp.comment' already exists in db).
What's the most efficient way of going about this?
Sample data:
$data['MyModel'] = [
[
'title' => 'foo',
'created' => '2013-12-18 11:29:06',
'external_id' => 120,
'external_type' => 'github.commit'
],
[
'title' => 'bar',
'created' => '2013-12-18 13:22:06',
'external_id' => 120,
'external_type' => 'basecamp.comment'
]
];
NB: Notice that MyModel.external_id isn't unique on it's own.
This is where validation comes into play. In your MyModel class, add the following:
public $validate = array(
'external_type' => array(
'rule' => 'idAndTypeUnique',
'message' => "Type and ID already exist"
)
);
public function idAndTypeUnique()
{
$existing = $this->find('first', array(
'conditions' => array(
'external_id' => $this->data[$this->name]['external_id'],
'external_type' => $this->data[$this->name]['external_type']
)
));
return (count($existing) == 0);
}
Your saveAll() call would look like:
$this->MyModel->saveAll($data, array('validate' => true));
The easiest way is to make a unique index on those two fields.
alter table my_model add unique index(external_id, external_type);
This forces the constraint in the database level.
If you want to force this constraint in the cake layer, then check this out:
cakephp isUnique for 2 fields?
I already searched many forums for my really strange issue, but I still can't figure out whats going wrong during my save process... The issue: Cake says, my data was saved, creates an autoincrement-ID but no record is stored in the database.
The environment
I have a cake-1.3.13 app running for some time and now needed to add another database table, which is of course related to other tables. My problem is saving records for the habtm-relation table, which looks like this:
CREATE TABLE IF NOT EXISTS `employees_projects_rejectreasons` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`employees_project_id` int(10) unsigned NOT NULL,
`rejectreason_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `employees_project_id` (`employees_project_id`,`rejectreason_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=6;
I scaffolded the simple model only with basic validation criteria.
<?php
class EmployeesProjectsRejectreason extends AppModel {
var $name = 'EmployeesProjectsRejectreason';
var $validate = array(
'employees_project_id' => array(
'numeric' => array(
'rule' => array('numeric'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
'rejectreason_id' => array(
'numeric' => array(
'rule' => array('numeric'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $belongsTo = array(
'EmployeesProject' => array(
'className' => 'EmployeesProject',
'foreignKey' => 'employees_project_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Rejectreason' => array(
'className' => 'Rejectreason',
'foreignKey' => 'rejectreason_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
I created several records for Rejectreasons and EmployeesProjects, so I have some valid entries here in the database. Now I want to link them together by creating a new record in the given employees_projects_rejectreasons table. I try to do this from another controller (the EmployeesProjectsController). Here is my latest attempt to save the data:
$this->EmployeesProject->EmployeesProjectsRejectreason->create();
$eprData = array(
'EmployeesProjectsRejectreason' => array(
'employees_project_id' => (int)$id,
'rejectreason_id' => (int)$rrId
)
);
if($this->EmployeesProject->EmployeesProjectsRejectreason->save($eprData)) {
debug('successfully saved EPR with ID '.$this->EmployeesProject->EmployeesProjectsRejectreason->__insertID);
} else {
debug('could not save EPR with employees_project_id='.$id.' and rejectreason_id='.$rrId);
}
Now what happens
After I make an attempt to save a record, my debug gives me the following success report:
successfully saved EPR with ID 4
So the save() call returned true, a new ID was created by the auto_increment function of mySQL. So far so good. But when I check my database, there was no record created. But the auto_increment_counter was increased by 1, as if a record was stored, but it wasn't.
Running the app with debug-level 2, I can see the generated SQL-statement from cake, which looks perfectly fine to me:
INSERT INTO `employees_projects_rejectreasons` (`employees_project_id`, `rejectreason_id`) VALUES (3, 3)
If I run this statement directly on the sql server, the record ist inserted correctly.
What I already tried
I already tried different approaches with the save procedure. I tried working with setters instead of a data-array:
$this->EmployeesProject->EmployeesProjectsRejectreason->set('employees_project_id', $id);
as well, but it made no difference. After I wrote a custom save-method in the EmployeesProjectsRejectreason-Model, calling it from the controller, but it always produced the same result.
I tried
deleting the model-cache
restarting the server-instances and the server itself
Deleting the table and creating it again
disabling validation in the model
removing the unique foreign-key index
Saving with hard-coded and existing ids as foreign key
Some more strange behaviour
The last tests with hard-coded IDs in my controller code confronted me with more riddles: If I try storing existent foreign_key-IDs, the data is not saved as before. But if both IDs are hardcoded and NOT EXISTING (I used invented IDs 345 AND 567, which are definetely not existing in the database) a record was finally inserted!
Moreover I scaffolded Models, Views and Controllers for the new tables. When I run the scaffolded view "myApp/employees_projects_rejectreasons/add" and add a new record, everything works just fine.
I'm just not able to save the record from other controllers. Since I already have a huge headache, solving this problem, I highly appreciate any hint for a solution!!
Thanks in advance guys!
I finally found a solution to solve the issue. I still don't know, why the save code before did not work, but here is how I changed my code to make it work:
From my form, the data array comes in the following format:
Array
(
[EmployeesProject] => Array
(
[id] => 10
[user_id] => 0
[additional_information] => some comment text
[state] => absage
[Rejectreason] => Array
(
[0] => 1
[1] => 8
)
)
)
I searched for some solutions to save habtm relations in cakePHP directly with one call, but that does not seem to be possible in cake-1.3. So I created this pretty simple save routine in my EmployeesProjectController, which works perfectly fine for me:
if (!empty($this->data)) {
if ($this->EmployeesProject->save($this->data)) {
if(array_key_exists('Rejectreason', $this->data['EmployeesProject'])) {
foreach($this->data['EmployeesProject']['Rejectreason'] as $key => $rrId) {
$this->EmployeesProject->EmployeesProjectsRejectreason->create();
$this->EmployeesProject->EmployeesProjectsRejectreason->set('rejectreason_id', $rrId);
$this->EmployeesProject->EmployeesProjectsRejectreason->set('employees_project_id', $this->data['EmployeesProject']['id']);
if($this->EmployeesProject->EmployeesProjectsRejectreason->save()) {
}
}
}
}
}
Thanks #Yoggi for supporting me solving this issue!
My schema has a column that is of type "bit(1)". I haven't found a way that this can be expressed in Fuel. They don't seem to support the "bit" type and can't properly build insert queries.
Is there a way (possibly undocumented) to get Fuel to support this?
hmm... the orm supposedly accepts the bit field.
i have created a model from database. Look my migration script and model, maybe it can help you.
Model
class Model_Test extends \Orm\Model
{
protected static $_properties = array(
'id',
'whatever',
);
protected static $_table_name = 'tests';
}
Migration script
builded from an existing table using the command: oil refine fromdb:model test
namespace Fuel\Migrations;
class Create_tests
{
public function up()
{
\DBUtil::create_table('tests', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true),
'whatever' => array('type' => 'bit'),
), array('id'));
}
public function down()
{
\DBUtil::drop_table('tests');
}
}
In the controller, you must be need cast the value as INT
$f = Input::post('whatever_post_field');
$o = Model_Test::forge(array('whatever' => (int)$f));
$o->save();