I need to upload images using symfony, but ive not been able to do it using my form...
A simplified model is:
Offer:
columns:
id:
name:
pic:
flyer:
description:
.
.
.
relations:
Picture:
local: pic
foreign: id
type: one
Picture_2:
class: Picture
local: flyer
foreign: id
type: one
Picture:
columns:
id:
path:
name:
.
.
.
Now, im using a form that extends OfferForm, since I need my form to have file widgets instead of a choice widget for the fields 'pic' and 'flyer'. In the saving process, then, i need to create two instances of 'Picture' to create the two Picture objects associated to this Offer.
I have not managed to find good and complete documentation on uploading files... or at least not to my case... every tutorial or article magically uses the $form->save() method, and all goes fine!, but i have had multiple errors while doing this...
this is my form class:
class myOfferForm extends OfferForm {
protected $statusChoices = array(
'A' => 'Active',
'E' => 'Expired',
);
protected $validStatus = array('A','E');
public function configure() {
parent::configure();
$this->setWidgets(array(
'id' => new sfWidgetFormInputHidden(),
'name' => new sfWidgetFormInputText(),
'picFile' => new sfWidgetFormInputFileEditable(array(
'file_src' => $this->getObject()->getPicFileSrc(),
'is_image' => true,
'with_delete' => !is_null($this->getObject()->getPicFileSrc())
)),
'flyerFile' => new sfWidgetFormInputFileEditable(array(
'file_src' => $this->getObject()->getFlyerFileSrc(),
'is_image' => true,
'with_delete' => !is_null($this->getObject()->getFlyerFileSrc())
)),
'from' => new sfWidgetFormDate(array(
'format' => '%day%/%month%/%year%',
'can_be_empty' => false,
'default' => date('Y/m/d')
)),
'to' => new sfWidgetFormDate(array(
'format' => '%day%/%month%/%year%',
'can_be_empty' => false,
'default' => date('Y/m/d')
)),
'description' => new sfWidgetFormTextarea(),
'status' => new sfWidgetFormChoice(array(
'choices' => $this->statusChoices)),
'products' => new sfWidgetFormDoctrineChoice(array(
'model' => 'Product',
'table_method' => 'getActivesOrderedByName',
'add_empty' => 'Check associated products',
'multiple' => true,
)
),
));
$this->widgetSchema->setLabels(array(
'id' => '',
'name' => 'Name *:',
'picFile' => 'Picture *:',
'flyerFile' => 'Flyer *:',
'from' => 'Valid From *:',
'to' => 'Valid To *:',
'description' => 'Description :',
'status' => 'Status *:',
'products' => 'Associated Products :',
));
$this->setValidators(array(
'id' => new sfValidatorChoice(array(
'choices' => array($this->getObject()->get('id')),
'empty_value' => $this->getObject()->get('id'),
'required' => false,
)),
'name' => new sfValidatorString(),
'picFile' => new sfValidatorFile(array(
'required' => false,
'mime_types' => 'web_images',
'path' => WebPromocion::getStaticDirPath().'/',
'validated_file_class' => 'OfferValidatedFile',
)),
'flyerFile' => new sfValidatorFile(array(
'required' => false,
'mime_types' => 'web_images',
'path' => WebPromocion::getStaticDirPath().'/',
'validated_file_class' => 'OfferValidatedFile',
)),
'from' => new sfValidatorDate(),
'to' => new sfValidatorDate(),
'description' => new sfValidatorString(),
'status' => new sfValidatorChoice(array(
'choices' => $this->validStatus,
'required' => true,
)),
'products' => new sfValidatorDoctrineChoice(array(
'required' => false,
'model' => 'Product',
'column' => 'id',
'multiple' => true, )),
));
$this->validatorSchema['fotoFile_delete'] = new sfValidatorPass();
$this->validatorSchema['flyerFile_delete'] = new sfValidatorPass();
$this->widgetSchema->setIdFormat('offer_form_%s');
$this->widgetSchema->setNameFormat('offer[%s]');
}
}
The OfferValidatedFile class:
class OfferValidatedFile extends sfValidatedFile {
/**
* Generates a random filename for the current file, in case
* it already exists.
*
* #return string A convenient name to represent the current file
*/
public function generateFilename()
{
$filename = $this->getOriginalName().$this->getExtension($this->getOriginalExtension());
if (file_exits(WebPromocion::getStaticDirSrc().$filename)) {
return sha1($this->getOriginalName().rand(11111, 99999)).$this->getExtension($this->getOriginalExtension());
} else {
return $filename;
}
}
}
And, in my action, I am doing, along with other stuff:
$this->form->save()
There is a problem. The Offer object does not have any existing Picture object to be associated with by the time the form is saved....
I think the main problem is that i want to use one form to handle submition of information related to two different objects.
So, what am I doing wrong? what am I not doing? Does someone knows a complete documentation on this subject that i could use? Is there a clean symfonian way to do this?
This documentation is for the version of symfony and doctrine you're using. Unfortunately, rather than outlining initial setup for you, they include an installer script. Note that this type of setup is outlined elsewhere in both 'A Gentle Introduction to Symfony' as well as in other parts of 'More with Symfony' for version 1.4. Fortunately there is also a fairly verbose look at refactoring the script's form class in the first link which I think would benefit you quite a bit as well - It explains the model's processing of the form (Where you appear to be having issues) quite well, which may make debugging a little less mystifying for you.
I recommend giving it a good read. I followed this for a project a few months ago and came out of it without any issues.
Related
Having just arrived at Prestashop 1.5, I am making a very simple module: a video of the week, associated with multiple products that need to appear right next to it.
I decided to start from the Backoffice. Right now, I can view, add, edit and remove all the Video entries but I'm a bit lost on how to map the N-N association between a video and its related products... The lack of documentation isn't helping either.
Any ideas how to pull this off?
Here's a bit of my code, the Video class is defined by:
class Video extends ObjectModel {
public $id_video;
public $title;
public $url;
public $active;
public static $definition = array(
'table' => 'video',
'primary' => 'id_video',
'multilang' => false,
'fields' => array(
'id_video' => array(
'type' => ObjectModel :: TYPE_INT
),
'title' => array(
'type' => ObjectModel :: TYPE_STRING,
'required' => true
),
'url' => array(
'type' => ObjectModel :: TYPE_STRING,
'required' => true
),
'active' => array(
'type' => ObjectModel :: TYPE_BOOL,
'required' => true
)
),
);
(...)
and the AdminVideo class is here:
class AdminVideoController extends ModuleAdminController {
public function __construct()
{
$this->table = 'video';
$this->className = 'Video';
$this->lang = false;
$this->fields_list['id_video'] = array(
'title' => $this->l('ID'),
'align' => 'center',
);
$this->fields_list['title'] = array(
'title' => $this->l('Title'),
'width' => 'auto'
);
$this->fields_list['url'] = array(
'title' => $this->l('URL'),
'width' => 'auto'
);
$this->fields_list['active'] = array(
'title' => $this->l('Active'),
'width' => '70',
'align' => 'center',
'active' => 'status',
'type' => 'bool',
'orderby' => false
);
parent::__construct();
}
public function postProcess()
{
parent::postProcess();
}
public function renderList()
{
$this->addRowAction('edit');
$this->addRowAction('delete');
$this->addRowAction('details');
return parent::renderList();
}
public function renderForm()
{
if (!($obj = $this->loadObject(true)))
return;
$this->fields_form = array(
'legend' => array(
'title' => $this->l('This weeks video'),
'image' => '../img/admin/world.gif'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Nome'),
'name' => 'title',
'size' => 33,
'required' => true,
'desc' => $this->l('Title')
),
array(
'type' => 'text',
'label' => $this->l('URL'),
'name' => 'url',
'size' => 33,
'required' => true,
'desc' => $this->l('Video URL')
),
array(
'type' => 'radio',
'label' => $this->l('Active:'),
'name' => 'active',
'required' => false,
'class' => 't',
'is_bool' => true,
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
'desc' => $this->l('Only one video can be active at any given time')
),
)
);
if (Shop::isFeatureActive())
{
$this->fields_form['input'][] = array(
'type' => 'shop',
'label' => $this->l('Shop association:'),
'name' => 'checkBoxShopAsso',
);
}
$this->fields_form['submit'] = array(
'title' => $this->l(' Save '),
'class' => 'button'
);
if (!($obj = $this->loadObject(true)))
return;
return parent::renderForm();
}
}
One other thing: would it be possible to add a preview of the video inside the backoffice? I tried to echo YouTube's embed code, but it gets inserted even before the header. Is there a clean way of doing this or do I have to use some jQuery trickery? I was basically doing an echo of YT's embed code just before the end of postProcess().
Thanks in advance!
The simplest way to associate the videos to the products is by adding a "products" text field in your "video" table to store a comma separated list of the ids of the associated products (eg.: 1,10,27). Even if it's a bit rudimentary, it should work.
Alternatively, you could use a table like this:
create table video_product (
id_association int not null auto_increment,
id_video int,
id_product int,
primary key (id_association)
);
The problem with this solution is that the PrestaShop ObjectModel core does not provide any method to automatically update or delete the related tables (at least as far as I know), so you have to insert the code to manage the "video_product" table in your "Video" class.
If you want an example of how to do this, you should look at the classes/Product.php script, which manages the product table and all its related tables (categories, tags, features, attachments, etc.).
To have an idea of how the Prestashop database is structured, have a look at the docs/dbmodel.mwb file, which contains the schema of the database; this file can be viewed by using the MySQL Workbench application.
I am new to PyroCMS and am willing to build a Job Site wherein there'll be 2 main users namely, Employers and Job Seekers. In order to allow them to register on the site, I'm using the Streams API from PyroCMS to build the forms. These users will be part of 2 different modules namely the Employer module and the Job Seeker module.
In the details.php file, under the install() function, I want to create multiple streams(database tables). The following code helps us to add a stream:
$this->streams->streams->add_stream();
The following code then helps us to define the fields to be added to the stream:
$this->streams->fields->add_fields($fields);
My concern is how do I add multiple streams like the above ones and add fields to each of them? In other words, how would the syntax
$this->streams->fields->add_fields($fields);
know which stream to add the fields to?
Have a look at the Fields Driver documentation for the Streams API. Fields and streams are separate entities, with no required association between the two. When adding a field you can assign it to a stream like this:
$field = array(
'name' => 'Question',
'slug' => 'question',
'namespace' => 'streams_sample',
'type' => 'text',
'extra' => array('max_length' => 200),
'assign' => 'STREAM_SLUG_GOES_HERE',
'title_column' => true,
'required' => true,
'unique' => true
);
$this->streams->fields->add_field($field);
Or you can create the streams and fields separately, and then assign each field to a stream like this:
$this->streams->fields->assign_field('streams_sample', 'STREAM_SLUG_GOES_HERE', 'question', array('required' => true));
All this talk of fields and streams makes me want to go outside...
You can add multiple streams like this example.
// Add banners streams
if ( ! $this->streams->streams->add_stream(lang('banner:banners'), 'banners', 'banner', 'banner_', null)) return false;
// Add groups streams
if ( ! $this->streams->streams->add_stream(lang('banner:groups'), 'groups', 'banner', 'banner_', null)) return false;
// Add some fields
$fields = array(
// BANNERS
array(
'name' => 'Banner Title',
'slug' => 'banner_title',
'namespace' => 'banner',
'assign' => 'banners',
'type' => 'text',
'extra' => array('max_length' => 200),
'title_column' => true,
'required' => true,
'unique' => true
),
// GROUPS
array(
'name' => 'Group Title',
'slug' => 'group_title',
'namespace' => 'banner',
'assign' => 'groups',
'type' => 'text',
'extra' => array('max_length' => 200),
'title_column' => true,
'required' => true,
'unique' => true
)
);
$this->streams->fields->add_fields($fields);
I want to develop a module that add fields to user profile in drupal 7, like phone number and CV ...
and I don't know how to do that (using Database or using fields API)
pls help me.
Any clear tutorials will be appreciated.
Try to follow the following code
$myField_name = "NEW_FIELD_NAME";
if(!field_info_field($myField_name)) // check if the field already exists.
{
$field = array(
'field_name' => $myField_name,
'type' => 'text',
);
field_create_field($field);
$field_instance = array(
'field_name' => $myField_name,
'entity_type' => 'user', // change this to 'node' to add attach the field to a node
'bundle' => 'user', // if chosen 'node', type here the machine name of the content type. e.g. 'page'
'label' => t('Field Label'),
'description' => t(''),
'widget' => array(
'type' => 'text_textfield',
'weight' => 10,
),
'formatter' => array(
'label' => t('field formatter label'),
'format' => 'text_default'
),
'settings' => array(
)
);
field_create_instance($field_instance);
Hope this works... Muhammad.
I'm trying to make a simple custom field "field_book_year" for the new node type "synopsis_book".
I have wrote in .install file:
function synopsis_install() {
node_types_rebuild();
$types = node_type_get_types();
// In Drupal 7 you must explicitly add a "body" field when you create a custom content type,
// thus the call to node_add_body_field($types['newsletter']);.
node_add_body_field($types['synopsis_book']);
$body_instance = field_info_instance('node', 'body', 'synopsis_book');
$body_instance['type'] = 'text';
field_update_instance($body_instance);
field_create_field(array(
'field_name' => 'field_book_year',
'label' => t('Company posting the job listing'),
'type' => 'text',
'translatable' => TRUE,
)
);
field_create_instance(array(
'field_name' => 'field_book_year',
'label' => t('Company posting the job listing'),
'entity_type' => 'node',
'bundle' => 'synopsis_book',
'type' => 'text',
'widget' => array(
'type' => 'text_textfield',
),
'display' => array(
'example_node_list' => array(
'label' => t('Company posting the job listing'),
'type' => 'text',
),
),
'description' => 'Begin Date',
)
);
}
Then, I have in .module these functions:
function synopsis_node_info()
{$types = node_type_get_types();print_r($types);
return array(
'synopsis_author' => array('name' => t('Author'), 'base' => 'synopsis_author', 'description' => t('Author description, biography etc.'),
'has_body' => true, 'has_title' => true, /*'min_word_count' => 11,*/ 'help' => t('Enter blah-blah-blah'),
'title_label' => t('Author full name')
),
'synopsis_book' => array('name' => t('Book'), 'base' => 'synopsis_book', 'description' => t('Book description, synopsis etc.'),
'has_body' => true, 'has_title' => true, /*'min_word_count' => 11,*/ 'help' => t('Enter blah-blah-blah'),
'title_label' => t('Book title')
),
);
}
/**
* Implement hook_form() with the standard default form.
*/
function synopsis_book_form($node, $form_state) {
return node_content_form($node, $form_state);
}
/**
* Implements hook_validate().
*/
function synopsis_book_validate($node)
{
// Enforce a minimum character count of 2 on company names.
if (isset($node->field_book_year) &&
strlen($node->field_book_year['und'][0]['value']) < 2
) {
form_set_error('job_post_company',
t('The company name is too short. It must be atleast 2 characters.'),
$limit_validation_errors = NULL);
}
}
Not matter all I've written, the page of adding the Book looks like this! No 'field_book_year' field. There is even no body field
What am I doing wrong? Thank you.
I think the problem you're having is that hook_install is run when your module is installed, before the node type is created. So essentially you're trying to attach a field to a non-existant node type at that point.
The way I've always done this is to create the node type in hook_install before trying to attach the field (this is an example from a module that provides a testimonial content type):
// Make sure a testimonial content type doesn't already exist
if (!in_array('testimonial', node_type_get_names())) {
$type = array(
'type' => 'testimonial',
'name' => st('Testimonial'),
'base' => 'node_content',
'description' => st("Use <em>basic pages</em> for your static content, such as an 'About us' page."),
'custom' => 1,
'modified' => 1,
'locked' => 0,
'title_label' => 'Customer / Client Name'
);
$type = node_type_set_defaults($type);
node_type_save($type);
node_add_body_field($type);
}
// See if the testimonial date field exists
if (!field_info_field('field_testimonial_date')) {
field_create_field(array(
// Field info here
));
}
// If the date field is not attached, attach it
if (!field_info_instance('node', 'field_testimonial_date', 'testimonial')) {
field_create_instance(array(
// Field instance info here
));
}
If you look in the standard installation profile install file you'll see this is actually how the Drupal core performs this task, so I would expect it's the 'correct' way to do it.
I am using magento V1.5. I am working on Customer EAV & have tried to create another EAV module.
I have added few attributes in customer entity. Now MY requirement is those attributes must be editable from frontend as well as backend.
Please tell me how to add those attributes in forntend form (customer edit form). & Tell me what to do in backend to have those options to be editable.
I am thinking if there is a way in admin like in our Form.php we prepare form with adding elements to it. then we not need to write a code to create actual html. Magento automatically does it. SO idea is it must also load the new attributes in that was just added. (like they appear in product edit.)
Second Issue is, Can u guys tell me what should I write in my Grid.php >> prepareCollection (for other EAV module ). so that it must get all the attributes with their values ( or may be few )
here is something that I have in my Grid.php but its not working
protected function _prepareCollection()
{
$collection = Mage::getModel('pincodes/eavpincodes')->getCollection();
$this->setCollection($collection);
return parent::_prepareCollection();
}
& this is my collection file
class Namespace_Pincodes_Model_Resource_Eav_Mysql4_Eavpincodes_Collection extends Mage_Eav_Model_Entity_Collection_Abstract
{
protected function _construct()
{
$this->_init('pincodes/eavpincodes');
}
}
But its not returning anything in my grid
& here is my Attribute collection file
class Inkfruit_Pincodes_Model_Resource_Eav_Mysql4_Attribute_Collection extends Mage_Eav_Model_Mysql4_Entity_Attribute_Collection
{
public function _construct()
{
$this->_init('pincodes/resource_eav_attribute', 'eav/entity_attribute');
}
protected function _initSelect()
{
$this->getSelect()->from(array('main_table' => $this->getResource()->getMainTable()))
->where('main_table.entity_type_id=?', Mage::getModel('eav/entity')->setType('pincodes_eavpincodes')->getTypeId())
->join(
array('additional_table' => $this->getTable('pincodes/eavpincodes')),
'additional_table.attribute_set_id=main_table.attribute_id' // I think this sql need to be changed but I have no idea what it'll be
);
return $this;
}
}
Guys thank you so much. This forum has been specially very helpful to me
Regards
SAM
Ok guys I have created a separate module for customers that has one mysql4_install file & it goes as follows
$installer = $this;
$installer->startSetup();
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttribute('customer', 'profile_image', array(
'label' => 'Profile Image',
'type' => 'varchar',
'input' => 'file',
'visible' => true,
'required' => false,
'user_defined' => true,
));
$setup->addAttribute('customer', 'mobile', array(
'label' => 'Mobile Number',
'type' => 'int',
'input' => 'text',
'visible' => true,
'required' => false,
'user_defined' => true,
));
$installer->endSetup();
$installer->installEntities();
But when I hit the url for this module I see no error but these attributes are not in my database.
I also have created Entity_Setup file & it goes as follows I think its incorrect but I gave it a try
<?php
class Namespace_Customer_Entity_Setup extends Mage_Eav_Model_Entity_Setup
{
public function getDefaultEntities()
{
return array (
'customer' => array(
'entity_model' => 'customer/customer',
'attribute_model' => 'customer/attribute',
'table' => 'customer/entity',
'attributes' => array(
'profile_image' => array(
//the EAV attribute type, NOT a mysql varchar
'type' => 'varchar',
'backend' => '',
'frontend' => '',
'label' => 'Profile Image',
'input' => 'file',
'class' => '',
'source' => '',
// store scope == 0
// global scope == 1
// website scope == 2
'global' => 0,
'visible' => true,
'required' => false,
'user_defined' => true,
'default' => '',
'searchable' => true,
'filterable' => true,
'comparable' => false,
'visible_on_front' => false,
'unique' => false
),
'mobile' => array(
'type' => 'varchar',
'backend' => '',
'frontend' => '',
'label' => 'Mobile Number',
'input' => 'text',
'class' => '',
'source' => '',
'global' => 0,
'visible' => true,
'required' => true,
'user_defined' => true,
'default' => '',
'searchable' => true,
'filterable' => true,
'comparable' => false,
'visible_on_front' => false,
'unique' => false
),
),
)
);
}
}
But I see nothing, not any new attribute in database.
Can u guys help here whats wrong??
Thanks
Guys here is My solution. the above answers worked for adding attribute to database only
My question has three parts.
1. Adding attributes to entity in database.
Ans. the above install scripts worked. using a Setup.php & mysql_install/ mysql_upgrade script.
2. Attribute should be editable from Frontend
Ans. We need to modify the file app/design/fontend/default//template/customer/form/edit.phtml
3. Attribute must be editable from Backend
Ans. for that we need to add this snippet in our config.xml
<global>
<fieldsets>
<customer_account>
<create>1</create><update>1</update>
</customer_account>
</fieldsets>
</global>
this will do everything
Hope this will help somebody
This worked for me, notice the additional lines:
<?php
class Millena_CustomerExportAdditions_Model_Resource_Eav_Mysql4_Setup extends Mage_Eav_Model_Entity_Setup
{
public function getDefaultEntities()
{
return array(
'customer' => array(
'entity_model' =>'customer/customer',
'attribute_model' => 'customer/attribute',
'table' => 'customer/entity',
'additional_attribute_table' => 'customer/eav_attribute',
'entity_attribute_collection' => 'customer/attribute_collection',
'attributes' => array(
'export_status' => array(
//'group' => 'Group/Tab',
'label' => 'Customer Export Status',
'type' => 'int',
'input' => 'select',
'default' => '0',
'class' => '',
'backend' => '',
'frontend' => '',
'source' => 'millena_customerExportAdditions/customer_attribute_source_exportStatus',
'global' => 2, //global scope
'visible' => true,
'required' => false,
'user_defined' => false,
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => false,
'visible_in_advanced_search' => false,
'unique' => false
)
)
)
);
}
}
Install script is simply:
<?php
$installer = $this;
$installer->installEntities();
Having same issue here. Using addAttribute in 1.5.0.1 seems to add it into database but customer admin won't render it.
This method works fine with product and category attributes. And in 1.4.0.0 it works for customers too.
In Magento chagelog there is bullet point under improvements about customer attribute rendering. I'll start checking it next.