Getting PHPUnit To Run On Local Windows Machine From Remote Server

So I’ve got PHPUnit installed on our development server, but I don’t want to log into the server every time that I want to run a test. To do this locally, I need to change the PHP.ini file settings before PHP ran PHPUnit. The reason for this is because on the development server PHP is installed at C:PHP5 but this directory doesn’t exists on my local machine, so when I open up the command line and do the following:


\pathToServerPHP5phpunit

I get ‘”C:PHP5.php.exe”‘ is not recognized as an internal or …

The reason for this is because if you look in the phpunit.bat file you’ll see that it sets the PHPBIN path to C:PHP5.php.exe so you’re computer is going to look there, no buneo. The trick is to make your computer look for all related PHP files on the server. There are probably a variety of ways to do this but what I did was the following:

1) Since I didn’t want to mess around changing the values in phpunit.bat and phpunit I just wrote a script that would bypass phpunit.bat by running PHP with custom specified include_path and extension_dir


\pathToServerPHP5php -d extension_dir="\pathToServerPHP5ext" -d include_path="\pathToServerPHP5pear; ... ; ." \pathToServerPHP5phpunit TestFile"

2) Since the web root of my applications vary and I need to run the test files from within the public domain of the application, I just wrote a batch script to ask me where the web root is and where the test file is:


@echo off
set /p website="Web root path to application (starts in publicaccess): "
set /p testfile="Where is the PHP Test file located (starts in UnitTests): "
set /p options="Additional PHPUnit options: "
pushd \pathToServerpublicDomain%website%
\pathToServerPHP5php -d extension_dir="\pathToServerPHP5ext" -d include_path="\pathToServerPHP5pear; ... ; ." \pathToServerPHP5phpunit TestFile" %options% \pathToServerUnitTests%testfile%
popd
pause

Mantis 1.2.0 and Automatic Notices (Reminder.php)

This expands on the emailing problem that I was having with Mantis.

I just had the most terrible time setting up an auto reminder with Mantis (Mantis is a bug tracking software) and a user contributed mailing reminder script (http://www.mantisbt.org/bugs/view.php?id=5887).

I’m using IIS 6 and PHP 5.3

Step 1 – Using the correct configuration function:

You need to open up reminder.php and change all of the following to use db_get_table instead of config_get


$t_user_table = config_get( 'mantis_user_table' );
$t_project_table = config_get( 'mantis_project_table' );

// In bug_get_assign_date()
$t_bug_history_table = config_get( 'mantis_bug_history_table' );
$t_bug_table = config_get( 'mantis_bug_table' );

// In user_get_assigned_bug
$t_bug_table = config_get('mantis_bug_table');

// In user_get_not_assigned_bug
$t_bug_table = config_get( 'mantis_bug_table' );

Comment out the following

// in the first for loop of user_get_not_assigned_bug
lang_push( user_pref_get_language( $row['id'] ) );

// in the second for loop of user_get_not_assigned_bug
lang_push( user_pref_get_language( $t_user_id ) );

// In email_build_bug_info()
$t_result = diff_date( $t_now_time, unixtimestamp($t_assign_date );

if( $t_result == config_get( 'first_remind' ) && bug_ok_to_send( $p_user_id, $p_bug_id ) ) {
return $t_message;
} else {
if( $t_result >= config_get( 'second_remind' ) && date_ok_to_send( $p_user_id, $p_bug_id ) ) {
return $t_message;
} else {
return '';
}
}

Near the end of reminder.php (past line 300) change
$t_email_send = email_send( $t_send_email , $t_subject, $t_message);

to


$t_email_send = email_send((object) array('email' => $t_send_email , 'subject' => $t_subject, 'body' => $t_message));

This still leaves some warnings about some lang_get() values not getting found, but I get the emails now so that’s all that I cared about.

Drupal – Import data into nodes and content types

I needed to import a whole bunch of stuff from a text file into Drupal and it involve using custom CCK types.  I found some great PHP code to do this here: http://www.rtraction.com/blog/devit/drupal-import-data-into-nodes-and-content-types.html but I wanted to do it using Python, so here is my translation of that code:


import MySQLdb
db = MySQLdb.connect(host='', user='', passwd='', db='')
cursor = db.cursor()

def insert_node(title, type,body, date = ""):

# Drupal required me to have a vid on insert.
cursor.execute("select max(vid)+1 from node");
vid = int(cursor.fetchone()[0])

# If no date value
if date == "":
sql = "INSERT INTO node (title, type, uid, created, changed, vid, promote, comment) VALUES('"+title+"','"+str(type)+"',1,UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), "+str(vid)+", 1, 2)"
else:
sql = "INSERT INTO node (title, type, uid, created, changed, vid, promote, comment) VALUES('"+title+"','"+str(type)+"',1,"+date+","+date+", "+str(vid)+", 1, 2)"

# Insert the node
cursor.execute(sql)
insert_id = int(cursor.lastrowid)
db.commit()

# Insert revision node.
sql = "INSERT INTO node_revisions (nid, title, uid, body) VALUES ('"+str(insert_id)+"', '"+title+"',1,'"+body+"')"
cursor.execute(sql)
revision_insert_id = int(cursor.lastrowid)
db.commit()

# Not sure if this code has any meaning
if insert_id > 0:
sql = "UPDATE node SET vid = "+str(revision_insert_id)+" WHERE nid = "+str(insert_id)
cursor.execute(sql)
db.commit()

return {'insert_id':insert_id, 'revision_id':revision_insert_id}

def insert_special_node(content_type, data, title = "", body = "", date = ""):

# Insert node data
data_ids = insert_node(title,content_type, body ,date)

# Get any custom columns and values
cols = []
values = []

for c in data.keys():
cols.append(c)
v = "'" + data[c].replace("'", "\'") + "'"
values.append(v)

# Create a string list out of them
col_str = ",".join(cols)
val_str = ",".join(values)

# Insert custom content data.
sql = "INSERT INTO content_type_"+content_type+" (vid, nid,"+col_str+") VALUES("+str(data_ids["revision_id"])+","+str(data_ids["insert_id"])+" ,"+val_str+")"
cursor.execute(sql)
db.commit()

Write / Read Custom Data – Zend_Session_SaveHandler_DbTable

I couldn’t find this anywhere so I’ll post it here. When storing information with sessions you sometimes might want to keep a user id, real user name, etc as part of the session. To accomplish this using Zend and a session database table:

1) Set up the database: http://framework.zend.com/manual/1.10/en/zend.session.savehandler.dbtable.html

2) To save custom data:

// Create the table adapter and then authenticate the login.
$adapter = $this->getAuthAdapter($db, $this->view->form->getValues());
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($adapter);

// If a successful login, store custom session data into the session table's datacolumn.
if($result->isValid()) {
$results = $adapter->getResultRowObject(array('id', 'username', 'firstname', 'lastname'));
$mysession = new Zend_Session_Namespace('mysession');
$mysession->id = $results->id;
$mysession->username = $results->username;
$mysession->firstname = $results->firstname ;
$mysession->lastname = $results->lastname ;
}

3) To get the custom data:

$mysession = new Zend_Session_Namespace('mysession');
echo $mysession ->id;
echo $mysession ->username;
echo $mysession ->firstname;
echo $mysession ->lastname;

Creating A Dynamic Grouped Form Element

So a common thing that I’ve always done in my forms is create a group of inputs that can be dynamically created again (through JS). For example I would allow users to add N number of contacts. To add a new one the user would click on “add” and JS would do its DOM creation and add all the new elements with name=”myname[]”. I wanted to do this with Zend and still have the JS generated content reshow up on a form submission. I’ve searched forever on how to do this, so hopefully this helps someone. (It’s probably not the best way, but it does work.)

These two tutorial helped greatly:

http://weierophinney.net/matthew/archives/212-The-simplest-Zend_Form-decorator.html (custom elements)
http://www.jeremykendall.net/2009/01/19/dynamically-adding-elements-to-zend-form/ (ajax)

Form HTML to reproduce:





The Person Element Class:

addPrefixPath(
'My_Form_Decorator',
'My/Form/Decorator',
'decorator'
);

parent::__construct($spec, $options);
$this->_fnameID = parent::getID().'FirstName';
$this->_lnameID = parent::getID().'LastName';
$this->_emailID = parent::getID().'Email';
}

public function loadDefaultDecorators()
{
if ($this->loadDefaultDecoratorsIsDisabled()) {
return;
}
$decorators = $this->getDecorators();
if (empty($decorators)) {
$this->addDecorator($this->getDecoratorName())
->addDecorator('Errors')
->addDecorator('Description', array(
'tag' => 'p',
'class' => 'description')
)
->addDecorator('HtmlTag', array(
'tag' => 'ul',
'id' => $this->getName())
);
}
}

protected function getDecoratorName(){
return 'Person';
}

public function getLabel($type){

if(isset($type)){
switch($type){
case 'firstName':
return $this->getFirstNameLabel();
case 'lastName':
return $this->getLastNameLabel();
case 'email':
return $this->getEmailLabel();
}
}
else {
return parent::getID();
// throw new Exception('Please choose a label.');
}

}

public function getID($type){

if(isset($type)){
switch($type){
case 'firstName':
return $this->getFirstNameID();
case 'lastName':
return $this->getLastNameID();
case 'email':
return $this->getEmailID();
}
}
else {
return parent::getID();
// throw new Exception('Please choose a label.');
}

}

public function getFirstNameID(){
return $this->_fnameID;
}

public function getFirstNameLabel(){
return $this->_fnameLabel;
}

public function setFirstName($value){
$this->_fname = $value;
return $this;
}

public function getFirstName(){
return $this->_fname;
}

public function getLastNameID(){
return $this->_lnameID;
}

public function getLastNameLabel(){
return $this->_lnameLabel;
}

public function setLastName($value){
$this->_lname = $value;
return $this;
}

public function getLastName(){
return $this->_lname;
}

public function getEmailID(){
return $this->_emailID;
}

public function getEmailLabel(){
return $this->_emailLabel;
}

public function setEmail($value){
$this->_email = $value;
return $this;
}

public function getEmail(){
return $this->_email;
}

public function setValue($values){
if(isset($values['firstName']) && isset($values['lastName']) && isset($values['emailName'])){
$this->setFirstName($values['firstName']);
$this->setLastName($values['lastName']);
$this->setEmail($values['email']);
}
else {
// What till validation, could add it here?
; //throw new Exception('Invaild Person, please provide a first name, last name and email.');
}

return $this;
}

public function getValue(){
return $this->getFirstName().' '.$this->getLastName().', '.$this->getEmail();
}

}

The People Decorator class:

%s';

public function render($content){
$el = $this->getElement();
if(!$el instanceof My_Form_Element_Person){
return $content;
}

$view = $el->getView();
if(!$view instanceof Zend_View_Interface){
return $content;
}
$markup = $this->wrap($this->renderFirstName($el).$this->renderLastName($el).$this->renderEmailName($el));

switch ($this->getPlacement()) {
case self::PREPEND:
return $markup . $this->getSeparator() . $content;
case self::APPEND:
default:
return $content . $this->getSeparator() . $markup;
}
}

protected function renderFirstName($el){
return $this->renderEl('firstName', $el->getFirstName(), $el);
}

protected function renderLastName($el){
return $this->renderEl('lastName', $el->getLastName(), $el);
}

protected function renderEmailName($el){
return $this->renderEl('email', $el->getEmail(), $el);
}

protected function renderEl($type, $value, $el){
$name = $el->getFullyQualifiedName();
return sprintf($this->_format, $el->getID($type), $el->getLabel($type), $el->getID($type), $name.'['.$type.']', $value);
}

protected function wrap($markup) { return '

  • '.$markup.'
  • '; }
    }

    Here is the DynamicController that handles the AJAX JS creation:

    disableLayout();
    $ajaxContext = $this->_helper->getHelper('AjaxContext');
    $ajaxContext->addActionContext('newfield', 'html')->initContext();

    $id = $this->_getParam('id', null);

    $element = new My_Form_Element_Person('person');

    // What is returned thru ajax
    $this->view->field = $element->__toString();
    }
    }

    My JS script (I use prototype) You can see how to do it with JQuery from on of the above tutorials:

    Event.observe('addElement', 'click',
    function() {
    ajaxAddField();
    }
    );
    // Get value of id - integer appended to dynamic form field names and ids
    var id = $("id").getValue();
    // Retrieve new element's html from controller
    function ajaxAddField() {

    // Update the database based on the Primary key with the new value.
    new Ajax.Request('/apply/index.php/dynamic/newfield',
    {
    method: 'post',
    parameters: {'id':'id='+id},
    onSuccess: function(el){
    $("addElement-label").insert(el.responseText);
    // Increment and store id
    $("id").val(++id);
    }
    });

    }

    The prevalidation method (in your Form class) that captures the dynamic content on submit:

    public function preValidation(array $data) {
    // Search $data for dynamically added fields using findFields callback
    $fnames = $data['person']['firstName'];
    $lnames = $data['person']['lastName'];
    $emails = $data['person']['email'];

    // For each person
    for($i=0;$isetFirstName($fnames[$i]);
    $el->setLastName($lnames[$i]);
    $el->setEmail($emails[$i]);
    $this->persons[] = $el;
    }
    }
    // Used to redisplay the new content.
    public function getPersons(){

    $els = $this->persons;
    $xhtml = '';
    foreach($els as $el => $e){
    $xhtml .= $e->__toString(); // Add HTML
    }
    return $xhtml;
    }

    In my main view I display all of the people by:

    form->getPersons() ?>

    For the newField action you need a viewscript with:

    field ?>

    That’s all of the pieces. If I get time better I’ll try to explain how to put them together. Please read this tutorial first, it will help you set up the AJAX stuff. Then just add a button element and a container and everything should work.

    What do you think??

    Zend_Form – Submitting Without MVC

    There was a time when I didn’t use MVC…


    class ContactForm extends Zend_Form {
    public function __construct($options = null) {
    parent::__construct($options);

    $this->setAction("test.php");
    $this->setMethod("post");

    $contact_name = new Zend_Form_Element_Text('contact_name');
    $contact_name->setLabel('Contact Name: ')
    ->setRequired(true)
    ->addValidator('NotEmpty');

    $submit = new Zend_Form_Element_Submit('submit');
    $submit->setLabel('Submit');

    $this->addElements(array($contact_name, $submit));
    }

    public function setView(Zend_View_Interface $view) {

    parent::setView($view);
    // Render each form element.
    foreach ($this as $item) {
    $item->setView($view);
    }
    return $this;
    }
    }
    session_start();
    if (isset($_POST['submit'])) {
    // Get the form object.
    $form = unserialize($_SESSION['myForm']);
    if ($form->isValid($_POST)) {
    echo 'success';
    }
    // Not valid, so populate the form with the sent values.
    else {
    $form->populate($formData);
    }
    }
    else {
    // Need to keep a handle on the form (I think Zend does this internally if you use the MVC approach)
    $form = new ContactForm();
    $_SESSION['myForm'] = serialize($form);
    }
    // Display your form.
    echo $form->render(new Zend_View());