How to changes input required attribute in symfony2 form? - symfony

I'm using a form on add and edit page in which there is a input file which is required for add record but it is not required on edit page. Is there a way to change attribute on different pages?
$builder->add('title', 'text', array(
'required' => true,
))->add('description', 'textarea', array(
'required' => false,
))->add('fileName', 'file', array(
'data_class' => null,
'required' => true,
'label' => 'Upload File'
));
this is my controller
if ($custFile === null) {
$custFile = new File();
}
$fileForm = $this->createForm(new CustomerFileType(), $custFile);
$fileForm->handleRequest($request);
if ($fileForm->isValid()) {
$data = $fileForm->getData();
$custFile->setUserType('customer');
$custFile->setUserId($request->get('id'));
$custFile->setDateAttached($data->date);
$om->persist($data);
$file = $custFile->getFileName();
if ($file instanceof UploadedFile) {
$uploadManager = $this->get('probus_upload.upload_manager.user_files');
if ($newFileName = $uploadManager->move($file)) {
$custFile->setFileName(basename($newFileName));
}
}
$om->flush();
return $this->redirect($this->generateUrl('minicasp_customer_edit_customer', array(
'id' => $request->get('id'),
)));
}
$fileRecord = array();
if (null !== $customer) {
$fileRecord = $om->createQueryBuilder()
->from('MinicaspCustomerBundle:file', 'f')
->select('f')
->where('f.userId = :customer')
->andWhere('f.userType = :userType')
->orderBy('f.id', 'DESC')
->setParameter('customer', $request->get('id'))
->setParameter('userType', 'customer')
->getQuery()
->getResult()
;
}
return $this->render('MinicaspCustomerBundle:Default:customerAccount.html.twig', array(
'form' => $form->createView(),
'payment_form' => $paymentForm->createView(),
'file_form' => $fileForm->createView(),
'payments' => $payments,
'file_record' => $fileRecord,
'file_edit' => $fileEdit
));

Get your object inside form class and check if your add or edit new record, and based by this set the value of "required" attribute:
$obj = $builder->getData();
$builder->add('fileName', 'file', array(
'data_class' => null,
'required' => $obj->getId() === null ? true : false,
'label' => 'Upload File'
));

#Umair Malik, according to your last comment, you can try this in your controller:
if ($request->getMethod() == 'POST') {
$form->submit($request);
$formData = $form->getData();
if ($formData->getFile() !== null){
/*
* New file has been uploaded
* Save or copy your old record; after this will be over-written
*/
}
$entityManager->persist($formData);
$entityManager->flush();
}

You can create two form types, with different options.
On a side note, you don't need to put "required => true" that's the default option,

Related

Symfony2: Persisting embedded collection within self-referencing embedded collection

Overview
I have two entities;
Element
ElementAnswer
Element has a self-referencing relation and ElementAnswer has a One-To-Many relation with Element (One Element can have many ElementAnswers).
I'm using Symfony2 with embedded collection and it's is working (together with javasript). I can add multiple 'child' elements to the 'parent' element. Also i can add multiple answers to the child element. But.. When i add a child element and add answers to the child element only the child element gets persisted. The answers (which is an embedded collection to the child elements) don't get persisted. AND when i edit the whole collection the answers are persisted.
To be more precise i made some screenshots AND i debugged the post data. Which is exactly the same.
ElementType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('question')
//->add('answers')
->add('answers', 'collection', array(
'entry_type' => new AnswerType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'empty_data' => null,
))
->add('conditions', 'collection', array(
'entry_type' => new ConditionalType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'empty_data' => null,
))
//->add('children', )
->add('children', 'collection', array(
'entry_type' => new ElementChildType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'empty_data' => null,
))
;
}
ElementChildType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('answers', 'collection', array(
'entry_type' => new AnswerType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'empty_data' => null,
'block_name' => 'child_element_answer',
'prototype_name' => '__child_element_answer__',
))
;
}
This is how the form looks like before i submit it:
(Child element 1 and 2 are already persisted. Child element 3 is a newly added entity in the form
This is the post data:
element[name]:parent-element-name
element[question]: blabla
element[children][0][name]:child element 1
element[children][0][answers][0][name]:child answer 1-1
element[children][1][name]:child element 2
element[children][1][answers][0][name]:child answer 2-1
element[children][2][name]:child element 3
element[children][2][answers][0][name]:child answer 3-1
element[_token]:xxxxxxxxxxxxxxxxxxxxxxxxxxxx
This is how the form looks like after submit:
(As you can see: there is no child answer in child element 3)
And when i add a child answer now (after submitting) the child answer DOES get persisted. The same controller is being called and the same entities, so i am stuck. Please help. Thank you!
EDIT:
I finally edited my controller the following way. Probably not the best practice, but it's working so i thought i should let you know:
/**
* Displays a form to edit an existing Element entity.
*
* #Route("/{id}/edit", name="element_edit")
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Element $element, $firstPost = NULL)
{
$em = $this->getDoctrine()->getManager();
$deleteForm = $this->createDeleteForm($element);
$editForm = $this->createForm('AppBundle\Form\ElementType', $element);
$editForm->handleRequest($request);
$breadcrumbs = array();
$breadcrumbs[] = array("name" => "Dashboard", "url" => $this->get("router")->generate("dashboard"));
$breadcrumbs[] = array("name" => "Elementen lijst", "url" => $this->get("router")->generate("element_index"));
$breadcrumbs[] = array("name" => "Element bewerken");
if ($editForm->isSubmitted() && $editForm->isValid()) {
$originalChildren = new ArrayCollection();
$postChildren = new ArrayCollection();
$newChildren = new ArrayCollection();
foreach ($element->getChildren() as $child) {
$originalChildAnswers = new ArrayCollection();
$originalChildren->add($child);
foreach ($child->getAnswers() as $childAnswer) {
$originalChildAnswers->add($childAnswer);
}
}
if (isset($request->request->get('element')['children'])) {
foreach ($request->request->get('element')['children'] as $postChild) {
$postChildren->add($postChild);
}
}
$newElements = [];
$i = 0;
foreach ($originalChildren as $child) {
if (null != $child->getId() && $element->getChildren()->contains($child)) {
$i++;
} else {
$newElements[] = $i;
$i++;
}
}
foreach ($newElements as $newElement) {
$newChildren->set($newElement, $postChildren[$newElement]);
}
foreach ($newChildren as $key => $newchild) {
foreach ($newchild['answers'] as $newChildAnswer) {
$childAnswerKey = $element->getChildren()->getKeys()[$key];
$answerEntity = new Answer();
$answerEntity->setName($newChildAnswer['name']);
$element->getChildren()[$childAnswerKey]->addAnswer($answerEntity);
}
}
$em->persist($element);
$em->flush();
return $this->redirectToRoute('element_edit', array('id' => $element->getId()));
}
return $this->render('element/edit.html.twig', array(
'breadcrumbs' => $breadcrumbs,
'element' => $element,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}

Symfony 2: Set field as read only after first save

I have a Symfony 2 entity. When I create a new record, I must fill all the values using a form, but after saving it, one of the values, $amount shouldn't be updatable when I update the others members.
How can I accomplish this? It's possible to mark a form member as a read-only, in runtime?
By using the validation_groups and name options when creating your form, you can change the form.
The name attribute sets the form creation, and the validation_groups takes care of the validation.
For example, in the create/new method of your controller;
public function createAction(Request $request)
{
// Instantiate new Foo object
$client = new Foo();
// create the form (setting validation group)
$form = $this->formFactory->create('foo', $foo, array(
'name' => 'create',
'validation_groups' => array('create')
)
);
// form has been submitted...
if ('POST' === $request->getMethod()) {
// submits the form
$form->handleRequest($request);
// do validation
if ($form->isValid()) {
// do whatever
}
}
// either GET or validation failed, so show the form
return $this->template->renderResponse('FooBundle:foo:add.html.twig', array(
'form' => $form->createView(),
'foo' => $foo
));
}
And in the edit/update function of your controller;
public function updateAction($id, Request $request)
{
// Instantiate Client object
$client = new Foo($id);
// create the form (setting validation group)
$form = $this->formFactory->create('foo', $foo, array(
'name' => 'update',
'validation_groups' => array('update')
));
// form has been submitted...
if ('POST' === $request->getMethod()) {
// submits the form
$form->handleRequest($request);
// do validation
if ($form->isValid()) {
// do whatever
}
}
// either GET or validation failed, so show the form
return $this->template->renderResponse('FooBundle:foo/edit:index.html.twig', array(
'form' => $form->createView(),
'foo' => $foo
));
}
And your Form Type will look something like;
class FooType extends BaseAbstractType
{
protected $options = array(
'data_class' => 'FooBundle\Model\Foo',
'name' => 'foo',
);
private $roleManager;
public function __construct($mergeOptions = null)
{
parent::__construct($mergeOptions);
}
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->$options['name']($builder, $options);
}
private function create(FormBuilderInterface $builder, array $options)
{
// ID
$builder->add('Id', 'text', array(
'required' => true,
'label' => 'ID',
'attr' => array(
'placeholder' => 'Format: 2 alphanumeric (e.g. A1)'
)
));
// Name - only show on create
$builder->add('Name', 'text', array(
'required' => true,
'label' => 'Name',
'attr' => array(
'placeholder' => 'Your name'
)
));
// add the submit form button
$builder->add('save', 'submit', array(
'label' => 'Save'
));
}
private function update(FormBuilderInterface $builder, array $options)
{
// ID
$builder->add('Id', 'text', array(
'required' => true,
'label' => 'ID',
'attr' => array(
'placeholder' => 'Format: 2 alphanumeric (e.g. A1)',
)
));
// Name - just for show
$builder->add('Name', 'text', array(
'required' => true,
'label' => 'Name',
'attr' => array(
'readonly' => 'true' // stops it being editable
)
));
// add the submit form button
$builder->add('save', 'submit', array(
'label' => 'Save'
));
}
}
P.S. All my classes are declared as services, so how you call create forms/views/etc may be different.

How To Create New Content Type Programmatically in Drupal 7?

I'm building a module (my_module) in Drupal 7.
It has some functionality and also will create new content type.
In my_module.install I implemented the hook_install (my_module_install).
Can I use more one implementation of hook_install to create new content type (my_cck_install) in this module?
If (yes), how should I do this?
Else: have I do this in another module? :-)
You can't use more than one implementation of hook_install in the same module; in PHP you can't have 2 function with the same name which rules this out.
You would just need to add your new content type in the same hook_install anyway (have a look at how the standard installation profile does it at /profiles/standard/standard.install). This is how I always add new content types from the install file (using the example of a testimonials module):
function testimonial_install() {
// 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',
'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);
}
}
The following code will create a content type called "Event" with a machine name of 'event' and a title field -
//CREATE NEW CONTENT TYPE
function orderform_node_info() {
return array(
'event' => array(
'name' => t('Event'),
'base' => 'event',
'description' => t('A event content type'),
'has_title' => TRUE
),
);
}
function event_form($node,$form_state) {
$form['title'] = array(
'#type' => 'textfield',
'#title' => t('event Title'),
'#default_value' => !empty($node->title) ? $node->title : '',
'#required' => TRUE,
'#weight' => -5
);
return $form;
}
//END CONTENT TYPE
you should place it in your .module file... if you want do add additional fields to it, let me know and I'll patch you up with the code... good luck!
/**
* Implements hook_node_info()
*/
function mymodule_node_info() {
return array(
'news' => array(
'name' => t('News'),
'base' => 'news',
'description' => t('You can add News here'),
'has_title' => TRUE,
'title_label' => t('News title')
)
);
}
/**
* Implement hook_form()
*/
function mymodule_form($node, $form_state) {
return node_content_form($node, $form_state);
}
Add the implementation to mymodule.install is as follows:
/**
* Implements hook_install().
*/
function mymodule_install() {
node_types_rebuild();
$types = node_type_get_types();|
node_add_body_field($types['news']);
}
You can get a detailed description with code from here
/*
* Implementation in hook node info in .Module file
*/
function test_node_info() {
return array(
'product' => array(
'name' => t('Product'),
'base' => 'product',
'description' => t('Product Title'),
)
);
}
/**
* Implement hook_form()
*/
function product_form($node, $form_state) {
return node_content_form($node, $form_state);
}
/**
* Implements hook_install() in .install file.
*/
function test_install() {
node_types_rebuild();
$types = node_type_get_types();
node_add_body_field($types['product']);
//New way to implement to add fields in your content type
foreach (_test_installed_fields() as $field) {
field_create_field($field);
}
foreach (_test_installed_instances() as $fieldinstance) {
$fieldinstance['entity_type'] = 'node';
$fieldinstance['bundle'] = 'product';
field_create_instance($fieldinstance);
}
}
/*
* Define your fields
*/
function _test_installed_fields() {
$t = get_t();
return array(
'product_title123' => array(
'field_name' => 'product_title123',
'label' => $t('Product Title'),
'type' => 'text'
),
'description123' => array(
'field_name' => 'description123',
'label' => $t('Description'),
'type' => 'text'
),
);
}
/*
* Define your instance of fields
*/
function _test_installed_instances() {
$t = get_t();
return array(
'product_title123' => array(
'field_name' => 'product_title123',
'type' => 'text',
'label' => $t('Product Title'),
'widget' => array(
'type' => 'text_textfield'
),
'display' => array(
'example_node_list' => array(
'label' => $t('Product Title'),
'type' => 'text'
)
)
),
'description123' => array(
'field_name' => 'description123',
'type' => 'text',
'label' => $t('Description'),
'widget' => array(
'type' => 'text_textarea_with_summary'
),
'display' => array(
'example_node_list' => array(
'label' => $t('Description'),
'type' => 'text'
)
)
),
);
}
/**
* Implements hook_uninstall().
*/
function test_uninstall() {
$ournewtype = 'product';
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
$result = db_query($sql, array(':type' => $ournewtype));
$nodeids = array();
foreach ($result as $row) {
$nodeids[] = $row->nid;
}
node_delete_multiple($nodeids);
node_type_delete($ournewtype);
}
That's it.

How can i add my custom form to custom block in my custom module

I've made a custom Drupal module. Inside which I've created a block and a form. How can I make the form appear in the block content? Cheers.
Block Code:
function module_block($op = 'list', $delta = 0, $edit = array()) {
$block = array();
if ($op == "list") {
// Test
$block[0]["info"] = t('Block');
}
else if ($op == 'view') {
$block['content'] = module_function();
}
return $block;
}
// End module_block
Form Code:
function module_my_form($form_state) {
$form['email'] = array(
'#type' => 'textfield',
'#title' => t('Email'),
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}
Cheers again for any help.
For anyone looking, change:
$block['content'] = module_function();
to
$block['content'] = drupal_get_form('module_my_form');
Cheers

Drupal Ctools Form Wizard in a Block

I created a custom module that has a Ctools multi step form. It's basically a copy of http://www.nicklewis.org/using-chaos-tools-form-wizard-build-multistep-forms-drupal-6.
The form works. I can see it if I got to the url i made for it.
For the life of me I can't get the multistep form to show up in a block.
Any clues?
/**
* Implementation of hook_block()
* */
function mycrazymodule_block($op='list', $delta=0, $edit=array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('SFT Getting Started');
$blocks[1]['info'] = t('SFT Contact US');
$blocks[2]['info'] = t('SFT News Letter');
return $blocks;
case 'view':
switch ($delta){
case '0':
$block['subject'] = t('SFT Getting Started Subject');
$block['content'] = mycrazymodule_wizard();
break;
case '1':
$block['subject'] = t('SFT Contact US Subject');
$block['content'] = t('SFT Contact US content');
break;
case '2':
$block['subject'] = t('SFT News Letter Subject');
$block['content'] = t('SFT News Letter cONTENT');
break;
}
return $block;
}
}
/**
* Implementation of hook_menu().
*/
function mycrazymodule_menu() {
$items['hellocowboy'] = array(
'title' => 'Two Step Form',
'page callback' => 'mycrazymodule_wizard',
'access arguments' => array('access content')
);
return $items;
}
/**
* menu callback for the multistep form
* step is whatever arg one is -- and will refer to the keys listed in
* $form_info['order'], and $form_info['forms'] arrays
*/
function mycrazymodule_wizard() {
$step = arg(1);
// required includes for wizard
$form_state = array();
ctools_include('wizard');
ctools_include('object-cache');
// The array that will hold the two forms and their options
$form_info = array(
'id' => 'getting_started',
'path' => "hellocowboy/%step",
'show trail' => FALSE,
'show back' => FALSE,
'show cancel' => false,
'show return' =>false,
'next text' => 'Submit',
'next callback' => 'getting_started_add_subtask_next',
'finish callback' => 'getting_started_add_subtask_finish',
'return callback' => 'getting_started_add_subtask_finish',
'order' => array(
'basic' => t('Step 1: Basic Info'),
'lecture' => t('Step 2: Choose Lecture'),
),
'forms' => array(
'basic' => array(
'form id' => 'basic_info_form'
),
'lecture' => array(
'form id' => 'choose_lecture_form'
),
),
);
$form_state = array(
'cache name' => NULL,
);
// no matter the step, you will load your values from the callback page
$getstart = getting_started_get_page_cache(NULL);
if (!$getstart) {
// set form to first step -- we have no data
$step = current(array_keys($form_info['order']));
$getstart = new stdClass();
//create cache
ctools_object_cache_set('getting_started', $form_state['cache name'], $getstart);
//print_r($getstart);
}
//THIS IS WHERE WILL STORE ALL FORM DATA
$form_state['getting_started_obj'] = $getstart;
// and this is the witchcraft that makes it work
$output = ctools_wizard_multistep_form($form_info, $step, $form_state);
return $output;
}
function basic_info_form(&$form, &$form_state){
$getstart = &$form_state['getting_started_obj'];
$form['firstname'] = array(
'#weight' => '0',
'#type' => 'textfield',
'#title' => t('firstname'),
'#size' => 60,
'#maxlength' => 255,
'#required' => TRUE,
);
$form['lastname'] = array(
'#weight' => '1',
'#type' => 'textfield',
'#title' => t('lastname'),
'#required' => TRUE,
'#size' => 60,
'#maxlength' => 255,
);
$form['phone'] = array(
'#weight' => '2',
'#type' => 'textfield',
'#title' => t('phone'),
'#required' => TRUE,
'#size' => 60,
'#maxlength' => 255,
);
$form['email'] = array(
'#weight' => '3',
'#type' => 'textfield',
'#title' => t('email'),
'#required' => TRUE,
'#size' => 60,
'#maxlength' => 255,
);
$form['newsletter'] = array(
'#weight' => '4',
'#type' => 'checkbox',
'#title' => t('I would like to receive the newsletter'),
'#required' => TRUE,
'#return_value' => 1,
'#default_value' => 1,
);
$form_state['no buttons'] = TRUE;
}
function basic_info_form_validate(&$form, &$form_state){
$email = $form_state['values']['email'];
$phone = $form_state['values']['phone'];
if(valid_email_address($email) != TRUE){
form_set_error('Dude you have an error', t('Where is your email?'));
}
//if (strlen($phone) > 0 && !ereg('^[0-9]{1,3}-[0-9]{3}-[0-9]{3,4}-[0-9]{3,4}$',
$phone)) {
//form_set_error('Dude the phone', t('Phone number must be in format xxx-xxx-
nnnn-nnnn.'));
//}
}
function basic_info_form_submit(&$form, &$form_state){
//Grab the variables
$firstname =check_plain ($form_state['values']['firstname']);
$lastname = check_plain ($form_state['values']['lastname']);
$email = check_plain ($form_state['values']['email']);
$phone = check_plain ($form_state['values']['phone']);
$newsletter = $form_state['values']['newsletter'];
//Send the form and Grab the lead id
$leadid = send_first_form($lastname, $firstname, $email,$phone, $newsletter);
//Put into form
$form_state['getting_started_obj']->firstname = $firstname;
$form_state['getting_started_obj']->lastname = $lastname;
$form_state['getting_started_obj']->email = $email;
$form_state['getting_started_obj']->phone = $phone;
$form_state['getting_started_obj']->newsletter = $newsletter;
$form_state['getting_started_obj']->leadid = $leadid;
}
function choose_lecture_form(&$form, &$form_state){
$one = 'event 1'
$two = 'event 2'
$three = 'event 3'
$getstart = &$form_state['getting_started_obj'];
$form['lecture'] = array(
'#weight' => '5',
'#default_value' => 'two',
'#options' => array(
'one' => $one,
'two' => $two,
'three' => $three,
),
'#type' => 'radios',
'#title' => t('Select Workshop'),
'#required' => TRUE,
);
$form['attendees'] = array(
'#weight' => '6',
'#default_value' => 'one',
'#options' => array(
'one' => t('I will be arriving alone'),
'two' =>t('I will be arriving with a guest'),
),
'#type' => 'radios',
'#title' => t('Attendees'),
'#required' => TRUE,
);
$form_state['no buttons'] = TRUE;
}
/**
* Same idea as previous steps submit
*
*/
function choose_lecture_form_submit(&$form, &$form_state) {
$workshop = $form_state['values']['lecture'];
$leadid = $form_state['getting_started_obj']->leadid;
$attendees = $form_state['values']['attendees'];
$form_state['getting_started_obj']->lecture = $workshop;
$form_state['getting_started_obj']->attendees = $attendees;
send_second_form($workshop, $attendees, $leadid);
}
//----PART 3 CTOOLS CALLBACKS -- these usually don't have to be very unique
/**
* Callback generated when the add page process is finished.
* this is where you'd normally save.
*/
function getting_started_add_subtask_finish(&$form_state) {
dpm($form_state);
$getstart = &$form_state['getting_started_obj'];
drupal_set_message('mycrazymodule '.$getstart->name.' successfully deployed' );
//Get id
// Clear the cache
ctools_object_cache_clear('getting_started', $form_state['cache name']);
$form_state['redirect'] = 'hellocowboy';
}
/**
* Callback for the proceed step
*
*/
function getting_started_add_subtask_next(&$form_state) {
dpm($form_state);
$getstart = &$form_state['getting_started_obj'];
$cache = ctools_object_cache_set('getting_started', $form_state['cache name'],
$getstart);
}
//PART 4 CTOOLS FORM STORAGE HANDLERS -- these usually don't have to be very unique
/**
* Remove an item from the object cache.
*/
function getting_started_clear_page_cache($name) {
ctools_object_cache_clear('getting_started', $name);
}
/**
* Get the cached changes to a given task handler.
*/
function getting_started_get_page_cache($name) {
$cache = ctools_object_cache_get('getting_started', $name);
return $cache;
}
//Salesforce Functions
function send_first_form($lastname, $firstname,$email,$phone, $newsletter){
$send = array("LastName" => $lastname , "FirstName" => $firstname, "Email" => $email
,"Phone" => $phone , "Newsletter__c" =>$newsletter );
$sf = salesforce_api_connect();
$response = $sf->client->create(array($send), 'Lead');
dpm($response);
return $response->id;
}
function send_second_form($workshop, $attendees, $leadid){
$send = array("Id" => $leadid , "Number_Of_Pepole__c" => "2" );
$sf = salesforce_api_connect();
$response = $sf->client->update(array($send), 'Lead');
dpm($response, 'the final response');
return $response->id;
}
Am assuming you have enabled the block from admin. To do a quick check that the block is indeed getting rendered on the page you are looking at, try returning a test string along with your rendered form, from your block callback.
If that doesn't work, try clearing your cache from admin/settings/performance and try again. If I am not wrong, blocks are cached by default. Let us see if it shows up then.

Resources