ver | Stable | Develop |
---|---|---|
3.3.x | ||
3.4.x |
kohana / orm Goto Github PK
View Code? Open in Web Editor NEWKohana ORM
Kohana ORM
When creating column names for with(), : is used to join the table and column, the column name now needs to be escape in databases such as Postgres, since : isn't a valid identifier ins ANSI SQL. A possible solution could be to use ___ (3 underscores) as the separator to avoid having to rework many things. A possible patch is included.
:100644 100644 5418cdd... 0000000... M modules/orm/classes/Kohana/ORM.php
diff --git a/modules/orm/classes/Kohana/ORM.php b/modules/orm/classes/Kohana/ORM.php
index 5418cdd..6e900f1 100644
--- a/modules/orm/classes/Kohana/ORM.php
+++ b/modules/orm/classes/Kohana/ORM.php
@@ -849,7 +849,7 @@ class Kohana_ORM extends Model implements serializable {
}
// Split object parts
- $aliases = explode(':', $target_path);
+ $aliases = explode('___', $target_path);
$target = $this;
foreach ($aliases as $alias)
{
@@ -869,7 +869,7 @@ class Kohana_ORM extends Model implements serializable {
// Pop-off top alias to get the parent path (user:photo:tag becomes user:photo - the parent table prefix)
array_pop($aliases);
- $parent_path = implode(':', $aliases);
+ $parent_path = implode('___', $aliases);
if (empty($parent_path))
{
@@ -892,7 +892,7 @@ class Kohana_ORM extends Model implements serializable {
foreach (array_keys($target->_object) as $column)
{
$name = $target_path.'.'.$column;
- $alias = $target_path.':'.$column;
+ $alias = $target_path.'___'.$column;
// Add the prefix so that load_result can determine the relationship
$this->select(array($name, $alias));
@@ -1119,7 +1119,7 @@ class Kohana_ORM extends Model implements serializable {
foreach ($values as $column => $value)
{
- if (strpos($column, ':') === FALSE)
+ if (strpos($column, '___') === FALSE)
{
// Load the value to this model
$this->_object[$column] = $value;
@@ -1127,7 +1127,7 @@ class Kohana_ORM extends Model implements serializable {
else
{
// Column belongs to a related model
- list ($prefix, $column) = explode(':', $column, 2);
+ list ($prefix, $column) = explode('___', $column, 2);
$related[$prefix][$column] = $value;
}
Hi,
having the situation of selecting users having 'admin' role and any of some predefined roles set one can use, for example, next sequence
$admins = ORM::factory('Role')->where('name', '=', 'admin')->find()->customers;
// $rids is an array of predefined roles IDs
$admins
->distinct(TRUE)
->join('customer_role', 'roles_list')->on('roles_list.customer_id', '=', 'user.id')
->where('roles_list.role_id', 'in', $rids);
this produces absolutely perfectly valid SQL:
SELECT DISTINCT `user`.*
FROM `customer` AS `user`
JOIN `customer_role` ON (`customer_role`.`customer_id` = `user`.`id`)
JOIN `customer_role` AS `roles_list` ON (`roles_list`.`customer_id` = `user`.`id`)
WHERE `customer_role`.`role_id` = '2' AND `roles_list`.`role_id` IN (2, 9, 1, 8)
However, if we try to count such admins using $admins->count_all()
this is rendered to wrong sQL like this:
SELECT DISTINCT COUNT(`user`.`id`) AS `records_found`
FROM `customer` AS `user`
JOIN `customer_role` ON (`customer_role`.`customer_id` = `user`.`id`)
JOIN `customer_role` AS `roles_list` ON (`roles_list`.`customer_id` = `user`.`id`)
WHERE `customer_role`.`role_id` = '2' AND `roles_list`.`role_id` IN (2, 9, 1, 8)
Which in turn gives wrong count. It easy to see that we need to have
SELECT COUNT(DISTINCT
user.
id)
instead of
SELECT DISTINCT COUNT(
user.
id)
see https://github.com/kohana/orm/blob/3.3/master/classes/Kohana/ORM.php#L1621
particularly starting from line 1644 (https://github.com/kohana/orm/blob/3.3/master/classes/Kohana/ORM.php#L1644)
Thanks
I have a table with only one column - id.
When I create object and then save them - the following error is occurring:
SQLSTATE[HY000]: General error: 1 near ")": syntax error [ INSERT INTO `attribute_collections` () VALUES ()
I think, that kohana orm does not support to insert record with only 1 column (and this one is primary key).
I think it should be fixed.
Now I make a selection like this:
$count_all = ORM::factory('Advert')
->where('status_id', 'in', [
ORM::factory('Advert_Status')->where('name', '=', 'new')->find(),
ORM::factory('Advert_Status')->where('name', '=', 'moderation')->find(),
])->count_all();
It would be nice to be able to do so:
$count_all = ORM::factory('Advert')
->where('status_id', 'in', ORM::factory('Advert_Status')
->where('name', 'in', ['new', 'moderation'])
->find_all()
)->count_all();
What do you think?
ORM methods are prone to SQL injection
for example method limit($number)
should enforce / cast true natural number, not anything user passes into it.
Same with other functions
Hi after upgrading to PHP 5.6.21 find_all will return objects but _original_values is empty and new values are loaded as _changed so ->pk() function return NULL
$model = new Model_Status ();
$results = $model->find_all ();
foreach ( $results as $result ) {
self::$_table [$result->pk ()] = ( object ) $result->as_array ();
}
object Model_Status(58) {
protected _changed => array(4) (
"id" => string(2) "id"
"name" => string(4) "name"
"code" => string(4) "code"
"message" => string(7) "message"
)
protected _primary_key => string(2) "id"
protected _primary_key_value => NULL
ORM shouldn't rely on magic methods natively but use the methods for setting / getting instead. Examples;
$this->{$name} = $var;
$this->{$key}->values($values[$key], $column);
$this->$column = $values[$column];
$data[$var] = $this->{$var};
$this->{$property} = $value;
This obviously doesn't apply to properties which aren't magic anyway
I have the next code:
class Model_User extends Model_Auth_User
{
protected $_has_one = array(
'profile' => array(
'model' => 'User_Profile',
'foreign_key' => 'user_id'
)
);
protected $_has_many = array(
'user_tokens' => array(
'model' => 'User_Token',
'foreign_key' => 'user_id',
),
'roles' => array(
'model' => 'Role',
'through' => 'roles_users'
)
);
}
So, i can create Model_User node and, for example, a few roles for user by:
public function createUser(array $userData, array $userProfileData, array $roles)
{
// ...
$this->values()->check()->save();
$this->add('roles', $roles);
// ...
}
But, how i can create the profile node? Profile is a simple model, which has user_id as primary key and other non-value data (first_name, last_name of user and etc.).
So, i tried to do this:
public function createUser(array $userData, array $userProfileData, array $roles)
{
// ...
$this->values()->check()->save();
$userId = $this->id;
$userProfileData['user_id'] = $userId;
ORM::factory('User_Profile')->values($userProfileData)->check()->save(); // this
$this->add('roles', $roles);
// ...
}
But in values() method primary_key (user_id) is unsetting! So, i need use this:
ORM::factory('User_Profile')->set('user_id', $userId)->values($userProfileData)->check()->save();
That looks strange, i think. Need to create method as 'add()' (add() for has_many relations) for has_one relation, i think.
By this (title of issue), password of user first hashes (By filter of Model_User (Auth::instance()->hash()), and after them it checks for some rules from rules() method. And, so, min_length, for example, doesn't works.
Hi,
original code of ORM::count_all() looks as:
public function count_all()
{
// remembering select columns
...
$this->_build(Database::SELECT);
...
// Add back in selected columns
$this->_db_pending += $selects;
$this->reset();
// Return the total number of records in a table
return (int) $records;
}
$this->reset(); looks wrong:
we are counting not all records in the table, but those matching the conditions set earlier,
eg. if we have 100 records in total, but only 55 of them do have ref_id = 55 then following code will return 55
$mdl = ORM::factory('Model')->where('ref_id', '=', 55);
echo $mdl->count_all();
so why do we reset builder entirely? Should not we do $this->reset(FALSE);
instead?
thanks
I want to check existing of some relations in my model. So, for example, we take a default User model. So, for check roles we should do this: ORM::factory('User', 1)->has('roles'). If user has at least 1 role, returns TRUE. So, next, i want to check existing of user tokens (remember me checkbox in authorization), so i do this: ORM::factory('User', 1)->has('user_tokens'). And this return me an exception, because it's unknown from which table we should select number of nodes for checking this relation.
So, we have next code in our model:
class Model_User extends Model_Auth_User
{
protected $_has_many = array(
'user_tokens' => array(
'model' => 'User_Token',
'foreign_key' => 'user_id',
),
'roles' => array(
'model' => 'Role',
'through' => 'roles_users'
)
);
}
For correct works of that function (has()) we should add to 'user_tokens' relatio name of table to 'through' key, but, by database conception, this is not correct.
And my second question is: how to check one-to-one relation? For example, i has 'user_profile' table (which contains first_name, last_name, address and other none-value information):
(the same model)
protected $_has_one = array(
'profile' => array(
'model' => 'User_Profile',
'foreign_key' => 'user_id',
)
);
And how can i check this relation? Excepting of this ofc:
ORM::factory('User', 1)->profile->count_all() > 0
So, what can you say, community?
How we know, table (by default) roles_users has 2 fields: role_id, user_id. And primary key in this table (in database level) is bunch of two fields (role_id, user_id). So, in Kohana's ORM not exist that option (I mean: declare primary key using two fields).
For example (in my project, i changed some base names for my convenience (this is default Model for roles_users table) as this:
class Model_Role_UserRef extends ORM
{
protected $_primary_key = array('role_id', 'user_id');
protected $_table_name = 'core_roles_users_ref';
}
Also, about unique fields. In MySQL (for example) we can also use bunch of fields for unique values (for example id and email). So, in Kohana's ORM not exist that option too. But, in Kohana, this rule works just on rules() method (one solve of that problem is: we can catch database exception from MySQL).
This can work just by (for example, of course):
echo ORM::factory('User')->renderForm();
And we see on screen all of fields, relations (selects (one-to-one), multiple checkboxes for many-to-many relations, etc.).
I saw that option in Symfony 1.4 (you declare model class and can render form for insert node to this moel). In Symfony 1.4 you can also generate the whole admin-panel by this options. But, of course, in Symfony 1.4 are Propel and Doctrine ORM conception...
So, i think, but it is the most important thing for framework. So, developers just declare model for table and use some automatic filters, rules, checks and form generating.
Also: need to think about automatic pagination generating for list of ORM data;
For creating user i need to do this actions (insert to users, roles_users and user_profile (first_name, last_name data and some) tables (this is method from Model_User):
public function createUser($userData, $userProfileData, $userRoles = array(Model_Role::ROLE_LOGIN))
{
$db = Database::instance();
$db->begin();
try
{
// `users`
$userData['password'] = Arr::get($userData, 'password', Generate::generatePassword(Generate::PWD_TYPE_6_NUMBERS));
$this->values($userData);
$this->check();
$this->save();
$userId = $this->id;
// `user_profile`
$userProfileId = ORM::factory('User_Profile')->createUserProfile($userId, $userProfileData);
// `roles_users`
$this->add('roles', $userRoles);
// ...
$db->commit();
return $userId;
}
catch(Database_Exception $exception)
{
$exception->getMessage();
$db->rollback();
return FALSE;
}
return FALSE;
}
So, it looks very strong and massive. And if your models are not simple (for creating 1 essence you need to create related nodes in other tables), you already must use the transactions.
I am not really sure, that it is not OK and transactions need into ORM, but we can discuss about that :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.