CFWheels "Hello Database" in true MVC format - model-view-controller

The "Hello Database" example at cfwheels.org includes only a controller and views. What would the app look like if it included a model? Total beginner here, and I want to know when and how to use a model.
http://cfwheels.org/docs/1-3/chapter/beginner-tutorial-hello-database
To make sure this is a programming question, what would the model code look like in the Hello World app? I'm guessing just a line or two.

First of all, the example app follows all conventions and it is very simple application so there is no need to use model.
But if you want to use model for that then it would go like this:
In model folder,
create a CFC file with name User.cfc and add following code in it
<cfcomponent extends="Model">
<cffunction name="init">
</cffunction>
</cfcomponent>
You can see there is nothing in the init function as there is no need to do anything as of now. But in case you want something you can add
<cfset table(name="users")>
in the init function.

Related

CodeIgniter 4 Dynamic Routes

I'm new to CI.
In my future project, we will have a menu structure like this:
Menu1
--Submenu1
--Submenu2
--[...]
Menu2
--Submenu3
--Submenu4
[...]
So, many menus, and each of them will have many submenus (many submenus will have a CRUD, or similar).
My problem is making the routes to all this pages, I would like to organize the Controllers inside folders (with the menu's name) and each submenu would be a Controller, like this:
/app/Controller/Menu1/Submenu1.php
/app/Controller/Menu1/Submenu2.php
/app/Controller/Menu2/Submenu1.php
etc...
And then my Views would be like this:
/app/Views/Menu1/Submenu1/index.php
/app/Views/Menu1/Submenu1/insert.php
etc...
But at the same time, I don't want to create one entry in the Routes.php file for each submenu, is there a way to create a route that simply takes the path URI and search in the folders for that exact values?
Firstly, bear in mind that you need to make code that is manageable. From the looks of it, your views and controllers will need to be a bit more streamlined otherwise it will become quite a lot to manage.
Therefore I think you would be better off doing a number of things:
1) Create a controller called MY_Controller.php in application/core and extend all controllers from it (that way you can centralise your methods)
2) User a per menu controller. So Controller = Menu1 or Menu2
3) Try and keep your views as re-usable as possible to avoid over complicating things
You should end up with something like this:
menu1/Submenu1 >> Controller (Menu1) >> function Submenu1
menu1/Submenu2 >> Controller (Menu1) >> function Submenu2
Bear in mind that with Codeigniter the following url will result in:
url: menu1/submenu1/param1/param2
Controller
function submenu1($param1,$param2)
So there is no need to get URI components as CI will route them automatically.

prevent duplicate value using ajax in sugar crm

i have create module using module builder , now i am having a field called as book Name
now if i give same book name 2 time t is accepting .
i don't want to use and plug in for checking duplicate value because i want to learn the customization through code .
so i can call ajax and check in data base weather the same book name is exist in db or not but i don't know how controller works in sugar crm . and how to call ajax in sugar crm .
can any one guide me , your help is much appreciated .
If you really want to accomplish this using ajax then I'd recommend an entryPoint as the way to go. This customization will require a couple of simple things. First you'll write a little bit of javascript to perform the actual ajax call. That ajax call will post to the entryPoint you write. The entryPoint will run the query for you and return a response to you in the edit view. So lets get started by writing the entryPoint first.
First, open the file custom/include/MVC/Controller/entry_point_registry.php. If the folder structure and file do not exist yet, go ahead and create them.
Add the following code to the entry_point_registry.php file:
$entry_point_registry['test'] = array('file' => 'custom/test.php', 'auth' => true);
Some quick explanation about that line:
The index value of test can be changed to whatever you like. Perhaps 'unique_book_value' makes more sense in your case. You'll see how this value is used in a minute.
The file value in the array points to where you're gonna put your actual code. You should also give this a more meaningful name. It does NOT need to match the array key mentioned above.
The 'auth' => true part determines whether or not the browser needs to have an active logged in session with SugarCRM or not. In this case (and almost all) I'd suggest keeping this to true.
Now lets look at the code that will go in custom/test.php (or in your case unique_book_name.php):
/* disclaimer: we are not gonna get all crazy with using PDO and parameterized queries at this point,
but be aware that there is potential for sql injection here. The auth => true will help
mitigate that somewhat, but you're never supposed to trust any input, blah blah blah. */
global $db; // load the global sugarcrm database object for your query
$book_name = urldecode($_REQUEST['book_name']); // we are gonna start with $_REQUEST to make this easier to test, but consider changing to $_POST when confirmed working as expected
$book_id = urldecode($_REQUEST['book_id']); // need to make sure this still works as expected when editing an existing record
// the $db->quote is an alias for mysql_real_escape_string() It still does not protect you completely from sql injection, but is better than not using it...
$sql = "SELECT id FROM book_module_table_name WHERE deleted = 0 AND name = '".$db->quote($book_name)."' AND id <> '".$db->quote($book_id)."'";
$res = $db->query($sql);
if ($db->getRowCount($res) > 0) {
echo 'exists';
}
else {
echo 'unique';
}
A note about using direct database queries: There are api methods you can use to accomplish this. (hint: $bean->retrieve_by_string_fields() - check out this article if you wanna go that route: http://developer.sugarcrm.com/2012/03/23/howto-using-the-bean-instead-of-sql-all-the-time/) However, I find the api to be rather slow and ajax should be as fast as possible. If a client asked me to provide this functionality there's a 99% chance I'd use a direct db query. Might use PDO and parameterized query if I'm feeling fancy that day, but it's your call.
Using the above code you should be able to navigate to https://crm.yourdomain.com/index.php?entryPoint=test and run the code we just wrote.
However at this point all you're gonna get is a white screen. If you modify the url to include the entryPoint part and it loads your home page or does NOT go to a white screen there are 3 potential causes:
You put something different for $entry_point_registry['test']. If so change the url to read index.php?entryPoint=whatever_you_put_as_the_array_key
You have sugar in a folder or something on your domain so instead of crm.yourdomain.com it is located somewhere ugly and stupid like yourdomain.com/sugarcrm/ if this is the case just make sure that your are modifying the url such that the actual domain portion is preserved. Okay I'll spell it out for you... https://yourdomain.com/sugarcrm/index.php?entryPoint=test
This is more rare, but for some reason that I cannot figure out apache sometimes needs to be reloaded when adding a new entrypoint. If you have shell access a quick /etc/init.d/apache2 reload should do the trick. If you don't have shell access you may need to open a ticket with your hosting provider (or get a fricking vps where you have some control!!!, c'mon man!)
Still not working? Did you notice the "s" in https? Try http instead and buy a fricking $9 ssl cert, geez man!
Okay moving on. Let's test out the entryPoint a bit. Add a record to the book module. Let's add the book "War of Art" (no, not Art of War, although you should give that a read too).
Now in the url add this: index.php?entryPoint=test&book_name=Art%20of%20War
Oh gawd that url encoding is hideous right! Don't worry about it.
You should hopefully get an ugly white screen with the text "exists". If you do let's make sure it also works the other way. Add a 2 to the book name in the url and hopefully it will now say "unique".
Quick note: if you're using Sugar you're probably also using mysql which is case insensitive when searching on strings. If you really need case sensitivity check out this SO article:
How can I make SQL case sensitive string comparison on MySQL?
Okay so now we have our entryPoint working and we can move on to the fun part of making everything all ajaxical. There are a couple ways to go about this, but rather than going the most basic route I'm gonna show you what I've found to be the most reliable route.
You probably will need to create the following file: custom/modules/CUSTOM_BOOK_MODULE/views/view.edit.php (I hope by now I don't need to point out changing that path to use your module name...
Assuming this file did not exist and we are starting from scratch here is what it will need to look like:
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
class CUSTOM_BOOK_MODULEViewEdit extends ViewEdit
{
public function display()
{
// make sure it works in the subpanel too
$this->useForSubpanel = true;
// make the name value available in the tpl file
$this->ss->assign('name_value', $this->bean->name);
// load the parsed contents of the tpl into this var
$name_input_code = $this->ss->fetch('custom/modules/CUSTOM_BOOK_MODULE/tpls/unique_book_checker.tpl.js');
// pass the parsed contents down into the editviewdefs
$this->ss->assign('custom_name_code', $name_input_code);
// definitely need to call the parent method
parent::display();
}
}
Things are looking good. Now we gotta write the code in this file: custom/modules/CUSTOM_BOOK_MODULE/tpls/unique_book_checker.tpl.js
First a couple of assumptions:
We're going to expect that this is Sugar 6.5+ and jquery is already available. If you're on an earlier version you'll need to manually include jquery.
We're going to put the event listener on the name field. If the book name value that you want to check is actually a different field name then simply adjust that in the javascript below.
Here is the code for custom/modules/CUSTOM_BOOK_MODULE/unique_book_checker.tpl.js:
<input type="text" name="name" id="name" maxlength="255" value="{$name_value}" />
<span id="book_unique_result"></span>
{literal}
<script type="text/javascript">
$(document).ready(function() {
$('#name').blur(function(){
$('#book_unique_result').html('<strong> checking name...</strong>');
$.post('index.php?entryPoint=test', {book_name: $('#name').val(), book_id: $('[name="record"]').val()}, function(data){
if (data == 'exists') {
removeFromValidate('EditView', 'name');
addToValidate('EditView', 'name', 'float', true, 'Book Name Must be Unique.');
$('#book_unique_result').html('<strong style="color:red;"> ✗</strong>');
}
else if (data == 'unique') {
removeFromValidate('EditView', 'name');
addToValidate('EditView', 'name', '', true, 'Name Required');
$('#book_unique_result').html('<strong style="color:green;"> ✓</strong>');
}
else {
// uh oh! maybe you have php display errors on?
}
});
});
});
</script>
{/literal}
Another Note: When the code detects that the name already exists we get a little hacky and use Sugar's built in validation stuff to prevent the record from saving. Basically, we are saying that if the name already exists then the name value MUST be a float. I figured this is pretty unlikely and will do the trick. However if you have a book named 3.14 or something like that and you try to create a duplicate this code will NOT prevent the save. It will tell you that a duplicate was found, but it will not prevent the save.
Phew! Okay last two steps and they are easy.
First, open the file: custom/modules/CUSTOM_BOOK_MODULE/metadata/editviewdefs.php.
Next, find the section that provides the metadata for the name field and add this customCode attribute so that it looks like this:
array (
'name' => 'name',
'customCode' => '{$custom_name_code}',
),
Finally, you'll need to do a quick repair and rebuild for the metadata changes to take effect. Go to Admin > Repair > Quick Repair & Rebuild.
Boom! You should be good to go!

How to specify composite action variables in magento dataflow xml profiles

I have created some custom actions to use inside a Magento Dataflow profile. I would like to pass in composite parameter values (arrays or dictionaries) to the action, similar to the map var you can pass to the default parser actions. I.e., I would like to do something like this:
<var name="attribute_map">
<map name="sColore"><![CDATA[colore]]></map>
<map name="sMarca"><![CDATA[marca]]></map>
<map name="sFornitore"><![CDATA[fornitore]]></map>
</var>
The variable turns out as null in this case, although, upon fiddling with the xml and skimming through the code, it seems that this pattern only works with <var name="map">. Puzzling and disappointing. I also have not been able to find even the slightest hint about the relevant xml schema in any documentation whatsoever...
Any idea on this? Thanks!
(I am working with Community Edition version 1.7.0.2)
If i understand right what you ask, you could overwrite the system/convert/profile/wizard.phtml from admin and add another section similar to existing map but the form elements should have name="gui_data[attribute_map]...[]".
Then you should overwrite the _parseGuiData method from Mage_Dataflow_Model_Profile to form the correct profile actions xml.
Hope that helps.
You can't, using the core implementation.
The var elements can only contain simple text, unless the element has the attribute name="map", in which case the profile parser will search for children map elements and use them to populate a php associative array.
The relevant code is inside the importProfileXml method of the Mage_Dataflow_Model_Convert_Profile_Collection class:
if ($varNode['name'] == 'map') {
$mapData = array();
foreach ($varNode->map as $mapNode) {
$mapData[(string)$mapNode['name']] = (string)$mapNode;
}
$container->setVar((string)$varNode['name'], $mapData);
}
To extend this behavior you should override this class with a custom (sub)class through the usual magento class override methods.

Syntax for outputting raw with 'using'

I'm implementing AuthorizeNet into my site and as per [this posting] I am to use something like:
#using (Html.BeginSIMForm("http://...", 1.99M, "...", "...", true))
{
#Html.CheckoutFormInputs(true);
#Html.Hidden("order_id", "1234");
<input type = "submit" value = "Pay" />
}
the trouble is that the BeginSIMForm method outputs HTML which, of course, gets escaped by Razor, so I need to output raw.
I've tried:
#Html.Raw(using(html.BeginSIMForm()) { ... })
but that's no good. I can't quite get the syntax right. is there a way to tell Razor to generate raw output between certain markers?
* update *
I missed something which was in the posting. what I need to do is wrap the call to .CheckoutFormInputs() like this:
#Html.Raw(Html.CheckoutFormInputs(true));
and that produces the right output... however, the call to .BeginSIMForm() produces output (a form) at the very top of my page and breaks everything. grr...
I've had a look at the source code for their helper. what garbage. I recommend anyone wanting to implement this service on Razor not bother downloading it. I will code the forms by hand. may come back with some code.
Based on the thread you referenced, it seems like that component is not implemented correctly with respect to how it writes the output. You should contact the authors of that library and verify that it supports MVC 3 including the Razor view engine.
I have a detailed answer here
https://stackoverflow.com/a/8426501/1087034
I hope this helps.

Is it possible to pass argument from visualforce apex tag?

I have a function searchWorkByName that takes "key" as an argument and use SQOL to retrieve the data.
In visualforce side, I have a link that calls searchWorkByName but would like to be able to pass argument such as character 'a'
example, (this throws an error)
<apex:commandLink value="search!" action="{!searchWorkByName('aaa')}" />
Is it possible to do so if not what is the alternatives?
apex class
public class SearchWorkTest {
public PageReference searchWorkByName(String key) {
//find record of work names starting from provided key character
workNames = [select name from work__c where work__c.name like 'key%'];
return Page.searchResult;
}
}
visualforce
<apex:page standardController="work__c" extenstions="SearchWorkTest">
<!-- Is it possible to pass argument like 'foo' ? -->
<apex:commandLink value="search!" action="{!searchWorkByName}" />
</apex:page>
You can pass in parameters from a page into a function like this:
<apex:commandLink value="search!" action="{!searchWorkByName}">
<apex:param name="key" value="val"/>
</apex:commandLink>
Obviously, the value of the parameter in this case is fixed. If you want something dynamic (i.e. user types something and that is passed to the function), I'm not 100% sure how you'd do that, but I think it might be possible. However, the solution already posted skins the cat for you, but I thought I'd follow up with an alternative in case it's any use.
No, you cannot pass arguments to actions like that.
1 option is to make this variable a normal form field that user can type text/select from dropdown/whatever - if you'll use same name for a variable in Apex (and make it publicly visible by setters/getters), this will work without problems. Check out my answer at How do I integrate Salesforce with Google Maps? to get started.
Second option - if this search must be somehow done programatically without user having to click anything, if the data for example comes from page itself (i.e. is read in <apex:repeat> tag)... you could make a small helper page & controller and call them as components. There is no problem with passing data to components. Check documentation for <apex:component> and <apex:componentBody>. But I think first answer os most useful for you.
Good luck!

Resources