So im creating a module in the backend, I have a shell module created (items in admin top menu and a page to visit.) basically I want to have an input field that the admin can type a number into then click a button "add", this will insert a row into an existing table in the database.
$connection = Mage::getSingleton('core/resource')->getConnection('core_write');
$connection->beginTransaction();
$fields = array();
$fields['name']= 'andy';
$connection->insert('test', $fields);
$connection->commit();
I have a table called "test" within my database. If I put the above code into my Controller file, it successfully adds a row to the database when i visit the admin page. But i need to allow the user to input the data that is inserted.
Would I have to move that code into the Model and somehow send the input data to the Model and let that do the work? or not. If this is correct could someone point me to a good place to research sending data to models? (if thats even possible)
iv tried lots of tutorials but they are all way to big for what I need, I dont need to display anything, I just need to have an input box and a save button.
EDIT
i have created a file block/Adminhtml/Form/Edit/Form.php which contains the following . . .
class AndyBram_Presbo_Block_Adminhtml_Form_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form(
array(
'id' => 'edit_form',
'action' => $this->getUrl('*/*/test'),
'method' => 'post',
)
);
$form->setUseContainer(true);
$this->setForm($form);
$fieldset = $form->addFieldset('display', array(
'legend' => 'Display Settings',
'class' => 'fieldset-wide'
));
$fieldset->addField('label', 'text', array(
'name' => 'label',
'label' => 'Label',
));
if (Mage::registry('andybram_presbo')) {
$form->setValues(Mage::registry('andybram_presbo')->getData());
}
return parent::_prepareForm();
}
}
then in my controller i have 2 functions like below . . .
public function indexAction()
{
$this->loadLayout();
$this->_addContent($this->getLayout()->createBlock('presbo/adminhtml_form_edit_form'));
}
public function testAction()
{
echo 'form data here';
$this->loadLayout();
$this->renderLayout();
}
the form is displayed successfully but there is no button to send or say 'do an action'
Further Edit
i have successfully added a submit button to the form that successfully goes to the testAction and echo' "form data here".
how do i then access the data,
iv added the below line
$postData = $this->getRequest()->getPost();
now if i echo $postData, it just puts "array"
if i echo $postData[0] it doesnt put anything just a blank page
any ideas or pointers?
Magento is built as an MVC framework, thus you're right - you need to pass data from controller to the model, and do not do any DB updates directly in a controller's code. The best source for an example is the own Magento code - you can take any controller action, which saves data to DB to see, how it is done. E.g. check app/code/core/Mage/Adminhtml/controllers/NotificationController.php method markAsReadAction().
There you can see, that:
Data is retrieved from the request by calling
$this->getRequest()->getParam('id') - actually this is the answer
to the question, how to get the submitted data
Data is set to model, and then saved to the DB via call to the
$model->setIsRead(1)->save()
It is strongly encouraged to follow the same approach of working with models. This makes codes much better and easier to support.
Note, that "M" letter of "MVC" architecture in Magento is represented by two layers: Models and Resource Models.
Models:
Contain business logic of an entity. E.g. adding ten items to a
Shopping Cart model triggers a discount rule
Represented by classes with a general name of <Your_Module>_Model_<Model_Name>
If need to work with DB, then extend Mage_Core_Model_Abstract and have a Resource
Model, which is responsible for DB communication
Do not need to have basic save/load methods to be implemented, as the ancestor
Mage_Core_Model_Abstract already has all that routines ready to use
Created via call to Mage::getModel('<your_module>/<model_name>')
Resource Models:
Serve as DB abstraction layer, thus save/load data from DB, perform
other DB queries
Extend Mage_Core_Model_Resource_Db_Abstract in order to communicate with DB
Represented by classes with a general name of
<Your_Module>_Model_Resource_<Model_Name>
Automatically created by a corresponding model, when it needs to communicate with DB
So, in a controller you care about creating Models only. Resource Models are created by a Model automatically.
And, according to everything said above, your controller should look like:
public function testAction()
{
$model = Mage::getModel('your_module/your_model');
$model->setName('andy');
$model->save();
}
You can download a fully working example of the thing you need here.
There can be several variations to the code provided, depending on your specific case. But it represents a general approach to implementing the thing you want.
Related
I am new to Laravel and can't quite wrap my head around the Form Requests and how to use them. In simple cases, it's simple enough but what I need is a conditional creation of a related model before progressing with the rest of the request. Let me explain.
//Job model
job_id PK
client_id
some_field
//Client model
client_id
external_id
name
Now in my Create Job interface, I have a Select2 combo box that uses AJAX to search 2 different sources and can produce 3 different results.
So, say I am creating new Job and can have a POST looking like any of these:
Script found a Client with id 21, we just want to save, it all is simple
'client_id' => 21
'some_filed' => Whatever
OR
Script didn't find a Client but we did a search of external API and returned this Identifier, which I can then parse to create a new Client. This needs to be done before I save Job as I need to have a client_id ready for it
'client_id' => '196c3c7e34cde1d4593391ddf1901fd7'
'some_filed' => Whatever
OR
Script finds neither local Client nor a remote datapoint so we want to create a new Client using just the name provided. Of course this has to happen before saving the Job
'client_id' => 'My new client name'
'some_filed' => Whatever
Where do I perform all this functionality?
My first procedural guess would be to stick $data['client_id'] = Client::HandleClientAndReturnId($data['client_id']) in StoreJob's validationData() before returning the result.
But how would I handle/report possible validation issues with creating new Client and how to manage transaction - I don't want to create a Client if validation of Job fails.
I am using Form Requests and actually am parsing several models in the request already, but those are HAS_ONE type of relationships so I create them after the Job. Here I need to reverse the process. Here is what I have in my controller, if that is of any use:
class JobController extends Controller
{
public function store(StoreJob $request, StoreJobDataAdd $request_2, StoreJobDataSup $request_3)
{
$job = Job::create($request->validated());
if ($_POST['add_on']) {
$job->dataAdd()->create($request_2->validated());
}
if ($_POST['sup_on']) {
$job->dataSup()->create($request_3->validated());
}
return new JsonResponse([
'success' => true,
'message' => __('New Job has been created.')
]);
}
}
Here are my relations:
class Job extends Model
{
public function dataAdd()
{
return $this->hasOne(JobDataAdd::class, 'job_id', 'job_id');
}
public function dataSup()
{
return $this->hasOne(JobDataSup::class, 'job_id', 'job_id');
}
public function client()
{
return $this->belongsTo(Client::class, 'contact_id', 'contact_id_client');
}
}
I have a feeling I am missing the right way to do it but not quite sure where to look for the answers so please point me in the right direction.
Clarification:
The objective of the whole exercise is to allow users to create new Clients or select existing by using one combobox. It's a Select2 box. For unfamiliar - a dropdown replacement that has an ability to free-type a string that is used to search for existing records and if not found it sends to the server what user typed in. Something like a dynamic dropdown with ability to search and add options by the user.
I’ve added a small form to an index view to allow users to filter the data. I have placed the following code for the form inside the controller, but I question whether this is the right place to put it.
// ...
public function indexAction()
// ...
// build group list
$groupList = array(
0 => 'all',
1 => 'short people',
2 => 'tall people',
3 => 'fun people',
4 => 'boring people',
);
// create group selection box
$groupSelect = new Element\Select('group');
$groupSelect->setValueOptions($groupList);
$groupSelect->setAttributes(array(
'onChange' => 'this.form.submit()',
));
// create filter form
$form = new Form('group-filter');
$form->add($groupSelect);
$form->setData(array(
'group' => $group,
));
// process the form
$request = $this->getRequest();
if ($request->isPost()) {
$groupSelection = $request->getPost('group', 0);
return $this->redirect()->toRoute('admin-members', array('group'=>$groupSelection,));
}
// ...
Following the MVC pattern, does all of this code belong in the controller?
Nope it does not belong in the controller. Create a new form class (that extends Zend\Form\Form) and inject into the controller class. You can do that through the controllers factory, either through a factory class or the anonymous function "factory".
Other way to do it would be to get it (the form you created) in the controller from the service manager, but as far I know that's not the recommended method anymore, even though it still in the ZF2 docs.
That way your form code will be separated from the controller code, not mixing with the actual controller logic and, in the former case, also more easily testable.
You can learn more from this ZF2 forum thread. It's lengthy, but there are code samples and lead devs from ZF2 team are weighing in.
I have a generic Image model that is linked to by other models that need to have images attached. In most places the image is not required and we have fallbacks in case there is no image uploaded, but in a few particular cases I need to force the upload of an image for the form to validate, but I'm not sure how to validate that through another model. For instance, my model is something like this:
class Person extends AppModel
{
public $belongsTo = array(
'Image' => array(
'className' => 'Image',
'foreignKey' => 'image_id',
'type' => 'LEFT',
)
);
public $validate = array(
...
);
}
The Person model contains some text fields that folks have to enter as well as a redirect_url field. If a redirect is set the page logic will skip trying to load anything and will redirect directly to that URL. But, if it is not set then a bunch of other fields are required. I've got this working properly using a custom validation method in my Person model, but image_id field is not explicitly checked by the Person model since it is just a pointer to the Image model.
Can I somehow add a custom/dynamic validation rule to Image in this instance to have it check if Person.redirect_url is set? The only thing I can figure to do is to add this to my beforeSave() and basically manually check it using $this->data but I'd like to do this the "right" way if it's possible, hooking into the Validation class.
I tried a few variations on using something like this, with no luck thus far:
$this->Person->Image->validate['id']=array(...);
Edit:
Here is what I've tried doing, which kind of works:
public function beforeValidate($options=array()) {
parent::beforeValidate($options);
if(empty($this->data['redirect_url'])) {
if (!isset($this->data['Image']['filepath']) {
$this->invalidate('Image.filepath', 'Custom error message.');
return false;
}
}
}
This lets me invalidate the field without having to add extra code elsewhere, but when printing out the form field on the front end, I end up getting a generic "This file is required" error instead of my "Custom error message". I think this might be because file uploads are handled by a plugin that spirits them away to S3 instead of the local filesystem and it's getting overridden somewhere up the chain.
I am trying to do some very simple validation in my CakePHP contact form, but validation does not work eventhough I think I did everything necessary. Here's what I did:
I made a model like this:
class Office extends AppModel
{
var $name = 'Office';
var $useTable = false;
public $validate = array('onderwerp' => 'notEmpty');
}
(I also tried many other values for $validate from the CakePHP online manual)
In Config/bootstrap.php I made this rule for not letting CakePHP expect plural "Offices":
Inflector::rules('plural', array('rules' => array(),
'irregular' => array(),
'uninflected' => array('office')));
In OfficeController, I do this in my method contact():
$this->Office->set($this->request->data);
if($this->Office->validates()){
echo "code validates";
} else {
print_r($this->Office->validationErrors);
}
And in my Office/contact.ctp view, I have (amongst other code like starting and ending the form) this code:
$this->Form->input('onderwerp', array('label'=>false, 'size' => 60));
Now, even when I fill in the form, leaving empty the field 'onderwerp', it executes the code that should be executed when the code is executed.
When I print_r($this->request->data) or print_r($this->Office) I see that my onderwerp field is there and that it is empty (or filled when I do fill in something).
Now, when I add a public function validates() in my model and echo something there, it IS being displayed. So I'd say CakePHP knows where to find my model, and does execute my controller code. I also tried adding return parent::validates(); in my validates() function, but this also yielded no validation error, or any other error for that matter. My debug level is set to 2.
I guess I'm missing a needle in this haystack. Thanks for helping me finding it!
so drop all the inflector stuff.
and use the right model in your Form->create()
either
$this->Form->create(null)
or
$this->Form->create('Office');
and if you follow my advice to use a table less model with schema you will also have more power over input creation and validation.
OK, so my Joomla app is in MVC format. I am still a little confused about where to put certain operations, in the Controller or in the Model. This function below is in the controller, it gets called when &task=remove. Should the database stuff be in the Model? It does not seem to fit there because I have two models editapp (display a single application) and allapps (display all the applications), now which one would I put the delete operation in?
/**
* Delete an application
*/
function remove() {
global $mainframe;
$cid = JRequest::getVar( 'cid', array(), '', 'array' );
$db =& JFactory::getDBO();
//if there are items to delete
if(count($cid)){
$cids = implode( ',', $cid );
$query = "DELETE FROM #__myapp_apps WHERE id IN ( $cids )";
$db->setQuery( $query );
if (!$db->query()){
echo "<script> alert('".$db->getErrorMsg()."');window.history.go(-1); </script>\n";
}
}
$mainframe->redirect( 'index.php?option=' . $option . '&c=apps');
}
I am also confused about how the flow works. For example, there is a display() function in the controller that gets called by default. If I pass a task, does the display() function still run or does it go directly to the function name passed by $task?
I would try to keep all database functionality in your model. If you don't know which model a method should go in, it's possible that you need to change your models to better reflect your problem.
In your case, though, I think this method would go in allapps since it can handle operations on multiple apps.
If you pass in a task, that method will be called. If you want to then call the display method, just call it at the end of your edit method.
When in doubt, take a look at the weblinks component's models and controllers. They are very simple and a good example of how to do MVC in Joomla!.