Drupal 7 - Trying to add form to list view - ajax

sorry if this has been asked before, I looked around but haven't found this specific question on StackOverFlow.com.
I have a view called 'view-post-wall' which I'm trying to add the form that submits posts to this view called 'post' via ajax submit, though I haven't begun adding ajax yet.
My module's name is 'friendicate'
I don't understand what I'm missing here, I'm following a tutorial and have been unable to get past this issue for 2 days now.
I don't get any errors either.
Here is the module code in full
function _form_post_ajax_add() {
$form = array();
$form['title'] = array(
'#type' => 'textfield',
'#title' => 'Title of post',
);
$form['body'] = array(
'#type' => 'textarea',
'#title' => 'description',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit post',
);
return $form;
}
function post_ajax_preprocess_page(&$variables) {
//krumo($variables);
$arg = arg();
if($arg[0] == 'view-post-wall') {
$variables['page']['content']['system_main']['main']['#markup'] = drupal_render(drupal_get_form('_form_post_ajax_add'));
}
}

There are multiple ways to accomplish this, and I'll outline those methods below. Also, if nothing works from my suggestions below, it's possible that you have an invalid form function name. Im not sure if that throws off Drupal or not. The correct format for the function name should end in _form and contain the arguments $form and $form_state, like so:
_form_post_ajax_add_form($form, &$form_state) { ... }
Also, if you want to use a hook, Steff mentioned in a comment to your question that you'll need to use your module name in the function name.
friendicate_preprocess_page(&$variables) { ... }
Ok, now for a few ideas how to get the form on the page.
Block
You can create a custom block within your module, and then assign it to a region in admin/structure/blocks
<?php
/**
* Implements hook_block_info().
*/
function friendicate_block_info() {
$blocks = array();
$blocks['post_ajax'] = array(
'info' => t('Translation Set Links'),
'cache' => DRUPAL_NO_CACHE,
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function friendicate_block_view($delta = '') {
$block = array();
if ($delta == 'post_ajax') {
$form = drupal_get_form('_form_post_ajax_add_form');
$block['content'] = $form;
}
return $block;
}
Clear the cache and your block should appear in admin/structure/blocks
Views attachment before/after
You can add markup before and after a view using the Views hook hook_views_pre_render()
<?php
/**
* Implements hook_view_pre_render().
*/
function frendicate_views_pre_render(&$view) {
if($view->name == 'view_post_wall') { // the machine name of your view
$form = drupal_get_form('_form_post_ajax_add_form');
$view->attachment_before = render($form);
}
}

Or maybe use view post render
function friendicate_views_post_render(&$view, &$output, &$cache) {
//use the machine name of your view
if ($view->name == 'view_post_wall') {
$output .= drupal_render(drupal_get_form('_form_post_ajax_add'));
}
}

Related

Phalcon validation scenario

I used to use Yii framework. I would like to make project using Phalcon. I could not find validation scenario on Phalcon. What is the best way to correctly implement it on Phalcon?
Thanks in advance.
Any data validation:
<?php
use Phalcon\Validation\Validator\PresenceOf,
Phalcon\Validation\Validator\Email;
$validation = new Phalcon\Validation();
$validation->add('name', new PresenceOf(array(
'message' => 'The name is required'
)));
$validation->add('email', new PresenceOf(array(
'message' => 'The e-mail is required'
)));
$validation->add('email', new Email(array(
'message' => 'The e-mail is not valid'
)));
$messages = $validation->validate($_POST);
if (count($messages)) {
foreach ($messages as $message) {
echo $message, '<br>';
}
}
http://docs.phalconphp.com/en/1.2.6/reference/validation.html
If you are working with models:
<?php
use Phalcon\Mvc\Model\Validator\InclusionIn,
Phalcon\Mvc\Model\Validator\Uniqueness;
class Robots extends \Phalcon\Mvc\Model
{
public function validation()
{
$this->validate(new InclusionIn(
array(
"field" => "type",
"domain" => array("Mechanical", "Virtual")
)
));
$this->validate(new Uniqueness(
array(
"field" => "name",
"message" => "The robot name must be unique"
)
));
return $this->validationHasFailed() != true;
}
}
http://docs.phalconphp.com/en/1.2.6/reference/models.html#validating-data-integrity
models also have events, so you can add any logic you need in these functions:
http://docs.phalconphp.com/en/1.2.6/reference/models.html#events-and-events-manager
I would like to use forms for CRUD as they are very dynamic and reusable.
You can achieve that in forms using options.
You can pass additional options to form and act like a scenario.
You can check Form constructor here
https://docs.phalconphp.com/en/latest/api/Phalcon_Forms_Form.html
In your controller you can pass $options
<?php
use Phalcon\Mvc\Controller;
class PostsController extends Controller
{
public function insertAction()
{
$options = array();
$options['scenario'] = 'insert';
$myForm = new MyForm(null, $options);
if($this->request->hasPost('insert')) {
// this will be our model
$profile = new Profile();
// we will bind model to form to copy all valid data and check validations of forms
if($myForm->isValid($_POST, $profile)) {
$profile->save();
}
else {
echo "<pre/>";print_r($myForm->getMessages());exit();
}
}
}
public function updateAction()
{
$options = array();
$options['scenario'] = 'update';
$myForm = new MyForm(null, $options);
}
}
And your form should look like something this
<?php
// elements
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
// validators
use Phalcon\Validation\Validator\PresenceOf;
class MyForm extends Form {
public function initialize($entity = null, $options = null) {
$name = new Text('first_name');
$this->add($name);
if($options['scenario'] == 'insert') {
// at the insertion time name is required
$name->addValidator(new PresenceOf(array('message' => 'Name is required.')));
}
else {
// at the update time name is not required
// as well you can add more additional validations
}
}
}
now you can add multiple scenarios and act based on scenarios.

Get list of all product attributes in magento

I have been doing frontend magento for a while but have only just started building modules. This is something i know how to do frontend but i am struggling with in my module. What i am trying to achieve for now, is populating a multiselect in the admin with all available product attributes. Including custom product attributes across all product attribute sets. I'm not entirely sure what table this will require because i don't want to assume that Flat Category Data is enabled.
I have created my admin area in a new tab in system config, i have created a multiselect field that is currently just being populated with three static options. This much works. Could anyone help me by pointing a finger in the right direction... currently this is what i have so far (for what it's worth).
<?php
class test_test_Model_Source
{
public function toOptionArray()
{
return array(
array('value' => 0, 'label' =>'First item'),
array('value' => 1, 'label' => 'Second item'),
array('value' => 2, 'label' =>'third item'),
);
}
}
///////////////////////////// EDIT /////////////////////////////////////
I feel like i might be onto something here, but it's only returning the first letter of every attribute (so i'm not sure if its even the attributes its returning)
public function toOptionArray()
{
$attributes = Mage::getModel('catalog/product')->getAttributes();
$attributeArray = array();
foreach($attributes as $a){
foreach($a->getSource()->getAllOptions(false) as $option){
$attributeArray[$option['value']] = $option['label'];
}
}
return $attributeArray;
}
///////////////////////////////// EDIT //////////////////////////////////////
I am not extremely close as i now know that the array is returning what i want it to, all attribute_codes. However it is still only outputting the first letter of each... Anyone know why?
public function toOptionArray()
{
$attributes = Mage::getModel('catalog/product')->getAttributes();
$attributeArray = array();
foreach($attributes as $a){
foreach ($a->getEntityType()->getAttributeCodes() as $attributeName) {
$attributeArray[$attributeName] = $attributeName;
}
break;
}
return $attributeArray;
}
I have answered my own question. I have found a way that worked however i'm not sure why, so if someone could comment and explain that would be useful. So although having $attributeArray[$attributeName] = $attributeName; worked when it came to a print_r when you returned the array it was only providing the first letter. However if you do the following, which in my opinion seems to be doing exactly the same thing it works. I can only imagine that when rendering it wasn't expecting a string but something else. Anyway, here is the code:
public function toOptionArray()
{
$attributes = Mage::getModel('catalog/product')->getAttributes();
$attributeArray = array();
foreach($attributes as $a){
foreach ($a->getEntityType()->getAttributeCodes() as $attributeName) {
//$attributeArray[$attributeName] = $attributeName;
$attributeArray[] = array(
'label' => $attributeName,
'value' => $attributeName
);
}
break;
}
return $attributeArray;
}
No need to do additional loops, as Frank Clark suggested. Just use:
public function toOptionArray()
{
$attributes = Mage::getResourceModel('catalog/product_attribute_collection')->addVisibleFilter();
$attributeArray = array();
foreach($attributes as $attribute){
$attributeArray[] = array(
'label' => $attribute->getData('frontend_label'),
'value' => $attribute->getData('attribute_code')
);
}
return $attributeArray;
}
You can try to get attributes in other way, like this
$attributes = Mage::getSingleton('eav/config')
->getEntityType(Mage_Catalog_Model_Product::ENTITY)->getAttributeCollection();
Once you have attributes you can get options in this way (copied from magento code)
$result = array();
foreach($attributes as $attribute){
foreach ($attribute->getProductAttribute()->getSource()->getAllOptions() as $option) {
if($option['value']!='') {
$result[$option['value']] = $option['label'];
}
}
}

How to add an autocomplete field in a Symfony2 form for a collection and using Propel?

I'm using Symfony 2.1 forms with PropelBundle and I'm trying to refactor a form that had a drop-down list of objects (to select from) to instead use a jquery autocomplete field (working with AJAX). For the dropdown list I was using the following code (which worked perfectly for the drop-down) in my form type:
$builder->add('books', 'collection', array(
'type' => 'model',
'options' => array(
'class' => 'MyVendor\MyBundle\Model\Book',
'property' => 'title',
),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'required' => false,
));
For the sake of giving a little context, let's say we are creating a new "Reader" object and that we would like to select the Reader's favorite books from a list of available "Book" objects. A collection type is used so that many "favorite books" can be selected in the new "Reader" form. Now, I would like to change the above to use autocomplete. For doing so, I tried to implement a Data Transformer to be able to get a Book object from a simple text field that could be used for the Autocomplete function to pass the Book ID as indicated in the answer to this Question. However, I was not able to figure out how to make the Data Transformer work with a collection type and Propel classes. I created a BookToIdTransformer class as indicated in the Symfony Cookbook and tried the following in the "ReaderType" file:
$transformer = new BookToIdTransformer();
$builder->add(
$builder->create('books', 'collection', array(
'type' => 'text',
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'required' => false,
))->addModelTransformer($transformer)
);
With the above, I get a "Call to undefined method: getId" exception (apparently the Transformer expects a PropelCollection of Books, not a single Book object..). Does anyone know how to go about it? or let me know if there are other ways to implement the autocomplete in Symfony using Propel and allowing for selecting multiple objects (e.g. a collection of books)?
The solution I ultimately went for is slightly different from my previous answer. I ended up using a "text" field type instead of a "collection" field type in my "ReaderType" form, since I ended up using the Loopj Tokeninput jQuery plugin which allows for selecting multiple objects (e.g. "Favorite Book") to associate to my main object (e.g. "Reader" object) in the form. Considering that, I created a "Data Transformer" for transforming the objects' ids passed (in a comma separated list in the text field) into a Propel Object Collection. The code is shared as follows, including a sample ajax object controller.
The key part of the "ReaderType" form looks as follows:
$transformer = new BooksToIdsTransformer();
$builder->add(
$builder->create('books', 'text', array(
'required' => false,
))->addModelTransformer($transformer)
);
The "Data Transformer" file looks like this:
// src/MyVendor/MyBundle/Form/DataTransformer/BooksToIdsTransformer.php
namespace MyVendor\MyBundle\Form\DataTransformer;
use \PropelObjectCollection;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use MyVendor\MyBundle\Model\BookQuery;
class BooksToIdsTransformer implements DataTransformerInterface
{
public function transform($books)
{
if (null === $books) {
return "";
}
if (!$books instanceof PropelObjectCollection) {
throw new UnexpectedTypeException($books, '\PropelObjectCollection');
}
$idsArray = array();
foreach ($books as $book) {
$idsArray[] = $book->getId();
}
$ids = implode(",", $idsArray);
return $ids;
}
public function reverseTransform($ids)
{
$books = new PropelObjectCollection();
if ('' === $ids || null === $ids) {
return $books;
}
if (!is_string($ids)) {
throw new UnexpectedTypeException($ids, 'string');
}
$idsArray = explode(",", $ids);
$idsArray = array_filter ($idsArray, 'is_numeric');
foreach ($idsArray as $id) {
$books->append(BookQuery::create()->findOneById($id));
}
return $books;
}
}
The ajax controller that returns a json collection of "books" to the Tokeninput autocomplete function is as follows:
namespace MyVendor\MyBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use MyVendor\MyBundle\Model\BookQuery;
class ClassAjaxController extends Controller
{
public function bookAction(Request $request)
{
$value = $request->get('q');
$books = BookQuery::create()->findByName('%'.$value.'%');
$json = array();
foreach ($books as $book) {
$json[] = array(
'id' => $book->getId(),
'name' => $book->getName()
);
}
$response = new Response();
$response->setContent(json_encode($json));
return $response;
}
}
And finally, the router in the "routing.yml" file:
ajax_book:
pattern: /ajax_book
defaults: { _controller: MySiteBundle:ClassAjax:book }

Calendar class in Codeigniter not showing next/previous months

I am trying to generate a calendar and almost have it, but when I click the next or previous links, the calendar is not displayed - otherwise it is correct. When I click the next url the address bar shows the correct url, but the next month is not shown.
Here is my code:
class Poll_controller1 extends skylark {
function poll_home()
{
$this->add_to_center(POLL,"poll_view1");
$this->load_lcr_template();
$prefs = array (
'show_next_prev' => TRUE,
'next_prev_url' => 'http://skylarkv2/index.php/poll_controller1/show'
);
$this->load->library('calendar', $prefs);
}
function show()
{
echo $this->calendar->generate($this->uri->segment(3), $this->uri->segment(4));
}
Am I making mistake or missing something?
try this from controller
public function display($year = null, $month = null)
{
$config = array(
'show_next_prev' => 'TRUE',
'next_prev_url' => base_url().'calendarC/display'
);
$this->load->library('calendar', $config);
$data['calendar'] = $this->calendar->generate($year, $month);
$this->load->view('calendar', $data);
}
Most likely, you just need to initialize the calendar class in the same scope that you generate it. The way you have it set up, show() has no knowledge of how the class was initialized in poll_home(). Try something like this:
function show()
{
$prefs = array (
'show_next_prev' => TRUE,
'next_prev_url' => 'http://skylarkv2/index.php/poll_controller1/show'
);
$this->load->library('calendar', $prefs);
echo $this->calendar->generate($this->uri->segment(3), $this->uri->segment(4));
}
There's also the chance that $this->uri->segment(3) and $this->uri->segment(4) are not what you think they are, double check that those values are correct. If you are have any routing going on, you may need to use $this->uri->rsegment() instead (note the r).

cakephp validation response returning data to controller

Hi i have made a custom validation in the model. How can i access the result($visitor) from this in the controller?
model:
<?php
class Visitors extends AppModel
{
var $name = 'Visitors';
var $validate = array(
'xxx' => array(
'rule' => array('checkxxx'),
'message' => 'yyy.'
)
);
function checkIxxx($check){
$visitor = $this->find('first', array('conditions' => $check));
return $visitor;
}
}
?>
in my controller i want this:
function start() {
$this->Visitors->set($this->data);
if($this->Visitors->validates())
{
if($this->Visitors->xxx->type == 'value') //this is a value from the $visitor array in the model**
{
//do something
}
}
is this possible?
Updated to be a relevant answer, apologies.
//Model
var myField = 'invalid';
function myValidation($var){
if($var === true){
// Passed your validation test
$this->myField = 'valid';
}else{
$this->myField = 'invalid';
}
}
// Controller
$this->Model->set($this->data);
$this->Model->validates($this->data);
if($this->Model->myfield == 'valid'){
// Field has passed validation
}
You will want to use
$this->Model->invalidFields()
PS: You dont follow cake conventions
the model should be "Visitor" (singular)

Resources