hydra12’s blog

Tech Stuff, TCEA, PHP, etc.

Update

Filed under: Cake, ExtJS, python, pygame — admin at 6:24 am on Friday, April 25, 2008

I’m still here. I’ve been working on my cake/extjs project (see last post), but it has been slow going. There are a few things that I want to include now so I don’t have to hack them in later, and figuring out how to do them has been tough. I think I made a breakthrough yesterday, so maybe I’ll be back on track soon.

I confess that, with the problems I’ve been encountering, I took a break from cake and started playing with python (specifically pygame). Maybe someday soon I’ll also have a tutorial on making a game with pygame. I’m exploring tile based maps for a small old-school rpg. We’ll have to see if I ever get anywhere with it.

Well, that’s it for now. See you later!
hydra12

What I’m Working On

Filed under: Cake, ExtJS, jquery — admin at 6:57 am on Tuesday, March 4, 2008

I’m sorry I haven’t posted anything lately. I’ve been really busy with both of my jobs, and we’ve had some family health issues to deal with, so I haven’t had much time for blogging.

I’ve been playing with extjs and jquery. I’m working on a webapp that will help me manage all my church stuff better - members, events, etc. The first part will be people management, and it will use cakephp, jquery, and extjs. When I get it working, I’ll post a tutorial and a sample app.

I’ve learned a lot since I first started blogging about extjs with cake. There aren’t a lot of resources out there on combining the two, so the learning is slow. I feel like I’m on the cutting edge or something :-)

Anyway, Felix posted a cool way to convert your model data to json in his World Domination slideshow from CakeFest. I’m using it and really liking it. That will be included in my upcoming tutorial. I’ll also have forms, layouts, tabs, etc. I’m even looking into creating a basic framework and then writing my people manager as a plugin. That way, I can write other plugins and integrate them easily. Anyone have any thoughts on that?

More soon (I hope).
hydra12

EXTJS Tree with CakePHP

Filed under: Uncategorized — admin at 12:36 pm on Tuesday, February 12, 2008

Sorry I’ve been out of circulation lately. I was going to make a tutorial on using trees with cake’s tree behavior, but someone else beat me to it. You can find it here:

http://blogs.bigfish.tv/adam/2008/02/12/drag-and-drop-using-ext-js-with-the-cakephp-tree-behavior/

CakePHP, EXTJS DataGrid, and Paging

Filed under: Cake, ExtJS — admin at 11:28 am on Tuesday, January 15, 2008

I was asked earlier if it was possible to use the datagrid with cake 1.2’s paginator. I did some checking, and I don’t think it is. The paginate function is closely tied to the paginate helper. When you call paginate in the controller, all I ever got back was the same results as findAll.

Fear not, however, because pagination with the datagrid is fairly painless. If you don’t have a working datagrid already, please work through my earlier tutorial first.

Ok, to add pagination, we first have to change our getAllUsers controller function. Change the definition to this:

function getAllUsers($limit=10, $page=0)

Page and Limit are how the model knows which chunk of data to pull from the database. We are just setting some defaults.

Now add the following lines inside the controller (I put mine right after the Configure::write line):

if(!empty($_POST['limit']))
	$limit = $_POST['limit'];
 
if(!empty($_POST['start']))
	$page = ($_POST['start']/$limit)+1;

ExtJS uses posts to send the paging params to cake. The problem is, it sends limit and start, while we need limit and page. The first part just checks to see if $_POST[’limit’] is empty, and if it isn’t, it assigns it to $limit. The second part is similar, but more complicated. For ExtJS, start is which record to start with. If we divide start by limit, we should get the page we are on. However, it didn’t work quite right. By adding 1 to the total, things now work.

Now, change the definition of $userA to read like this:

$userA = $this->User->findAll(null,'*','id ASC', $limit, $page); //gets all the User records and sorts them by username alphabetically.

Note - I left this out the first time. Thanks, Yoris, for catching this.

OK, that takes care of the controller, now we just need to modify myScript.js a little bit. Modify your grid code to look like this:

grid = new Ext.grid.GridPanel({
	ds: ds,
	columns: [
		{id:'id',header: "ID", width: 50, sortable: true, dataIndex: 'id'},
		{header: "Username", width: 125, sortable: true, dataIndex: 'username'},
		{header: "Full name", width: 125, sortable: true, dataIndex: 'fullname'}
	],
	cm: cm,
	stripeRows: true,
	height: 350,
	width: 350,
	title: 'Data Grid',
	bbar: new Ext.PagingToolbar({
		pageSize: 10,
		store: ds,
		displayInfo: true,
		displayMsg: 'Displaying users {0} - {1} of {2}',
		emptyMsg: 'No users to display'		
	})
});

bbar is what we are adding (I think it means bottom bar). Page size is the same as limit (I think). The rest is just configuration. Now change your ds.load command to look like this:

ds.load({params:{start:0, limit:10}}); //This loads data from the database into the datastore.

That’s it! You should now have a paging bar at the bottom.

CakePHP and EXTJS Forms

Filed under: Cake, ExtJS — admin at 4:13 pm on Friday, January 11, 2008

UPDATE NOTE - I removed a trailing comma on line 38 of myForm.js. It was causing IE problems.
UPDATE NOTE 2 - I changed the way I named the variables in myForm.js so that they are more cake-friendly. That makes the controller work like a regular application (if $data isn’t empty, save . . .). I got this idea from cakebaker’s new tutorial using jquery (http://cakebaker.42dh.com/2008/02/24/edit-in-place-with-jquery-and-cakephp/)

OK, several people have asked how to do this, so here’s how it works. EXTJS forms use ajax by default. You can make them submit like regular forms (see here: http://extjs.com/forum/showthread.php?t=8397&highlight=cancel+form+submit), but I’m going to use ajax/json today. I’m going to create a form that will add to my users database/datagrid from my last tutorial. You need to at least read this one first and setup the basics (include EXT, the host variable, etc).

NOTE - There may be an easier way to do this, but this is the best I’ve been able to come up with.

First, we’ll look at the controller. You need 2 (yes, two) controller functions to make this work. First, we’ll make a function called add:

1
2
3
4
function add()
{
	//blank controller function
}

Basically, this function exists for one reason only - it calls it’s view, which calls our javascript file (myForm.js, in this case).

The view is add.ctp and looks like this:

1
2
<div id="user-form"></div>
<?php echo $javascript->link('myForm'); ?>

It creates a div to hold our form, and it calls our js file. Now for the second controller function. I named it (creatively enough) add2. Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function add2() {
	Configure::write('debug', '0');     //turn debugging off; debugging breaks ajax
	$this->layout = 'Ajax';              //set the layout to Ajax so the ajax doesn't break
 
        //Cake does everything automagically through $this->data
        //Since we aren't using cake's automagic, we have to fake things a little
        //When a form is submitted, we are going to take the data submitted ($this->params['form']['username']
        //and assign it to $this->data['User']['username'] to make it fit with cake's automagic.
        //Otherwise, we can't use cake's save functions
 
        //Part of UPDATE2 - we don't need to do this anymore; it's taken care of in myForm.js
        //$this->data['User']['username'] = $this->params['form']['username'];
	//$this->data['User']['fullname'] = $this->params['form']['fullname'];
 
        //This is just like regular cake except for the set statements		
	if (!empty($this->data)) {
		$this->User->create();
		if ($this->User->save($this->data)) {
			$this->set('success', '{success:true}');  //this is a json statement.  EXT forms need this to know if things worked
		} else {
			$this->set('success', '{success:false}');  //EXT forms need this to know if something went wrong
		}
	}
}

OK, the comments should explain things there. The view is add2.ctp:

1
<?php echo $success; ?>

All this does is print the json return string we set in our controller. EXT forms need this to know if things worked or not. Since we are calling add2 through ajax, this page won’t be called directly, and the success statement won’t be printed to the screen. It will show up in firebug, though.

OK, now for the javascript (myForm.js - save it in /webroot/js).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 Ext.onReady(function(){
 
	Ext.QuickTips.init();
 
	//make a new form
	var form_user = new Ext.form.FormPanel({
		frame: true,
		title: 'Add User',
		bodyStyle: 'padding: 5px 5px 0',
		width: 350,
		labelWidth: 75,
		defaults: {width: 230},  	//this is the default field width
        defaultType: 'textfield', 	//this is the default field type.  You don't have to set this, but if not, you'll have to set it for each item
		items: [{
				fieldLabel: 'User Name',	//label text
				name: 'data[User][username]',			//field name for submit purposes
				allowBlank: false			//simple validation
			},
			{
				fieldLabel: 'Full Name',
				name: 'data[User][fullname]',
				allowBlank: false
			}],
		buttons: [{
				text: 'Save',		//text for submit button
				type: 'submit',		//type for button
				handler: function() {	//what happens when you click the button?
					form_user.form.submit({
						url: 'http://'+host+'/ext/users/add2',
						success: function() {
							Ext.MessageBox.alert('Message', 'It worked!', function(){window.location.href = 'http://'+host+'/ext/users/'});
						},
						failure: function() {
							Ext.MessageBox.alert('Message', 'Save failed!');
						}
					});				
				}
			},
			{
				text: 'Cancel',
				handler: function() {
					form_user.form.reset();
				}
		}]
	});
 
	form_user.render('user-form');
 })

OK, here’s what’s going on. Line 3 creates a new formPanel. The next several lines set different formPanel options. Line 14 starts defining our form fields. Line 24 defines our buttons. Line 27 defines the handler for our submit button. That’s how the form submits. NOTE - I’m using the host definition from my last tutorial. Success on line 30 is determined by the return value from add2 - success (true) or failure (false). If success is true, a message pops up to tell you ‘It worked!’, then it redirects to the datagrid from my last tutorial. If success is false, a message pops up to tell you the save failed. Cancel just resets the form.

There, I did it before going home for the weekend! Yeah! I hope this helps some people.

hydra12

EXTJS Datagrid with CakePHP (updated)

Filed under: Cake, ExtJS — admin at 2:30 pm on Thursday, January 10, 2008

OK, I’m rewriting my datagrid/cakephp tutorial. I’m using EXTJS 2.0 and CakePHP 1.2 beta. To keep things simple, we’re going to make a cake project with just one controller called users. Here is a dump of my database:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE DATABASE IF NOT EXISTS `ext`;
USE `ext`;
 
/*Table structure for table `users` */
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `username` varchar(25) collate latin1_general_ci NOT NULL,
  `fullname` varchar(50) collate latin1_general_ci NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
 
/*Data for the table `users` */
INSERT  INTO `users`(`id`,`username`,`fullname`) VALUES (1,'hydra12','Buckner, Mark'),(2,'cyclops','Summers, Scott'),(3,'nightcrawler','Wagner, Kurt'),(4,'wolverine','Logan'),(5,'iceman','Drake, Bobby'),(6,'archangel','Worthington, Warren'),(7,'storm','Munroe, Ororo'),(8,'gambit','LeBeau, Remy');

OK, that will give you a database called ext with a users table. Users has an id, username, and fullname. You should also have 8 entries in the table.

Now create a cake app (using bake or by hand, whichever you prefer) called ext. Download ext-2.0 and place it in /ext/webroot/js/.

Now add the following lines to your default layout in the head section to add ext.

1
2
<?php echo $javascript->link('ext-2.0/adapter/ext/ext-base'); ?>
<?php echo $javascript->link('ext-2.0/ext-all-debug'); ?>

Now add this line (also in the head section) to include the ext css file:

<link rel='StyleSheet' href='<?php echo $this->base ?>/js/ext-2.0/resources/css/ext-all.css' />

Finally, add this line to the head section:

1
2
3
<script>
	var host = '<?php echo $_SERVER['HTTP_HOST']; ?>';
</script>

This sets a javascript variable to the HTTP_HOST, which we will use later to avoid ‘Permission Denied’ errors due to XHR problems.

That takes care of our layout. Now let’s build a controller. Create a controller that looks like this:

1
2
3
4
5
6
7
8
9
10
11
<?php
    class UsersController extends AppController {
 
	var $name = 'Users';
	var $helpers = array('Html', 'Form', 'Javascript');
 
	function index()
        {
             //blank index method.  We'll load data with a json call from myScript.js.
        }
?>

Notice that the index() function is blank. That’s OK, because our myScript.js will take care of everything.

Now make a view file in /views/users/ called index.ctp. It should only have two lines:

<div id="grid-paging"></div>
<?php echo $javascript->link('myScript'); ?>

This line creates the div our grid will render to and also loads our javascript file (we’ll make it in a minute).

Our model file (user.php) is minimal:

1
2
3
4
5
6
<?php
class User extends AppModel {
	var $name = 'User';
	var $useTable = 'users';
}
?>

OK, that takes care of our model, controller, and index. Now we need another function in the controller to retrieve our user data. Add this function to the users controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
function getAllUsers()
    {
        Configure::write('debug', '0');  //set debug to 0 for this function because debugging info breaks the XMLHttpRequest
	$this->layout = "ajax"; //this tells the controller to use the Ajax layout instead of the default layout (since we're using ajax . . .)
	$userArray = array();	//this will hold our data from the database.
 
        $count = $this->User->findCount(); //counts the number of records in User.
        $userA = $this->User->findAll(null,'*','username ASC'); //gets all the User records and sorts them by username alphabetically.
 
	$userArray = Set::extract($userA, '{n}.User');  //convert $userArray into a json-friendly format
	$this->set('total', $count);  //send total to the view
	$this->set('users',$userArray);  //send users to the view
    }

This function gets the number of records and assigns the value to $count. Then it fetches all the records and assigns them to $userA. Set::extract converts the array to a more json-friendly format (it strips one level out of the multi-dimensional array). For more on this, see my earlier tutorial.

Now create get_all_users.ctp in /views/users/. Put this line in get_all_users.ctp:

<?php echo '{"total":'.$total.', "users":'.$javascript->Object($users).'}'; ?>

This takes the data sent from the controller and puts it into the correct json format.

Now for the fun part: create a file called myScript.js in /ext/webroot/js/. Add these lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Ext.onReady(function(){
    /******
     ****** host holds the name of my host computer.  I did this because of restrictions on making remote data requests.  If the 
     ****** host is localhost, things look great from my development machine.  If I try to view my page from another computer,
     ****** though, I get errors and nothing happens.  I set my host to tc-mark-lap (the name of my development computer).  If I 
     ****** view my page with localhost in the url, I get an error.  If I view it with tc-mark-lap, everything works.  This way,
     ****** I can view pages from my laptop or from a remote machine.  I'll have to remember to change this when I deploy to my
     ****** production server, though.  I might be able to set this in my controller or in a config table and use the javascript
     ****** helper to set it at runtime.  I'll have to check on that sometime.
     ******/
 
    //This is the datastore.  My json data will be loaded remotely, then stored in the datastore.  
    //I used the HttpProxy because I'm accessing data on my local machine
    //In my json reader, I define the fields I should get from my json data (id, last_name, first_name, etc.
    var ds = new Ext.data.Store({	
        proxy: new Ext.data.HttpProxy({url: 'http://'+host+'/ext/users/getAllUsers'}),  //note that I used host in the url
        reader: new Ext.data.JsonReader({
        root: 'users',
		totalProperty: 'total',
		fields: [
			{name: 'id'},
			{name: 'username'},
			{name: 'fullname'}
		]
		})
    });  
 
    //This is the column model.  This defines the columns in my datagrid.
    //It also maps each column with the appropriate json data from my database (dataIndex).
    var cm = new Ext.grid.ColumnModel([
        {header: "ID", dataIndex: 'id', width: 100, hidden: true},
		{header: "User Name", dataIndex: 'username', width: 100},
		{header: "Full Name", dataIndex: 'fullname', width: 100}
    ]);
 
    //Here's where we define our datagrid.  
    //We have to specify our dataStore and our columnModel.
    var grid = new Ext.grid.GridPanel({
		ds: ds,
		cm: cm,
		stripeRows: true,
		height: 350,
		width: 350,
		title: 'Data Grid'
    });
 
    ds.load(); //This loads data from the database into the datastore.
 
	grid.render('grid-paging');  //This renders our grid to the grid-paging div in our index.ctp view.
})

The comments should explain everything here. This should work with ext-2.0, and is actually simpler and (I hope) better designed than my previous 1.1 example.

hydra12

ExtJS Datagrid with CakePHP

Filed under: Cake, ExtJS — admin at 10:10 am on Monday, November 26, 2007

Note: I’m in the process of updating this post based on some things I learned here.

To use the extjs datagrid with cake (I’m using 1.2 pre-beta), first you need to download extjs and put it in /webroot/js. I put mine in /webroot/js/ext-1.1/. Now add the following lines to your default layout:

1
2
3
<?php echo $javascript->link('ext-1.1/adapter/ext/ext-base'); ?>
<?php echo $javascript->link('ext-1.1/ext-all-debug'); ?>
<?php echo $javascript->link('myScript'); ?>

Line 1 tells extjs that you are using extjs exclusively. You can also use jquery or yui.
Line 2 loads the extjs library. I used ext-all-debug for development purposes.
Line 3 loads my javascript file. I called it myScript.js and put it in /webroot/js.

Just before the tag, add this line:

1
<link rel='StyleSheet' href='<?php echo $this->base ?>/js/ext-1.1/resources/css/ext-all.css' />

This adds a link to extjs’s css file. This is kind of tricky in cake, since cake expects all css files to be in /webroot/css. You could copy the file there, then just use the html helper to link to the file. I didn’t do that because I want to be able to upgrade my extjs files, and I was afraid I’d forget to copy the new css file.

Put this code in the body of your layout:

1
2
3
<div id="grid-panel">
    <div id="grid-paging" style="border:1px solid #99bbe8;overflow:hidden; width: 665px; height: 00px;"></div>
</div>

Your grid-panel div will hold your datagrid. The grid-paging div will hold the paging bar if you want one (we won’t use it here).

I’m creating a grid to keep track of users, so I made a model called User and a controller called Users. Your Users controller should look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
class UsersController extends AppController {
 
    var $name = 'Users';
    var $helpers = array('Html', 'Form', 'Javascript');
 
    function index()
    {
        //blank index method.  We'll load data with a json call from myScript.js.
    }
 
    function getAllUsers()
    {
        $userArray = array();	//this will hold our data from the database.
        $this->layout = 'Ajax'; //this tells the controller to use the Ajax layout instead of the default layout.
        $count = $this->User->findCount(); //counts the number of records in User.
        $userA = $this->User->findAll(null,'*','last_name ASC'); //gets all the User records and sorts them by last name.
	/*
	 ************** Use this code if you are using cake 1.1.xx *************************
	foreach($userA as $userB)
	{
		$temp = array();
		foreach($userB['User'] as $key=>$value)
		{
			$temp[$key] = $value;
		}
		$userArray[] = $temp;					
	}
	*/
	$userArray = Set::extract($userA, '{n}.User');  // use this code if you are using cake 1.2.xx
	$this->set('users','{"total":'.$count.',"users":'.json_encode($userArray).'}');
    }
 
}
?>

Notice that index is blank. We’ll use index as our default controller, and our javascript will call getAllUsers() to fill our grid with json data. If you have ever debugged a cake array, you’ll notice that

$userA = $this->User->findAll(null,'*','last_name ASC');

will return something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$users = array
(
	0 => array
	(
		'User' => array
		(
			'id' => 1,
			'last_name' => 'Jones',
			'first_name' => 'Paul'
		)
	),
	1 => array
	(
		'User' => array
		(
			'id' => 2,
			'last_name' => 'Smith',
			'first_name' => 'Bill'
		)
	)
)

What we really need is an array that looks more like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$users = array
(
	0 => array
	(
		'id' => 1,
		'last_name' => 'Jones',
		'first_name' => 'Paul'
	),
	1 => array
	(
		'id' => 2,
		'last_name' => 'Smith',
		'first_name' => 'Bill'
	)
)

In cake 1.2, you can use

1
$userArray = Set::extract($userA, '{n}.User');

to extract all the ‘user’ arrays and put them into userArray. If you are not using cake 1.2, you have to use a for loop. I did things this way to start with, and just commented it out when I learned how to use Set::extract.

There are several different ways to take our database info and turn it into json data. I use php5 and have enabled json, so I used this in the controller:

1
$this->set('users','{"total":'.$count.',"users":'.json_encode($userArray).'}');

In the view, put this:

1
<?php echo $users; ?>

You can also do this the cake way (not sure if it works in 1.1). In the controller, put this in place of the above line:

1
2
$this->set('total', $count);
$this->set('users',$userArray);

In the view, put this:

1
<?php echo '{"total":'.$total.', "users":'.$javascript->Object($users).'}'; ?>

This will work with php4 or php5.

Now for the fun stuff. In myScript.js, put the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Ext.onReady(function(){
    /******
     ****** host holds the name of my host computer.  I did this because of restrictions on making remote data requests.  If the 
     ****** host is localhost, things look great from my development machine.  If I try to view my page from another computer,
     ****** though, I get errors and nothing happens.  I set my host to tc-mark-lap (the name of my development computer).  If I 
     ****** view my page with localhost in the url, I get an error.  If I view it with tc-mark-lap, everything works.  This way,
     ****** I can view pages from my laptop or from a remote machine.  I'll have to remember to change this when I deploy to my
     ****** production server, though.  I might be able to set this in my controller or in a config table and use the javascript
     ****** helper to set it at runtime.  I'll have to check on that sometime.
     ******/
    var host = 'tc-mark-lap';
 
    //This is the datastore.  My json data will be loaded remotely, then stored in the datastore.  
    //I used the HttpProxy because I'm accessing data on my local machine
    //In my json reader, I define the fields I should get from my json data (id, last_name, first_name, etc.
    var ds = new Ext.data.Store({	
        proxy: new Ext.data.HttpProxy({url: 'http://'+host+'/ekklesia3/users/getAllUsers'}),  //note that I used host in the url
        reader: new Ext.data.JsonReader({
        root: 'users',
	totalProperty: 'total',
        id: 'id'
        },[ 'id','last_name', 'first_name', 'address1', 'address2', 'city', 'state', 'zip', 'homePhone', 'cellPhone', 'otherPhone', 'birthdate', 'grade', 'school_id', 'school'])
    });  
 
    //This is the column model.  This defines the columns in my datagrid.
    //It also maps each column with the appropriate json data from my database (dataIndex).
    var cm = new Ext.grid.ColumnModel([
        {id: 'grid-paging', header: "ID",dataIndex: 'id', width: 100, hidden: true},
	{header: "Last Name", dataIndex: 'last_name', width: 100},
	{header: "First Name", dataIndex: 'first_name', width: 100},
	{header: "Address1", dataIndex: 'address1', width: 100},
	{header: "Address2", dataIndex: 'address2', width: 100},
	{header: "City", dataIndex: 'city', width: 100},
	{header: "State", dataIndex: 'state', width: 100},
	{header: "Zip", dataIndex: 'zip', width: 100}
    ]);
 
    //Here's where we define our datagrid.  Notice 'grid-paging' - 
    //that's the div in our layout that we want to render the grid to.
    //We also have to specify our dataStore and our columnModel.
    //I have no idea what selModel and enableColLock do :-)
    var grid = new Ext.grid.EditorGrid('grid-paging', {
        ds: ds,
	cm: cm,
	selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),
        enableColLock:false
    });
 
    //This sets a layout for our gridpanel div.  I'll try to do a tutorial on 
    //layouts some other time.
    var layout = Ext.BorderLayout.create({
        center: {
            margins:{left:2,top:3,right:2,bottom:3},
            panels: [new Ext.GridPanel(grid)]
        }
    }, 'grid-panel');
 
    grid.render();  //This renders our grid
    ds.load(); //This loads data from the database into the datastore.
})

The comments should explain everything here. This is more of a “Don’t ask questions, it just works” example, since I’m not quite sure how all the extjs stuff works myself at the moment.

Anyway, we now have a working datagrid. I hope that helps someone :-)
hydra12

Writing Multiple Rows at One Time in CakePHP

Filed under: Cake — admin at 10:16 am on Friday, November 16, 2007

I’m working on an application where I can keep track of who was at a meeting. I have a users table and a meetings table. Meeting belongsto User, and User hasMany Meeting. I wanted to have a form that shows the meeting date and a list of users with checkboxes next to each user name. When I click submit, I want to save the data in my meetings table.

Since User hasMany Meeting, I did this in my Users controller. I made a new function (called index2 here) that looks like this (explanation is in the comments):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
function index2()
{
	//turn off recursive search.  We just need names.
	$this->User->recursive = 0;
	//get all the user names and ids
	$users = $this->User->findAll(null,array('id','name'));
	$this->set('users', $users);
	if(!empty($this->data))
	{
		//set some variables for data parsing
		$date = null;
		$day = null;
		$month = null;
		$year = null;
 
		$saved = 0;		//keep track of how many rows are saved
 
		//Copy $this->data and then set $this->data to null.
		$tempData = $this->data;
		$this->data = null;
 
		//loop through the data and assign it in various ways
		foreach($tempData['Meeting'] as $id => $value)
		{
			//extract month, day, and year for saving later
			//everything else in $tempData['Meeting'] is a userID and checkbox value
			if($id == 'date_month')
			{
				$month = $value;
			}
			elseif($id == 'date_day')
			{
				$day = $value;
			}
			elseif($id == 'date_year')
			{
				$year = $value;
			}
			else
			{
				//set this to null or else it will only save one row and over-write
				//it with each loop iteration
				$this->User->Meeting->id = null;
 
				//set the date and add it to $this->data
				$this->data['date'] = $year.'-'.$month.'-'.$day;
 
				//set user_id and present and add to $this->data
				$this->data['user_id'] = $id;
				$this->data['present'] = $value;
 
				//save $this->data to Meeting and, if successfull, change $saved
				if($this->User->Meeting->save($this->data))
				{
					$saved += 1;
				}
			}
		}
 
		//Check to see if $saved == number of users.  If so, everything saved correctly
		if(count($users) == $saved)
		{
			$this->flash('Saved.', '/meetings/index2');
		}
		else
		{
			$this->flash('Error','/meetings/index2');
		}
	}
}

This example is kind of complicated because of what I was trying to do. The important things are these:

  • Loop through your data
  • Put the data you want to save into an array
  • Set the id to null
  • Save the data
  • Do it all again (and again and again . . .)

I hope that helps someone!
hydra12

Find unique table rows in CakePHP

Filed under: Cake — admin at 8:44 am on Friday, November 16, 2007

I was searching the CakePHP group for a way to use DISTINCT when querying the database. I knew I could do this by writing a regular SQL query, but I wanted to do it in a more ‘cakey’ way. Here’s what I found:

1
$this->ModelName->findAll(null, 'DISTINCT`ModelName`.`RowName`')

So if I had a table called models with a corresponding model called Meeting, and I want to find unique meeting dates (if I have several meeting entries that occur on the same date, I’ll only get one date back), I’d do this:

1
$this->Meeting->findAll(null, 'DISTINCT `Meeting`.`date`')

Pretty cool, huh?

Filed under: Uncategorized — admin at 9:44 pm on Tuesday, August 21, 2007

How Kids Can Work at Home: Introducing Google Notebook and Google Docs

Wouldn’t it be great if every student had a computer at home? Wouldn’t it be great if they all had the same software that we have at school? Have you ever had a student write their research paper in Microsoft Works, only to find out that you can’t open it at school since we don’t have Works, and Word won’t open it? Google Notebook and Google Docs will help fix some of these issues.

Google Notebook is just what it sounds like – a way to take notes while doing internet research. Think of it as a way to keep all your note cards on the internet and access them at school, at home, or wherever. Google Docs is a web-based word processor that will save in Word and PDF formats. It can be accessed from any computer with internet access.

Interested? Read on to learn how to use Google Notebook and Google Docs.

Register for a Google account.

  1. Go to www.google.com/notebook/.
  2. Click the ‘No Google Account? Sign up’ link.
  3. Enter a current e-mail address and a password (minimum of 8 characters long).
  4. Uncheck ‘Enable Web History’.
  5. Fill out the ‘Word Verification’ box.
  6. Click ‘I accept. Create my account.’

  1. Google will e-mail you a confirmation page to enable your account.
  2. Click the link in the e-mail to activate your account

Using Google Notebook with the Browser Extension

1. Find a web page with information you want to add to your notebook.

2. Highlight the information you want to add.

3. Right-click on the highlighted information and select ‘Note This (Google Notebook)’

Using Google Notebook without the Browser Extension

  1. Copy the information you want to add to your notebook.
  2. Go to your notebook (another browser window)
  3. Click ‘New note’
  4. Paste the information into the note. If you want the web site address, you have to paste that in, too.

Sharing a Notebook

  1. Click ‘Sharing Options’
  2. Add a list of e-mail addresses you’d like to share with.
  3. Type a short note to e-mail to the people you are sharing with.

Showing the Date of all Notes

  1. Click ‘Tools’
  2. Select ‘Show Note Details’

Print Your Notes

  1. Click ‘Tools’
  2. Select ‘Export to Google Docs’
  3. Print from Google Docs

- or –

  1. Click ‘Tools’
  2. Click ‘Print’

Working with Google Docs

Opening Google Docs

  1. Go to docs.google.com

- or -

  1. In Google Notebook, click ‘Tools’ and choose ‘Export to Google Docs’

Working in Google Docs

- Google Docs works very much like Microsoft Word.

- The Edit and Insert tabs should all be familiar.

- The Revisions tab keeps track of your document as you add to it or save it. You can see the different versions of your document, and even go back to a previous revision. It’s kind of like using the undo button.

Sharing a Google Doc

  1. You can share a document in Google Docs by clicking the share tab on the right. It works similarly to sharing with Google Notebook. You can make someone a collaborator (they can edit the document) or a viewer (they can see the document, but not edit it.)
  2. Collaborative sharing would be great for group projects . . .

Publishing a Google Doc

  1. Publishing makes a document accessible for anyone to view. The page gets it’s own Google URL.
  2. You can also publish your document to your blog if you have one set up.

Next Page »