jonathangeiger / kohana-jelly Goto Github PK
View Code? Open in Web Editor NEWSee the link below for the most up-to-date code
Home Page: https://github.com/creatoro/jelly
License: MIT License
See the link below for the most up-to-date code
Home Page: https://github.com/creatoro/jelly
License: MIT License
If you query something using aliases, or even using field name instead of column names, wouldn't you expect as_array() to use this alias or field name as the key in the assoc array, instead of the column name ? If we say that Jelly can totally abstract the database, then you shouldn't have to know the column names when using the array...
Perhaps the query should use AS in such cases... Just thinking and suggesting...
Some of the field views are not xhtml valid: the input-tags aren't closed correctly.
// incorrect xhtml
<input type="text" name="<?php echo $name?>" value="<?php echo date($pretty_format, $value)?>" id="field-<?php echo $name?>">
// correct xhtml
<input type="text" name="<?php echo $name?>" value="<?php echo date($pretty_format, $value)?>" id="field-<?php echo $name?>" />
I don't know how to properly entitle this bug so keep reading.
When you change a many-to-many field, the values are in the _changed
property but it can't be accessed using get()
. get()
will always display the values from the database.
I'm not sure if this is the same with other relationship fields but I'm working with Many-to-Many (user:roles).
This bug becomes apparent when you try to submit a form to edit an object, in my case: a user manager where I change the roles of a user.
If the validation fails, I re-display the form loading the changed values with it from $_POST. Other fields display the changed values, but the many-to-many(select multiple) doesn't. It still loads the values that are from the database.
A simpler code to test this bug is this:
$user = Jelly::select('user')->where('username', '=', 'testuser')->limit(1)->load();
//user currently has roles 1 and 2. let's change it to 3 and 4.
$user->set(array('roles' => array(3,4)));
//this will display role 1 and 2 even if you've already set 3 and 4 as the new roles.
foreach ($user->roles as $role)
{
echo Kohana::debug($role);
}
Thanks!
For example, Datamapper can perform the following using only two queries, where Jelly requires n+1 queries:
zoos = Zoo.all
zoos.each do |zoo|
# on first iteration, DM loads up all of the exhibits for all of the items in zoos
# in 1 query to the data-store.
zoo.exhibits.each do |exhibit|
# n+1 queries in other ORMs, not in DataMapper
puts "Zoo: #{zoo.name}, Exhibit: #{exhibit.name}"
end
end
I commented about this issue as #32. But I guess it deserves an issue on its own.
$user = Jelly::select('user')->load(1);
$admin = Jelly::select('role')->where('name', '=', 'admin')->load();
$user->remove('roles', array($admin));
//this doesn't work too. It deletes everything.
$user->remove('roles', 1);
$user->save();
You fixed #32 and #33 already, that means this isn't related to those 2.
Thanks again!
Is it possible to use labels for all issues? It's easier to read as a user. When their are more issues than now, everyone should see easily if it's a bug, a feature request...
For example:
label "bug" => red
label "feature request" => green
label "to consider" => yellow
maybe "planned", "in progress"
Think about it ;-)
I haven't looked into the code to check the real cause, but it seems that $value
is not passed to the input view if the object is blank or newly instantiated.
**ErrorException [ Notice ]: Undefined variable: value**
<input type="text" name="<?php echo $name?>" value="<?php echo $value ?>" id="field-<?php echo $name?>">
This happens when you use the input() for new objects.
Just found a bug where I'm not allowed to update an object if a unique field was changed but wasn't really changed.
Here's the code:
//this item has a unique field 'title' with value 'Item Title'
$item = Jelly::factory('item')->load($id);
$values = array(
'title' = 'Item Title', //this is exactly the same title.
);
$item->set($values);
try
{
$item->save();
$this->request->response = 'Item Saved!'
}
catch (Validate_Exception $e)
{
Kohana::debug($e->array->errors());
}
Error message says title must be unique. This situation happens when I use $item->set($_POST)
Thanks!
Hey Jonathan, I'm almost done developing the Jelly Auth Driver. Problem is, Jelly seems to suffer the same fatal flaw with Sprig. It hashes values every time a model is saved and loaded.
It's not a problem on saving, but it's a big problem if it hashes an already hashed password from the database. I would have applied the solution from Issue 61 of Sprig but since Jelly's architecture is different, I don't know how to fix this without delving deep into Jelly Core.
I'm working with :
catch (Validate_Exception $e)
{
$errors = $e->array->errors('forms/login/validate');
}
wich gives me:
"Forms/login/validate.email.unique" at the output.
How can it be handled to support a validate message that can be used by i18n?
Like 'unique' => ':field can not be used. Please use another' or something more casual.
Thanks
The error message I am receiving is:
ErrorException [ Notice ]: Undefined variable: model
Line 43 should be changed from:
$meta = Jelly::meta($model);
to:
$meta = Jelly::meta($this->_model);
Thanks for all of your work on Jelly.
How are image handeld?
Thanks
I'm not sure if it's my code, or if it's a bug:
--snipp--
->fields(array(
'id' => new Field_Primary,
'created' => new Field_Timestamp(array(
'auto_now_update' => TRUE,
)),
--snipp--
If I load a record, change some data and call ->save(), the timestamp field isn't updated
I just found this out when I using as_array in Jelly Collections.
Line 43 is currently:
$meta = Jelly::meta($model);
Which will return undefined variable $model. It should be like this:
public function as_array($key = NULL, $value = NULL)
{
if ($this->_model)
{
$meta = Jelly::meta($this->_model);
foreach (array('key', 'value') as $var)
{
if ($field = $meta->fields($$var))
{
$$var = $field->column;
}
}
}
return $this->_result->as_array($key, $value);
}
assigned to : banks
One issue I have had with Sprig which will be the same in Jelly is that models can't be serialized once n:many relations have been loaded since the related objects are stored in a Database_Result object which (in case of MySQL) depends on a result resource.
My solution in Sprig was to implement the magic __sleep method which looped through all related models stored and converted any Database_Result objects into Database_Result_Cached objects. The result then serialised fine.
This is most significant because of the way kohana's auth module works - it serialises the user and then expects to be able to retrieve the user, and their related roles, from the session.
I'm happy to put this in at some point - it is pretty simple.
This needs to be performance tested, but ccazette brought up the fact that the former is most likely faster for large result sets.
Parent doesn't have the select_array() method.
return parent::select_array($columns);
Is it supposed to return just the $columns
? select_array
seems to be found only on Jelly.
If I set through as an array in the model I will get a wrong $this->through. A possible solution would be this:
else
{
// Use the first column as the model
list($model, $col1) = explode('.', $this->through[0]);
list($model, $col2) = explode('.', $this->through[1]);
$this->through = array(
'model' => $model,
'columns' => array($col1, $col2)
);
}
A second solution, and I would recommend this is to change the documentation to use the correct format:
'through' = array(
'model' => 'model',
'columns' => array(
'model:foreign_key'
'foreign:foregn_key'
)
)
and drop the else from the code.
Equivalent of ORM::with()
In this case we will have to be a little bit clever about how the database columns are aliased in the join query so we can allow for loading multiple users with different relationships for example.
Would it be possible to make unique_key
smarter? I'd like to return a different unique key depending on the $key
in load()
.
So I can do this:
Jelly::select('user')->load(1);
and
Jelly::select('user')->load('admin');
And return the same results. If I can override unique_key()
like this, it would be possible. But I need to know the $key being loaded.
public function unique_key($value)
{
if (is_numeric($this->_key))
{
return $this->_meta->primary_key();
}
return 'name';
}
Also, I'm not sure what the $value
is in the unique_key($value)
is for? Can you enlighten me a bit?
Thanks!
In this case, we can use the plan you outline in the PM you sent me. I wonder, though, should behaviors have any special access to the query builder? Your outline doesn't really account for that.
I'm working on some One-To-Many relationships where I wanted to specify the column field of the parent instead of using the defaults.
I'm not really sure if I understand how this should work but here's a sample of my model declaration.
This is the parent
------------------------------------
->fields(array(
'id' => new Field_Primary,
'children' => new Field_HasManny,
'name' => new Field_Slug,
------------------------------------
This is the children
------------------------------------
->fields(array(
'id' => new Field_Primary,
'parent' => new Field_BelongsTo(array(
'column' => 'myparent_id',
)),
'name' => new Field_Slug,
------------------------------------
The error when I access $parent->children Database_Exception [ 1054 ]: Unknown column 'childrentable.parent_id' in WHERE clause
It generates the default which is parent_id
but I want to use myparent_id
as the real column.
_Note: I'm organizing my models into subdirectories so by default, Jelly assumes subdirectory_parent
is to be used as prefixes based on the model's class name. I don't want that so I have to explicitly specify which prefixes/columns/tables to use_
The links return a 404, looks like the extension isn't provided in the link (when I manually add the extension, it works...)
ps. Sorry for the "many" issues :)
Is it possible to set DB-variable for all models instead of doing this for every model in the meta? What I mean is:
A way to set the default DB for all your models (now 'default' hard written in the core)
A way to override this per model (like the API already support)
Why?
It's handy if all the models take the 'default'-db if the environment is IN_PRODUCTION and the 'local' when not.. Now I'm not sure where I can do/set this.
Pulled from the Kohana Forums post titled Jelly 0.9.5 tagged and released
TODO
DONE
Something like
Jelly::select('user', 1)->roles->delete();
Would be equivalent of
Jelly::delete('role')->where('user_id', 'IN', $user_collection->ids())->execute();
This could internally be done by making where('column', '=', $jelly_collection_instance)
map to where('column', 'IN', $jelly_collection_instance->ids())
. This would solve the first part of the eager loading problem simultaneously.
Not sure whether including a delete()
method in Jelly_Collection
is sensible. It breaks the API separation a bit since the collection now has query building. Perhaps make this work instead:
Jelly::delete($collection)->execute();
I encountered this issue while creating Jelly Auth.
When saving objects with relationship, Jelly doesn't seem to pass the new insert_id. So this code wouldn't work because it passes NULL to user_id of roles_users:
$user = Jelly::factory('user');
$login = Jelly::factory('role', 'login');
$admin = Jelly::factory('role', 'admin');
$user->set(array(
'username' => 'raeldc',
'password' => 'testuser',
'password_confirm' => 'testuser',
'email' => '[email protected]',
'roles' => array($login->id, $admin->id)
));
$user->save();
But it will work if I separate the saving of the roles relationship, and save it again.
$user->set(array(
'username' => 'raeldc',
'password' => 'testuser',
'password_confirm' => 'testuser',
'email' => '[email protected]'
));
$user->save();
$user->roles = array($login->id, $admin->id));
$user->save();
I tried other variations like using add(), but same problem, I have to save it twice
Also, notice that I'm manually specifying to pass the ID of $login and $admin models. That's because passing the model objects themselves doesn't seem to work.
Is this an issue or I'm just not getting how things should work?
Regards!
This will be ongoing but at this stage I feel we need to at least cover the basics as throughly as we can, as well as writing a test or adding a data set each time we fix a 'bug' to ensure we don't let it slip though again!
I'm happy to help out with this. I'd like us to be pretty confident that pretty much all of the API works as expected by the tim we get to 1.0.
As discussed
This is a pretty insignificant issue.
I just find it funny that you're using pretty_true
and pretty_false
for Field_Boolean. Why not just 'label_true' and 'label_false' to make it more "formal". :)
Anyway, it's always your choice Jonathan! I'm happy to follow.
Thanks!
Look at my Jelly User Model here.
I have 2 issues that when solved, will make Jelly-Auth Driver fully functional.
#1. Rules expect arrays. If you look at the rules declaration for min_length, max_length, etc, they are just simple integers. But the Validate class expects those values to be arrays. I can make them arrays, but it doesn't seem neat. What I did temporarily was to hack line 1013 of Jelly_Core_Model and make sure that an array is passed to $data->rules.
#2. Callback for password_matches. Sprig-Auth simply does this:
'callbacks' => array(
'matches' => array($this, '_check_password_matches')
),
But since the architecture of Jelly is different, $this is not recognized. What is the best way to do this in Jelly?
Thanks!
See title :)
For all relationship field input views, the iteration is still:
<?php foreach(Jelly::factory($foreign['model'])->load() as $related): ?>
This should be:
<?php foreach(Jelly::select($foreign['model'])->execute() as $related): ?>
This's marginal, but would be nice if the core could follow more the official kohana styling conventions for comparison and parentheses.
http://dev.kohanaphp.com/wiki/kohana2/CodingStyle
if(!$foo) become if( ! $foo)
if (($foo && $bar) || ($b && $c)) usually become if (($foo AND $bar) OR ($b AND $c))
Hi, just a minor issue, the API for the Field class states:
public bool default
Default value
I'm pretty sure that it shouldn't be a boolean.
I saw it now just extend Field_text but nothing special. Is there plan for custimze it to use it for tinyMCE or some other HTML-textarea (in view) and more control for invalid input? Or is this expected for the users to add such a field in the application folder?
Values of 0 are not set for Field_Integer
Values of '' (empty) are not set for Field_String
=> in the final query
Model :
$meta->table('tests')
->fields(array(
'id' => new Field_Primary,
'test_name' => new Field_String,
'ord' => new Field_Integer
));
Controller
$post['test_name'] = 'a name for the this test';
$post['ord'] = '0';
$test = Model::factory('test')
->set(array(
'test_name' => $post['test_name'],
'ord' => $post['ord'],
))->save();
Query
INSERT INTO tests
(test_name
) VALUES ('a name for the this test') (1)
The same occurs if I try to update a record and set the test_name to '' (empty) and the name is actually test3 in the database with id of 5.
Controller
$post['test_name'] = '';
$post['ord'] = '0';
$test = Model::factory('test')
->set(array(
'test_name' => $post['test_name'],
'ord' => $post['ord'],
))->save(5);
Query
No query at all.
Hi Jonathan,
Really like what you're doing here. Although I would like to make one suggestion (for now, anyway). Please use the html:: and form:: helpers instead of views for input() and add a parameter to append attributes the way Sprig does it. That's a a lot simpler when just generating some simple inputs. Most developers will have their own set of views for form elements anyways, so having a whole view-based setup for rendering seems a little redundant and less flexible.
Then again, I might be alone in really liking the way Shadowhand handled that...
I've messaged Banks about this a little while ago, but I've come up with something like a solution.
What I was trying to do is have custom sorting on a specific field. This field is a tinyint with values ranging from 0 to 4. I wanted to sort it like 1,2,3,4,0. To sort this with a regular query, you'd add:
SELECT * FROM `table` ORDER BY FIELD(`field_name`, 1,2,3,4,0)
But I'd like to have this sorting as default in my Jelly model, so I added it in the meta with the sorting method:
$meta->table('table')
->sorting(array(
DB::expr('FIELD(`table`.`field_name`, 1,2,3,0)')
));
// I've used the value part and not the key part of the array, because a class instance is not valid when used as a key
This would result in a false query though:
SELECT * FROM `table` ORDER BY `table`.0 FIELD(`table`.`field_name`, 1,2,3,0)
I've made 2 changes in Jelly_Builder_Core to get it work:
In the method 'order_by', I've added:
public function order_by($column, $direction = NULL)
{
// Swap the column and direction only when using a Database_Expression for sorting
if (is_int($column) AND $direction instanceof Database_Expression)
{
$column = $direction;
$direction = NULL;
}
return parent::order_by($this->_column($column, TRUE), $direction);
}
Another change in the same file :
protected function _column($field, $join = TRUE, $value = NULL)
{
// Return the field if this is a Database_Expression
if ($field instanceof Database_Expression)
{
return $field;
}
// etc
Refering to the discussion here:
http://forum.kohanaphp.com/comments.php?DiscussionID=4992&page=2#Comment_35775
object Jelly_Collection(2) {
protected _model => NULL
protected _result => object Database_MySQL_Result(6) {
protected _internal_row => integer 0
protected _query => string(128) "SELECT * FROM `brands` WHERE `brands`.`id` IN (SELECT `products`.`brand_id` FROM `products` WHERE `products`.`category_id` = 19)"
protected _result => resource(mysql result)
protected _total_rows => integer 8
protected _current_row => integer 0
protected _as_object => bool FALSE
}
}
This line
$field = $this->fields($name);
Calls undefined method $this->fields. I think it should have been:
$field = $this->_meta->fields($name);
This is the same as Issue #10.
I think it deserves a new issue.
This is my code:
`
$user = Model::factory('user');
$login = Jelly::select('role')->where('name', '=', 'login')->load();
$admin = Jelly::select('role')->where('name', '=', 'admin')->load();
$user->set(array(
'username' => 'test',
'password' => 'testuser',
'password_confirm' => 'testuser',
'email' => '[email protected]',
'roles' => array($login, $admin),
'logins' => 0,
));
$user->save();
`
This is the error message:
Database_Exception [ 1452 ]: Cannot add or update a child row: a foreign key constraint fails (`kohana3`.`roles_users`, CONSTRAINT `roles_users_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE) [ INSERT INTO `roles_users` (`role_id`, `user_id`) VALUES (NULL, 1), (NULL, 2) ]
The with() method from Field_HasOne is buggy, it doesn't select the correct join fields. It should be:
$join_col1 = $this->model.'.:primary_key';
$join_col2 = $this->foreign['model'].'.'.$this->foreign['column'];
LIne 712 should end with a ":" instead of a ";" I suppose...
As discussed on this thread : http://forum.kohanaphp.com/comments.php?DiscussionID=4713. (see my posts and banks replies)
'name' => new Field_String('name'),
'alternate-name' => 'name',
Would work so that it doesn't matter if you get/update alternate-name or name, it would always deal with 'name'. That's the neatest implementation we could find in that thread. Currently if you want several aliases, you have to create several Fields, so your model is getting bloated and updating soon gets messy...
I don't know if it's possible but I should be a lot clear if Paul Banks pushed his changes with his github-account instead of a personal account. I think that's the reason why when you click on "network" you can't see the branch from paul_banks.. As a follower of this project it's nice (and cool) to see what's been done, merged, ... and where every developer branch is over the "master", were it's get merged ...
Don't feel required to do this but it should be cool/nice :)
Keep up the good work!
Currently Field::input() only looks for a view with the same name as the field class.
That means, for example, Field_Email has to have an email.php view which is actually identical to the string.php view.
I think it would be better if Field objects had an $_input_view property that is set manually so that fields can inherit parent's views and only need specify one extra bit of meta data (in the field class) if they need an alternate view.
Would also save on the string manipulation and fetching of class names each time an input was fetched although this isn't really a big deal either way.
In this scenario, Jelly_Field_String would set $_input_view to be 'fields/string' and then Jelly_Field_Email wouldn't have to do anything to use the same input view. If the user wanted different HTML for an email input, they could override Field_Email and set $_input_view to be something else.
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.