bmidget / kohana-formo Goto Github PK
View Code? Open in Web Editor NEWObject-based form handling for Kohana 3.3
Home Page: http://bmidget.github.io/kohana-formo/
Object-based form handling for Kohana 3.3
Home Page: http://bmidget.github.io/kohana-formo/
Formo breaks the bundled API documentation in KO3.
"ReflectionException [ -1 ]: Class formo_render_json_core does not exist"
There isn't currently a good way to make a checkbox checked by default.
I'm thinking an option has "checked" as true:
$options = array
(
'item1' => array
(
'value' => 'somevalue',
'checked' => TRUE,
)
);
In addition to this, the method check
(in the specific checkboxes and bool drivers) to check a field by its alias.
$form->hobbies->check(array('running', 'swimming'));
Allow values to be loaded early. For instance:
$form->load($values)->add('username');
Load should always take precedence over defaults.
Bools need to update the model when checked or unchecked.
Rules, trigger, filters will be added always with the ->rules($rule)
method. It can be an array of rules or a single rule.
Since all validation rules are added via the same method, objects must be passed instead of just arrays.
Like this
$form->rule('email', Formo::rule('not_empty');
Or
$form->rule('username', Formo::rule(':model', 'unique', array('username')));
Or
$rules = array
(
Formo::rule('not_empty'),
Formo::rule(':model', 'unique', array('username'))
);
$form->rules('username', $rules);
Or
$rules = array
(
'email' => Formo::rule('not_empty'),
'email' => Formo::rule('email'),
'username' => Formo::rule('not_empty'),
'username' => Formo::rule(':model', 'unique', array('username'))
);
$form->rules($rules);
A very simple compatibility interface exists for non-full Jelly integration. In this way you can still define normal Validate rules in the model and Formo will interpret them.
Compatibility mode should be turned off when using full integration files.
checkboxes added like so
$form->add('blah','checkbox','xy');
end up with a name value of "form[]", and any values are lost upon submitting.
It happened again, but now with selects. Searches for /html/option
view.
...
'status' => new Field_Enum(array(
'choices' => array('draft', 'review', 'published'),
'default' => 'published',
'driver' => 'select',
'options' => array('Draft'=>'draft', 'Review'=>'review', 'Publish'=>'published'),
)),
'user' => new Field_BelongsTo,
...
Throws for both of them
Kohana_View_Exception [ 0 ]: The requested view /html/option could not be found
SYSPATH\classes\kohana\view.php [ 252 ]
247 */
248 public function set_filename($file)
249 {
250 if (($path = Kohana::find_file('views', $file)) === FALSE)
251 {
252 throw new Kohana_View_Exception('The requested view :file could not be found', array(
253 ':file' => $file,
254 ));
255 }
256
257 // Store the file path locally
$address = Formo::factory()
->add('street')
->add('zip');
$form->add('address', $address);
The items in the subform would be generated in html with the names:
name="address[street]"
name="address[zip]"
Auto-pull related data from Jelly
I use jelly-auth which has a rule: 'not_empty' => array(TRUE),
this rule fails in pseudo_args(), since array_search($search, $params) returns 0 where $search = ':field' and $param = array(TRUE)
should it be array_search($search, $params, TRUE)?
Formo uses this validation message file by default messages/validate.php, currently there is no way to set custome validation messages files like for example if I want to use messages/user/login.php, messages/user/registration.php, etc.
Thank you!!
Enum "choices" should be pulled into Formo options.
This is a simple change, but the container class should only do a few things at all.
The real magic should happen in the individual drivers, and that allows very complicated, custom drivers that do whatever you like.
For sure, val()
needs to be removed from container.
I am getting this error message when running validation with formo:
ErrorException [ Warning ]: Missing argument 2 for Kohana_Validate::max_length()
SYSPATH/classes/kohana/validate.php [ 71 ]
Here is my code
$user = Jelly::factory('user');
$user->subform(array('username', 'password'))
->add('submit', 'submit');
$user->subform->load()->validate();
Thank you for the help
According to the docs
$options = array
(
1 => 'Running',
2 => 'Jumping',
array
(
'alias' => 'swimming',
'value' => 900
)
);
$form->add_group('hobbies', 'select', $options, 2);
Should produce a select field like so:
<select class = "" name = "hobbies">
<option class = "">
</option>
<option class = "" value = "1">Running</option>
<option class = "" value = "2">Jumping</option>
<option class = "" value = "900">swimming</option>
</select>
But instead produces
<select class = "" name = "hobbies">
<option class = ""> </option>
<option class = "" value = "Running">1</option>
<option class = "" value = "Jumping">2</option>
<option class = "" value = "900">swimming</option>
</select>
To get it to work as expected I had to reverse the array so that the value was the option's value and the key was the option text.
I am getting Call to undefined method Model_User::form() when trying to call the form method
public function action_index() {
$user = Jelly::factory('user');
$user->form(array('username', 'password'))
->add('submit', 'submit');
echo $user->form->render('html');
if ($user->load()->sent())
{
try
{
// Data is validated at save
$user->save();
}
catch(Validate_Exception $e)
{
// Do something with $e
}
}
}
I already included the model and the jelly files for the full integration with jelly, It seems like there is no form() function in the module.
Can you please check this out.
Thank you!!
Container shouldn't do any validation. Instead, Formo and Ffield extend Validator, which extends Container.
The render classes, like Formo_Render extend just Container, not Validator.
Attributes stop working:
in the Jelly Model:
$user->form->attr('action', $_SERVER['REQUEST_URI'] );
or to a straight form:
$form = Formo::form()->attr('action', $_SERVER['REQUEST_URI'] );
Use validation exceptions instead of returning TRUE/FALSE
Please add @Package Formo to each file — it would be much easier to navigate in userguide
This is different from ignore. Ignore simply ignores rules inside a field or subform.
But setting render
to FALSE will not render the field. Rules still apply.
$form->$field->set('render', FALSE);
$form->$field->get('render');
Formo validation is returning the field value as "param1" in the validation error messages:
"password must be at least dffgf characters long"
When it should be for example:
"password must be at least 6 characters long"
My user model is the jelly-auth default one and it has this rule:
'password' => new Field_Password(array(
'hash_with' => array(Auth::instance(), 'hash_password'),
'rules' => array(
'not_empty' => array(TRUE),
'max_length' => array(50),
'min_length' => array(6)
)
)),
Thanks!!!
To make things altogether clearer, the API should be changed around a bit. Here are the basics:
Formo - The broadest interface
Formo_Container - Adds the ability to hold multiple fields
Formo_Validator - Formo-style validation
Formo_Form - A form/subform
Formo_Field - A field
Formo_Driver - Drivers for individual forms/subforms
Fomro_ORM - ORM drivers for ORM compatibility
The main change here is using the Formo class as the broad interface. Before it was what will become Formo_Form, and has had to double-act as the broad interface and a form/subform object.
If for instance a field named fax isn't required but also has a phone number formatting rule, it shouldn't throw an error when left empty.
Set editable to FALSE to make view only render the value
$form->$field->set('editable', FALSE);
$form->field->get('editable');
Hi, I am trying to render my user form and I did this simple step bellow but all I get as output is:
open()?>
render('html')?>
render('html')?>
render('html')?>
close()?>
It seems like something is breaking the rendering function. Can you please check and see what is going on.
Here is my simple code:
class Controller_Formo extends Controller_Template {
public function action_index() {
$user = Jelly::select('user', 5);
$user->subform(array('email'))
->add('submit', 'submit');
echo $user->subform->render('html');
}
} // End Serivice Validate Controller
You also have some code typos in your userguide, under the Jelly Integration section. I will create a bug for it.
Thank you!!!
In the docs, this is the correct way to load a Jelly model:
$form = Formo::form()->orm('load', $user);
However, this returns:
ReflectionException [ 0 ]: Method Formo_Driver_Form::orm() does not exist
is there a way to create a form with jelly to save a many-to-many relationship?
Example DB
table users {id, name}
table addresses {id, address, city}
table addresses_users {user_id, address_id}
Form displaying something like
name []
address[]
city[]
Checkbox
Checkboxes
Option
Radio
Radios
Select
In PHP 5.3 short_open_tag
is disabled by default and I think it's also deprecated. All the default views use <?=
, I think this should be changed to <?php echo
for greater compatibility.
Jelly and Kohana's validate are married together a bit too much, IMO.
Field_BelongsTo displays correctly in the form, but on save submits NULL for a new record (and does not change for existing records). Is there anything that needs to be specified manually?
Please see this patch. I think the pesudo params should not substituted before i18n translation.
www/modules/formo/classes/formo/validator/core.php
View file @ 8c67da2... ... @@ -508,13 +508,15 @@ abstract class Formo_Validator_Core extends Formo_Container {
508 508
509 509 $values = Arr::merge(array(':value' => $this->val(), ':field' => $this->alias()), (array) $param_names);
510 510
511 - $message = strtr($message, $values);
512 -
513 511 if (Kohana::config('formo')->translate === TRUE)
514 512 {
515 513 $values[':field'] = __($values[':field']);
516 514 $message = __($message, $values);
517 515 }
516 + else
517 + {
518 + $message = strtr($message, $values);
519 + }
518 520
519 521 return $message;
520 522 }
I observed some utf-8 encoded strings were messed up in output because of htmlentities(). It's used in a few places besides this one:
www/modules/formo/classes/formo/driver/checkbox/core.php
View file @ c22e25e... ... @@ -22,7 +22,7 @@ class Formo_Driver_Checkbox_Core extends Formo_Driver {
22 22 ->set('tag', 'input')
23 23 ->attr('type', 'checkbox')
24 24 ->attr('name', $this->field->parent()->alias().'[]')
25 - ->attr('value', htmlentities($this->render_field->val()));
25 + ->attr('value', HTML::entities($this->render_field->val()));
26 26
27 27 $parent_value = $this->render_field->parent()->val();
28 28
The proposed validate library from Jon Geiger will resolve any need for Formo to handle all validation internally.
The filter happens at render-time and thus this is a more accurate name.
Please update the Jelly Integration section in the userguide since form is no longer used for calling subform, instead you need to use the subform method.
from:
// For the login form, we just need a blank record
$user = Jelly::factory('user');
// We can pull specific parts of the model by using $model->subform() instead of $model->form
$user->subform(array('username', 'password'))
->add('submit', 'submit');
$this->template->content = $user->form->render('html');
// Notice here we are working with just the user form object and not
// just $user->load()->validate. This is because we are working with
// a couple fields and not the entire user model
if ($user->form->load()->validate())
{
if ($user->login())
$this->request->redirect('admin');
$user->form->error('invalid_login');
}
To this.
// For the login form, we just need a blank record
$user = Jelly::factory('user');
// We can pull specific parts of the model by using $model->subform() instead of $model->form
$user->subform(array('username', 'password'))
->add('submit', 'submit');
$this->template->content = $user->subform->render('html');
// Notice here we are working with just the user subform object and not
// just $user->load()->validate. This is because we are working with
// a couple fields and not the entire user model
if ($user->subform->load()->validate())
{
if ($user->login())
$this->request->redirect('admin');
$user->subform->error('invalid_login');
}
and at the very bottom of the same section replace:
$user = Jelly::factory('user');
$user->subq array('email'))
->add('submit', 'submit');
$this->template->content = $user->form->render('html');
// Notice loading and validating against the form and not user
if ($user->form->load()->validate())
{
// This would fail because in a typical user model,
// username and password would at least be required
// for a new record
$user->savew();
}
with this
$user = Jelly::factory('user');
$user->subform array('email'))
->add('submit', 'submit');
$this->template->content = $user->subform->render('html');
// Notice loading and validating against the subform and not user
if ($user->subform->load()->validate())
{
// This would fail because in a typical user model,
// username and password would at least be required
// for a new record
$user->save();
}
Create drivers for dynamic fields and dynamic subforms
I just pulled down the latest revision, but now I get this error.
ErrorException [ Fatal Error ]: Call to undefined method Formo_Driver_Form::find()
MODPATH/formo/classes/formo/driver/core.php [ 94 ]
89 $subform = Formo::factory($alias, $driver);
90
91 foreach ($fields as $field)
92 {
93 // Find each field
94 $field = $this->find($field);
95 // Remember the field's original parent
96 $last_parent = $field->parent();
97
98 // Add the field to the new subform
99 $subform->append($field);
Formo starts validating user model in complete_login function. And fails on password_confirm although we're just updating statistics.
Here's a piece of code I changed to work. But this is awful solution:
protected function complete_login($user)
{
// Update the number of logins
$user->logins += 1;
// Set the last login date
$user->last_login = time();
// TODO: very-very-very bad
$user->form->remove('password_confirm');
// Save the user
try
{
$user->save();
}
catch( Validator_Exception $e)
{
Notices::add('error',$e->getMessage().": ".print_r($user->form->errors(),true));
}
return parent::complete_login($user);
}
Here is default user_model given with jelly-auth:
$meta->name_key('username')
->sorting(array('username' => 'ASC'))
->fields(array(
'id' => new Field_Primary,
'username' => new Field_String(array(
'unique' => TRUE,
'rules' => array(
'not_empty' => NULL,
'max_length' => array(32),
'min_length' => array(3),
'regex' => array('/^[\pL_.-]+$/ui')
)
)),
'password' => new Field_Password(array(
'hash_with' => array(Auth::instance(), 'hash_password'),
'rules' => array(
'not_empty' => NULL,
'max_length' => array(50),
'min_length' => array(6)
)
)),
'password_confirm' => new Field_Password(array(
'in_db' => FALSE,
'callbacks' => array(
'matches' => array('Model_Auth_User', '_check_password_matches')
),
'rules' => array(
'not_empty' => NULL,
'max_length' => array(50),
'min_length' => array(6)
)
)),
'email' => new Field_Email(array(
'unique' => TRUE
)),
'logins' => new Field_Integer(array(
'default' => 0
)),
'last_login' => new Field_Timestamp,
'tokens' => new Field_HasMany(array(
'foreign' => 'user_token'
)),
'roles' => new Field_ManyToMany
));
I think there is problem with model definition.
I am getting this error message by simple doing the fallowing that shows in the guide. Any ideas to fix it.
ErrorException [ Warning ]: call_user_func_array() expects parameter 1 to be a valid callback, class 'Ffield' does not have a method 'callback'
MODPATH/formo/classes/formo/core.php [ 106 ]
class Controller_Formo extends Controller {
public function action_index() {
$user = Jelly::select('user', 52);
$form = Formo::factory() ->orm('load', $user);
}
}
I manage to fix this error by adding the modifying your compatibility user model file. The role field should be Field_ManyToMany and the name or alias should be 'roles' instead of 'role', this solved the issue.
I also had to add the notes field to my user table for it to completely work. Am I correct with these changes or I was just missing something.
Thank you!
My vesion of Jelly should be 0.9.6.2
Jelly::factory($this->model)->form->render('html');
Jelly::factory($this->model)->subform(array('title','body'))->render('html');
Anyone of these throws «ErrorException [ Fatal Error ]: Call to a member function primary_key() on a non-object» in MODPATH\jelly\classes\jelly\core.php [ 341 ]. I debugged a bit and it seems that meta_alias function gets false instead of Jelly_Meta object.
Is there any way for these modules to work? Or what version of Jelly should i use?
I am getting this error message by simple doing the fallowing that shows in the guide. Any ideas to fix it.
ErrorException [ Warning ]: call_user_func_array() expects parameter 1 to be a valid callback, class 'Ffield' does not have a method 'callback'
MODPATH/formo/classes/formo/core.php [ 106 ]
class Controller_Formo extends Controller {
public function action_index()
{
$user = Jelly::select('user', 52);
$form = Formo::factory() ->orm('load', $user);
}
}
The following creates 2 select boxes. One for the enum and the other for the relation. However, they are just the empty select boxes. What am I doing wrong?
$user = Jelly::select('user', 1);
$form = Formo::form()->orm->load($user);
Jelly Object User
$meta->table('users')
->fields(array(
'id' => new Field_Primary,
'name' => new Field_String,
'status' => new Field_Enum(array(
'choices' => array('dead','alive'))),
'mom' => new Field_BelongsTo(array(
'foreign' => 'mom',
'column' => 'id',
)),
));
Jelly Object Mom
$meta->table('moms')
->fields(array(
'id' => new Field_Primary,
'first_name' => new Field_String,
'last_name' => new Field_String,
));
There are two places where "Container" class is mentioned:
It seems like "Container" should be replaced by "Formo_Container".
Not overdone with some convention but useable out of the box to make appropriate styling.
Add ost filtering to the pre_render area of drivers
Jelly is changing things up for the better for its 1.0 release.
I need to make Formo work with that version of Jelly. Since both will be using the same library and rules for validation, this will change Kohana-Formo-Jelly a bit.
As Formo progresses toward its 1.0 mark, I wanted address a couple things:
I expect this to be marginally controversial.
In my opinion, this will be a much cleaner, language-agnostic solution for creating actual view files instead of the current method of passing the render object to the view. I'm actually quite excited about this, though you will ultimately lose the ability to work with field objects with methods like $field->attr('id', 'someId')
, for instance.
The nice thing about KOstache is you will not have to use it for the rest of the site if you don't want to.
Formo will not reach the 1.0 mark until Kohana implements Jon Geiger's (Validate changes)[http://dev.kohanaframework.org/issues/2966]. At that point Formo will use the validate library for all its validation.
The only difference here is Formo will not actually handle the validation. Syntax for setting rules, etc will be mostly the same. But you will catch Validate_Exception
instead of Validator_Exception
.
Formo will not reach the 1.0 mark until Jelly reaches the same point. The reason is I want to support Jelly out of the box and let the community expand into other ORM drivers. At this point I personally do not have any interest in Kohana's stock ORM module.
I'm currently working on the implementation. All fields will be namespaced all the time. That's just how Formo will work.
This is another issue that's been sitting unfinished for quite awhile. I am barely into this as well, but the specs are drawn. The way this works is you create a subform that is a template form. The template contains a field or fields and rules/filters/etc. that are projected onto any items added to the template subform.
The idea is you could easily add a dynamic field like "tags[]" that you can keep adding a tag, but likewise you could add an entire dynamic subform from a model definition.
Coupled with a bit of javascript, this will transform how I personally deal with forms and I can't wait for how much time this will save me
Finally, the 1.0 tag will be coupled with a playground demo site. While I hope to keep excellent documentation, I still get many, many people asking for examples of Formo in use. The playground demo will demonstrate the basics of form creation & manipulation, orm integration, and I'm most excited about dynamic field demonstrations coupled with orm integration.
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.