Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I need to develop a custom form generator using Laravel.
That means there will be a GUI to select and customise the forms like Registration Form or Booking Form.User should be able to add/edit/delete different form controls, define it as mandatory, etc.
Here I am little confused to handle this in back-end. What is the better way to achieve this?
Or how can I implement a database architecture to use some metadata table which can be used to handle multiple items like Wordpress and is there any built-in Laravel functionalities to handle these meta objects?
And how the insert/update/delete handled in this metadata approach?
Here an insert should have only one row in the meta table. Suppose at the time of user registration, without saving the firstname and lastname in separate rows in the meta table, it should use some objects like this in a single row.
a:3:{s:9:"firstname";s:10:"irshad.far";s:8:"lastname";s:0:"";s:5:"_meta";a:7:{s:2:"ip";s:10:"14.99.80.3";s:9:"confirmip";s:10:"14.99.80.3";s:11:"confirmtime";d:1407932201;s:8:"signupip";s:10:"14.99.80.3";s:10:"signuptime";d:1407932201;s:4:"lang";s:2:"en";s:4:"form";s:7:"unknown";}}
Handling a table of meta data is fairly straight forward using Laravel's Eloquent relations. Let's say you have a users table in your database that contains:
id email password created_at updated_at deleted_at
If you want to keep it simple and not add all sorts of extra data to your users table you could create a meta table and then a link table user_meta to relate the two.
But what if you also have a posts table (as with Wordpress) and your posts also need meta data? Instead of also creating a posts_meta table to link your posts to their meta, we can use Laravels Eloquent relations and create some Polymorphic Relations.
The Database
Here's our setup, along with our users table (above) we have a posts table which has the fields:
id title content created_at updated_at deleted_at
We also have our meta table that follows the guidelines for a polymorphic relation:
id name value metable_id metable_type
//int meta key meta value post/user id resource ie post/user
Using this we could add meta for a post or user to our meta table like this:
id name value metable_id metable_type
------------------------------------------------------
1 nickname Steve 1 User
2 author Steve O 1 Post
All we need to do to grab this info from the database is define the relations in our respective models.
The Models
So now we have our DB ready we need to setup our models (one model for User, one for Post and one for Meta) with our polymorphic relationship. Our User and Post models are both going to use the same function to relate to our Meta model:
User.php
========================================
class User extends Eloquent {
public function meta()
{
return $this->morphMany('Meta', 'metable');
}
}
Post.php
========================================
class Post extends Eloquent {
public function meta()
{
return $this->morphMany('Meta', 'metable');
}
}
Now we define the inverse of those relations in our meta model:
Meta.php
========================================
class Meta extends Eloquent {
public function metable()
{
return $this->morphTo();
}
}
That's it!
Getting the data
Now all you need to do to get at the meta data for a user or post is:
// Load in a post with an id of 1 and get all it's related meta
$post = Post::find(1);
$meta = $post->meta;
If we were to return the meta object we might see something like:
[{"id":2,"metable_id":1,"metable_type":"Post","name":"author","value":"Steve O"}]
Onwards!
From here you can create helper functions like this one that checks if the meta you're after exists in the results:
public function hasMeta($key)
{
$meta = $this->meta;
foreach ($meta as $item):
if( $item->name == $key ) return true;
endforeach;
return false;
}
// Use it like:
if($post->hasMeta('author')){
// Display author
}
Read more about Laravels Eloquent relationships in the docs here: http://laravel.com/docs/eloquent-relationships
I once did something similar, my approach was to build a mini DB engine where forms are like tables and data is rows:
A form which describes the structure and design of a form:
Form {
id,
title,
layout,
...
}
Fields of the form with types and validation rules
Field {
formId,
name,
type (String, Date, Image, Integer, Double, List, ...),
pattern (Regex validation maybe),
...
}
Inserted data in a form is a row belonging to that form
Row {
id,
formId,
}
Each row is a group of entries to fields of the corresponding form that can be validated following the predefined rules.
Entry {
rowId,
fieldId,
value
}
Type and rules can be regrouped in another object so you can have dynamic types that you can manage.
Lists can have another object that stores choices and type of list (multi-select, mono-select)
Metadataobjects itself would be saved in one table. But performance-wise I think those object should their own data tables.
Approach 1)
These types of forms needs to be predefined and linked to a specific controller. This must be either so that there is only one controller for each type of form like Registeration, and only one user defined metadataobject can be in use at either time. This controller's table parameter would be set to point to a database table created specifically for that metadataobject (or perhaps same table could be migrated according to metadata but then that table should be empty).
Or 2) every metadataobject should have it's own controller created which points to the object's data table.
In each approach routes needs to be created to point to the one controller of each type at use in each time.
One dilemma is how to manage revisions of those objects. Perhaps each object might have a running number postfix, and have their own controllers and data tables created (then it might be easier to migrate even populated tables [then user would be notified on front-end if his action would result in data loss, like for example with deleting a form data field]).
Another part of this project is to create an intelligent generator engine for assembling the HTML, CSS, and JS code according to a metadataobject. The generated code can be saved to reside in the same table as the objects themselves, and when used should be cached in the backend for rendering views.
Such metadataobject must itself have a clever format, so that it composes of predefined pieces of settings which will be converted to functionality by the form generator code.
Related
In a Silverstripe (version 3) model admin, how can I get the collection of fields from a different model so as to add them to this model's admin?
I have tried this using FieldList::addFieldsToTab:
$loremIpsumTab = Tab::create('LoremIpsum');
$fields->fieldByName('Root')->insertAfter('Main', $loremIpsumTab);
$loremIpsumFields = (
$this->LoremIpsum()->getCMSFields()
->fieldByName('Root.Main')->Fields());
$fields->addFieldsToTab('Root.LoremIpsum', $loremIpsumFields);
That creates the tab correctly, but moves the fields incorrectly: all the fields from 'Root.Main' are moved, not only those for the LoremIpsum model.
I had assumed this would interrogate the related LoremIpsum model for its CMS fields:
$this->LoremIpsum()->getCMSFields()
->fieldByName('Root.Main')->Fields()
So how can I move only those fields for the LoremIpsum model?
Hello and welcome to StackOverflow. What do you want to acchieve?
It seems you want to edit a has_one relation dataobject from your other dataobject. There are ready-to-use and tested modules for this scenario, e.g. https://github.com/stevie-mayhew/hasoneedit/tree/3.x , cause even if you manage to display the fields, SilverStripe assumes those values belong to the current model and not to a relation. Then you'll have extra work to save it back etc...
Some fields in your current model and in the LoremIpsum model have the same name, e.g. ID, Title, Created. This causes problems in your code above, cause you can only have one Field for e.g. ID in a Form.
The "hasoneedit" module overcomes this by prefixing the relation's fields.
My Symfony 1.4 application "Edit" menu very slow. When I click on edit link it takes almost 2 minutes to response.
I am using the following function in my module's action.class.php file.
public function executeNew(sfWebRequest $request) {
$this->form = $this->configuration->getForm();
$this->employee_attendance = $this->form->getObject();
}
There is a common pitfall when using automatically generated forms in Symfony. When your form has a field which is a foreign key of a related model then a <select> element is created for this element. All the possible values of the related values are fetched from the database and populated as objects. Then the __toString() method is used on each object to display a user friendly value on the list. If the implementation of this function uses another related object then the relation is read from the database for each object separately.
For example, if you have in your form a field for related object Shift and the __toString method in the Shift class refers to another model, let's say:
function __toString()
{
return sprintf(
'%s - %s',
$this->getShiftType()->getName(),
$this->getName()
);
}
Then the ShiftType will be fetched from the database one by one for each Shift. If your select lists several thousands shifts you will have the same amount of database queries run each time you open the form (not to mention resources needed to hydrate objects).
There are two things that can be done to solve the problem:
usually the related object is set in some other way than being chosen by the user so you can just skip the widget altogether. Something like unset($this['shift_id']); in your form's setup function.
If you do need the select use a specific table method where you will limit the number of elements retrieved from the DB and/or join with any relevant tables (the ShiftType in our example). You can add an option to the widget in your form:
$this->widgetSchema['shift_id']->addOption(
'tableMethod',
'yourFunctionRetrievingJoinedTables'
);
I am new to Symfony2 and building an app based on an existing legacy MySQL schema. I've become familiar with all the Intro docs (The Book etc) but still needing to inderstand some higher level concepts of how to properly use the framework. Trying to get my head around the concept of an entity in terms of how I normally would go about writing SQL queries. I've used the CLI to generate entities for all my existing tables. As an example ... there is a Clients and a Titles entity already. Titles are 'owned by' Clients and the core Symfony annotations have mapped them correctly.
So, given a titles table with many columns of values but only one titles.client_id ... say I want to create a form action in the ClientsController (clients.yml route: /clients/{id}/add_title) that for the given client id in the url will allow the user to enter a title name and have it save a new record into titles with only the titles.name & titles.client_id values ... very simple really.
My question is ... in defining this very simple query (in normal SQL)
INSERT INTO (titles) VALUES (name, client_id)
DO I need to create another entity for titles JUST to work with those 2 specific values?
OR
What is the ideal way to use part of an entity for a specific repository ... in this case just a subset of the titles table (name & client_id)?
Here is the Action method in my Clients Controller:
//use Entity & Form namespaces for BOTH tables;
public function addTitleAction(Request $request)
{
$client_entity = new Clients;
$titles_entity = new Titles;
// generate simple 2 input form with Form\TitlesType
return etc ...
}
You may be able to tell, I also need to figure out how to work with the Form classes but my basic question here is how to generate simple queries from larger Entities and how to call from the Controllers of another Entity/Table Controller. Thx for your help.
To wrap your head around the new concepts, think of an entity as a row returned from your table. Think of a repository as your queries on the table. So you should have a Title entity (not Titles).
INSERT INTO (titles) VALUES (name, client_id)
DO I need to create another entity for titles JUST to work with those
2 specific values?
You'll want to create a new object when creating a new record (think of the new object as a new record that you then save), along the lines of:
$title = new Title();
$title->setClient($client);
$em->persist($title);
I have managed to join 2 of my tables clients and risk_codes to each other where clients.risk_code_id is a foreign key for risk_codes.id.
In my edit view for Clients I ouput a form using the HTML Helper. E.g. to add an input to edit clients.name I would use echo $this->Form->input('name');
Given that risk_codes is a separate table/model how would I output a select dropdown with the options being risk_codes.name and the values being risk_codes.id?
The tables are linked like so:
Client belongsTo RiskCode
RiskCode hasMany Client
In your RiskCode model make sure that displayField is either set to null or name (the latter is one of the defaults):
public $displayField = 'name'; // or null;
In the controller set a list of risk codes for the view:
$this->set('riskCodes', $this->Client->RiskCode->find('list'));
And in the view simply reference the appropriate foreign key field name:
echo $this->Form->input('risk_code_id');
CakePHP will automatically create an appropriate select list, using the models id and displayField field values from the list set as riskCodes.
ps. Many questions like this are answered in the Cookbook, and can also be figured out by using CakePHP to bake the controllers and views.
I'm new to zend framework but have made my first steps with it successfully.
Until now I have created some Zend_Forms which are mapping single records of my model
to the form fields. I have handled the forms with form classes for each case.
This works all very well until now.
Now I have the situation that I have to asign features to a product. Features and products are parts of my application. Features are stored in my database in three tables. For each feature there is one record in the third table.
First is the feature group where the name of the feature group is saved. Every feature should be asigned to a feature group.
Second table is the features table. This table has an foreign key to the feature group and the name of the feature.
Third table is some kind of many-to-many relation which connects features to products. This table has an aditional field which contains an optional value (beside the two foreign keys) for this unique feature of the product.
For example: if the product has a weight of 4,78 kg the value "4,78" is stored in the third table and the label "weight of %s kg" is stored in the second table. The feature group could be something like "physical attributes" had is saved in the first table.
To cut a long story short:
My problem is how to handle the case that I have to create and edit multiple database records in one form. The plan is to have a form with many checkboxes for each for a feature whereby features are thematicaly grouped. Every checkbox should have an aditional text field to input optional values.
you could make a custom form class that extends Zend_Form and use that for you classes.
It could take in the construct instances of your models and construct the form inputs based on that models.
After form validation in your controller you can do
$values = $form->getValues();
and use that array to populate your models again
You can try creating subforms (Zend_Form_SubForm) inside your form class. This can separate fields for different tables. For edition, in your controller, when you pull all the data from the tree tables, you can populate subforms that correspond to the tables.
You can try to extend Zend_Form to create your own elements.
You will be able to write a class that connects to DB to get attributes (features & products).
Assuming you wrote My_Form_Element_Features & My_Form_Element_Products classes, you can do $features = new My_Form_Features(); and then use the base class methods like getValues(), populate(), etc.
You can take a look there to start :
http://framework.zend.com/manual/en/zend.form.elements.html
http://smartycode.com/extending/database-aware-select-elements/
--
To answer to your comment, you can use :
Zend_Form::setElementsBelongTo($array):
More information can be found at Zend_Form Advanced manual page.