GithubHelp home page GithubHelp logo

jonathangeiger / kohana-jelly Goto Github PK

View Code? Open in Web Editor NEW
146.0 146.0 34.0 1.33 MB

See the link below for the most up-to-date code

Home Page: https://github.com/creatoro/jelly

License: MIT License

PHP 100.00%

kohana-jelly's People

Contributors

banks avatar claudiuandrei avatar dewos avatar jerfowler avatar lokaltog avatar smgladkovskiy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

kohana-jelly's Issues

as_array() should take aliases into account

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...

Field views not valid xhtml

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?>" />

Many-To-Many field doesn't "get" changed values 0.9.5.5

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!

Smart lazy-loading of relationships

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 

Many-to-many remove() removes everything 0.9.5.5

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!

Github feature request

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 ;-)

$value in Input Views

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.

Updating a Model with Unique field

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!

Field_Password 'hash_with' is called every time the model is loaded.

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.

_is_unique(Validate $data, $field) error handling and i18n support

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

timestamp field with auto_now_update aren't updated

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

Small Bug in Jelly_Collection_Core->as_array()

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);
}

Support serialising Jelly models with loaded relations

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.

Bug in Line 257 of Jelly_Builder_Core

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.

ManyToMany if through is array, problem

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.

Support loading one-one relations eagerly with join

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.

Feature Request: Smart unique_key()

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!

Support for model behaviors

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.

Jelly_Field $column seems to be ignored 0.9.5.6

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_

Links in banks_dev guide returns 404

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 :)

Setting DB for all the models

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.

Documentation Improvements

Pulled from the Kohana Forums post titled Jelly 0.9.5 tagged and released

TODO

  • Compare and contrast various ways of accomplishing similar tasks, including:
  • deleting multiple records
  • obtaining a Jelly_Model or Jelly_Collection
  • A detailed explanation of the default behavior of models' assumptions regarding table names
  • Interesting or possibly unexpected behaviors
  • example: passing a primary key to select() immediately loads and returns the record
  • example: with() does not work with ManyToMany
  • How to configure Jelly to use a specific DB
  • I know this is not exactly part of Jelly, but a link to the Kohana reference would be good for pure beginners
  • How to reference joined (withable) model columns (after changes for #93)

DONE

  • d53b16b More in-depth description and examples of the meta-alias system
  • be4da92 Handling of field objects (when they filter, detect, translate, etc.)
  • More in-depth documentation beyond the API reference on field default behavior
  • example: Timestamp conversions to / from storage format and when / if this occurs
  • example: Password behavior (do they auto encrypt values, when, etc.)
  • ed2c6ae The difference between execute and load explained
  • 6f51f48 Best practices for recovering $_POST data into a Model
  • Explicit examples showing Arr::extract() best practices

Allow convenient, single query deleting of all models in a collection

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();

Problems on creating new entries with relationships

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!

Beef up unittests

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.

It's Pretty!

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!

Please suggest solutions for Jelly Auth

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!

Some leftover code from Jelly Field Views Jelly 0.9.5.3

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): ?>

CodingStyle

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))

Plans for Field_HTML ?

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?

'0' or '' (empty) values not in query.

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.

Feature Request: html and form helpers instead of views for input()

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...

Custom sorting

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

ManyToMany relationship returns as_array

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
    }
}

Bug in Line 710 of Jelly_Model_Core

This line

$field = $this->fields($name);

Calls undefined method $this->fields. I think it should have been:

$field = $this->_meta->fields($name);

Problem creating new entries with relationships Jelly-0.9.5.1

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) ]

Field_HasOne with() bug

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'];

Support multi-aliasing

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...

Commits with github account

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!

Extending Fields requires duplicate views

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.