Debugging PHP with MAMP 2, PHPStorm 4, OS X 10.7

| | Comments (0)

Getting this configured is simple enough, once you read 10,000 web pages. MAMP 2.0.5 ships with xdebug installed, but in my experience it does not work - at least, it does not work for me, on my 2.66 Ghz MacBook Pro 17”, running OS X 10.7.3. Internet research seems to indicate that this may be a 32bit vs 64bit problem.

So, here’s what I did to make it work:

First - Don’t use the MAMP built-in xdebug.so file. In your MAMP php.ini file there’s this line:

zend_extension="/Applications/MAMP/bin/php5.3/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so"

Replace it with this line:

zend_extension="/usr/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so"

OS X ships with a working version of xdebug - that’s what we’re using here.

Second - don’t use Chrome. At least for me, Chrome (I’m using the beta channel, so that may be part of the issue), does not work with the PHPStorm debugger - breakpoints are never triggered. Firefox (beta as well) works fine.

With the above two constraints, you can then follow the PHPStorm documentation on creating a zero-configuration debugging environment (basically, create a “PHP Web Application” debugging configuration), and everything will work correctly. In my case, I’m calling PHP code via XHR from an ExtJS front-end - PHP breakpoints work perfectly, I can step through code, examine variables, etc etc.

Add "setLabel" to ExtJS 4 fields...

| | Comments (0)

A trivial override:

Ext.form.field.Base.override({
    setLabel: function (text) {
        if (this.rendered) {
            Ext.get(this.labelEl.id).update(text);
        }
        this.fieldLabel = text;
    }
});

Make ExtJS 4 disabled fields darker

| | Comments (0)

I find the disabled fields in ExtJS 4 (and 3) too light, especially in Safari/Chrome. Just add this to your application’s CSS file to make them darker:

.x-item-disabled {
    color: #888888 !important;
    -moz-opacity: 100;
    opacity: 1;
}

.x-form-item-label .x-item-disabled {
    color: #888888 !important;
    -moz-opacity: 100;
    opacity: 1;
}

When installing Ubuntu 11 under VMWare Fusion it’s likely that the new Ubuntu “Unity” interface will not be enabled - you’ll just get some brief message during the install process or boot that the hardware doesn’t support it. I’m not 100% certain that this is a universal fix, but in my case using the “Additional Drivers” option under the “Administration” menu fixed the problem:

Additional drivers ubuntu

In the above image the “VMWare Client Tools” driver has been installed. When the “Additional Drivers” was initially displayed it was not - once it was installed I just restarted the Ubuntu VM and Unity started working.

ExtJS 3 - How to make a draggable Panel

| | Comments (1)

Just creating an Ext.Panel with ‘draggable’ set to true will give you a panel that you can drag around, but you need to override the ‘onDrag’ and ‘endDrag’ methods to track the position of the panel when it’s being dragged and set it to that position when the drag ends.

 

var panel = new Ext.Panel({
    draggable: {
      insertProxy: false,
      onDrag: function(e) {
        var el = this.proxy.getEl();
        this.x = el.getLeft(true);
        this.y = el.getTop(true);
      },
      endDrag: function(e) {
        this.panel.setPosition(this.x, this.y);
      }
    },
    title: 'Panel',
    width: 400,
    height: 400,
    x: 20,
    y: 20
  });

How to have an image that’s both draggable & resizable:

 

Ext.onReady(function() {
var el = Ext.get('image1');
el.dd = new Ext.dd.DDProxy('image1', 'group');
var r = new Ext.Resizable('image1', {
    preserveRatio: true,
    width: 400,
    height: 300,
    resizeChild: true
  });
});

 

The above assumes you have your image wrapped in a <div> with an id of “image1”, ie:

<div id=”image1”><img src=”images/test1.jpg”/></div>

 

In ExtJS 3.x to listen for double-click events on a GridPanel you attach a listener to the GridPanel like this:

this.on('rowdblclick', function(eventGrid, rowIndex, e) {
  console.log('double click');
}, this);

 

In ExtJS 4.0 you need to listen for events on the GridPanel’s view, via the “viewConfig”:

viewConfig: {
listeners: {
dblclick: function(dataview, index, item, e) { console.log('dblclick'); } } }

 

In my case, I wanted the GridPanel to fire a ‘rowdblclick’ event just like it did in Ext 3.x, so I defined my Ext 4.x GridPanel class like this:

Ext.define('MyGridPanel', {
  extend: 'Ext.grid.GridPanel',
  viewConfig: {
listeners: {
'dblclick': {
fn: function(dataview, index, item, e) {
var gridPanel = this.ownerCt.ownerCt;
gridPanel.fireEvent('rowdblclick', this, index, e);
}
}
}
},
initComponent: function() {
    this.addEvents(
      'rowdblclick'
      );
    this.callParent(arguments);
  }
});

 

The “this.ownerCt.ownerCt” in the handler seems like hackery to me, but for now at least, in PR3, it works.  Anyone have a better solution?

 

UPDATE FOR PR4:

The line “var gridPanel = this.ownerCt.ownerCt;” should be “var gridPanel = this.ownerCt;”

 

ExtJS cursor position in a TextArea or TextField

| | Comments (0)


Say you have a standard ExtJS TextArea with a ‘keyup’ event listener, ie:

var commentsField = new Ext.form.TextArea({
    fieldLabel: 'Comments',
    name: 'Comments',
    enableKeyEvents: true
});

commentsField.on('keyup', function(field, e) {

    // Here's how you get the current cursor position/selection range:

    var s, e;

    if (Ext.isIE) {
        var bookmark = document.selection.createRange().getBookmark();
        var selection = field.el.dom.createTextRange();
        selection.moveToBookmark(bookmark);

        var before = field.el.dom.createTextRange();
        before.collapse(true);
        before.setEndPoint("EndToStart", selection);

        var selLength = selection.text.length;

        s = before.text.length;
        e = s + selLength;

    } else {
        s = field.el.dom.selectionStart;
        e = field.el.dom.selectionEnd;
    }
}, this);



Just in case anyone would like to save the hour or so of Googling it took me to figure this out.

RESTful store example as a pre-configured class

| | Comments (2)

The ExtJS 3.2+ examples include a “RESTful store” which is a very interesting no-code way to get full CRUD behaviour from a GridPanel. Unfortunately the example is not written with a reusable structure - here is the same example, but as a pre-configured class:


Ext.onReady(function() {
            Ext.QuickTips.init();

            var TheGrid = Ext.extend(Ext.grid.GridPanel, {
                        title: 'Users',
                        frame: true,
                        height: 300,
                        width: 500,
                        viewConfig: {
                            forceFit: true
                        },
                        editor: new Ext.ux.grid.RowEditor({
                                    saveText: 'Update'
                                }),


                        onAdd: function(btn, ev) {
                            var u = new this.store.recordType({
                                        first: '',
                                        last: '',
                                        email: ''
                                    });
                            this.editor.stopEditing();
                            this.store.insert(0, u);
                            this.editor.startEditing(0);
                        },


                        onDelete: function() {
                            var rec = this.getSelectionModel().getSelected();
                            if (rec) {
                                this.store.remove(rec);
                            }
                        },


                        initComponent: function() {
                            var proxy = new Ext.data.HttpProxy({
                                        url: 'app.php/users'
                                    });

                            var reader = new Ext.data.JsonReader({
                                        totalProperty: 'total',
                                        successProperty: 'success',
                                        idProperty: 'id',
                                        root: 'data',
                                        messageProperty: 'message' // attribute in server response for user message...
                                    }, [{
                                                name: 'id'
                                            }, {
                                                name: 'email'
                                            }, {
                                                name: 'first',
                                                allowBlank: false
                                            }, {
                                                name: 'last'
                                            }]);

                            var writer = new Ext.data.JsonWriter({
                                        encode: false
                                    });

                            var store = new Ext.data.Store({
                                        restful: true,
                                        proxy: proxy,
                                        reader: reader,
                                        writer: writer
                                    });

                            var config = {
                                store: store,
                                plugins: [this.editor],
                                columns: [{
                                            header: "ID",
                                            width: 40,
                                            sortable: true,
                                            dataIndex: 'id'
                                        }, {
                                            header: "Email",
                                            width: 100,
                                            sortable: true,
                                            dataIndex: 'email',
                                            editor: new Ext.form.TextField({})
                                        }, {
                                            header: "First",
                                            width: 50,
                                            sortable: true,
                                            dataIndex: 'first',
                                            editor: new Ext.form.TextField({})
                                        }, {
                                            header: "Last",
                                            width: 50,
                                            sortable: true,
                                            dataIndex: 'last',
                                            editor: new Ext.form.TextField({})
                                        }],
                                tbar: [{
                                            text: 'Add',
                                            iconCls: 'silk-add',
                                            handler: this.onAdd,
                                            scope: this
                                        }, '-', {
                                            text: 'Delete',
                                            iconCls: 'silk-delete',
                                            handler: this.onDelete,
                                            scope: this
                                        }, '-']
                            };

                            Ext.apply(this, Ext.apply(this.initialConfig, config));
                            TheGrid.superclass.initComponent.apply(this, arguments);

                        },


                        onRender: function() {
                            this.store.load();
                            TheGrid.superclass.onRender.apply(this, arguments);
                        }
                    });
            Ext.reg('my_grid', TheGrid);



            var w = new Ext.Window({
                        modal: true,
                        items: {
                            xtype: 'my_grid',
                            title: 'Panel 1'
                        }
                    });
            w.show();
        });


Using the 'ref' option in ExtJS 3.x

| | Comments (0)

As with so many things in ExtJS, the ‘ref’ option introduced in 3.0 is not very well documented, at least as far as I can tell. Which is unfortunate, because it’s extremely useful, and drastically reduces the need for ids. Here’s an example of how to use it:

Ext.onReady(function() {
            Ext.BLANK_IMAGE_URL = 'ext/resources/images/default/s.gif';
            Ext.QuickTips.init();


            // Define a simple component

            MyComponent = Ext.extend(Ext.form.FormPanel, {
                        frame: true,

                        initComponent: function() {
                            var config = {
                                items: [{
                                            xtype: 'textfield',
                                            fieldLabel: 'Name'
                                        }, {
                                            xtype: 'textfield',
                                            fieldLabel: 'Address'
                                        }],
                                bbar: ['->', {
                                            text: 'Cancel',
                                            minWidth: 100,
                                            ref: '../cancelButton' 
                                        }, {
                                            text: 'Save',
                                            minWidth: 100,
                                            ref: '../saveButton' 
                                        }]
                            };

                            Ext.apply(this, Ext.apply(this.initialConfig, config));
                            MyComponent.superclass.initComponent.apply(this, arguments);

                        }
                    });
            Ext.reg('my_component_xtype', MyComponent);


            // Create a display a window with the panel in it...

            var w = new Ext.Window({
                        modal: true,
                        items: {
                            xtype: 'my_component_xtype',
                            title: 'Panel 1',
                            ref: 'theFormPanel'
                        }
                    });
            w.show();


            // See how we can use the references...

            w.theFormPanel.saveButton.on('click', function() {
                        console.log('Save was clicked');
                    }, this);

            console.log(w.theFormPanel.title);
        });

Find recent content on the main index or look in the archives to find all content.

Recent Assets

Tag Cloud

Pages

Powered by Movable Type 4.34-en