Quick Tip – Enabling XDebug in MAMP for OSX

I’ve swapped over to MAMP for my local web development needs on OSX. I work with a variety of projects that require different versions of PHP, and MAMP allows me to change the PHP version quickly and easily. It also comes with a preconfigured MySQL instance for my database needs.

By default, XDebug is not enabled in MAMP. I found plenty of MAMP Pro posts on how to setup XDebug, but not for simple MAMP. Here’s what you need to do.

Continue reading “Quick Tip – Enabling XDebug in MAMP for OSX”

Advertisement

How to Debug Laravel Apps in PHPStorm

I’ve mentioned it before, but I REALLY like PHPStorm when I’m doing my PHP development. It’s the closest I’ve found to a Visual Studio quality IDE for the PHP environment. I use the debugger frequently, but have run into some issues trying to get Laravel apps to debug properly. After some trial and error, I’ve finally figured out how to get it working. Continue reading “How to Debug Laravel Apps in PHPStorm”

Quick Tip – Configuring Laravel Environments on Media Temple

Note: This applies to Laravel 4. I’m still looking into options for Laravel 5…

I ran into a pesky little bug today where the Laravel standard environment configuration by hostname wasn’t working on a Media Temple deployed site. After some digging and tweaking, here’s how you get it to work…

Continue reading “Quick Tip – Configuring Laravel Environments on Media Temple”

Quick Tip: How to Run CodeIgniter on PHP 5.5 and MySQL 5.6

This isn’t a “production endorsed” solution, but it’s something that can get you by in a pinch. After reformatting my MacBook Pro and installing PHP 5.5 and MySQL 5.6 on it, I found that an old CodeIgniter application I was supporting wouldn’t run for me. After some error diagnosis (and code hacking) I was able to make things work by doing the following:

1. Change your config/database.php file to use the “mysqli” database driver. The “mysql” one is for older versions and will call deprecated methods if used.

  1. Rename and remap your “Yield” class. In PHP 5.5 there is is a new yield language construct, and that will interfere with the Yield class/method that CodeIgniter uses. To fix this:
  1. Modify your hooks/Yield_hook.php file and rename the class to “Yield_hook”
  2. In your config/hooks.php file, change the first hook mapping from class “Yield” to “Yield_hook”

Once you’ve saved those files, you should be up and running.

Quick Tip: Debug PHP Scripts from the Command Line using PHPStorm 6

Quick Tip

I’m a big fan of PHPStorm. It has made my PHP development life so much easier, especially with debugging. I’ve been trying to debug a PHP script from the command line (to diagnose a cron job that runs on our server) and here’s how you can do it using PHP Storm.  Continue reading “Quick Tip: Debug PHP Scripts from the Command Line using PHPStorm 6”

Creating a Quick Website to Always Know Your PHP Configuration in OSX

PHP Info Site

Lately I’ve been doing a lot of PHP reconfigurations. I’m upgrading versions, adding/removing features, and checking whether or not XDebug was installed. The standard technique is to modify a page on your site to include the phpinfo() command to get your details, but I decided to do something a little more convenient and permanent. I decided to create my own website for PHP Info! Continue reading “Creating a Quick Website to Always Know Your PHP Configuration in OSX”

How to run PHP applications in Visual Studio 2012

A PHP app launched from Visual Studio 2012
A PHP app launched from Visual Studio 2012

Note: This post comes as a HT to this StackOverflow question, I’m just tweaking a few things to accomodate for VSMMXII…

I’m working on a project to convert a PHP application to a .Net MVC application. The initial prototype has some nice bootstrap/highcharts functionality, so I want to preview the site locally as I’m migrating the code over. Instead of starting up or installing a new editor, I wanted to take advantage of IIS Express that comes with Visual Studio 2012 to run the app. It’s really easy to setup and here’s how to do it. Continue reading “How to run PHP applications in Visual Studio 2012”

Soup to Nuts - The Complete Package

Integrating the Nivo Slider into a CodeIgniter Site

Soup to Nuts - The Complete Package

Yesterday’s adventure in coding involved getting a slider type control integrated into the site we’re redesigning. We’re taking the old system that was PHP based with its own “templating” sytem and putting into CodeIgniter, which is the MVC framework that PyroCMS is based off of (if you remember my post from last week).

This new site features a lot of video, and there is a “slider” on the front of the page that cycles through the recent videos available. The current slider we have is functional, but out of date, and since we have jQuery at our disposal with the new site, I figured getting an existing solution that was easy to integrate and modify was in order.

Enter the Nivo Slider. I’ve worked with this slider at my old job, and really liked how you could get a basic slider off the ground really quick, but also had a lot of easy ways to extend and customize it, by using your own stylesheets or even writing your own Javascript code through some triggered events, such as when a new slide came in.

In order to make this MVC friendly to go with CodeIgniter, then plan is to create a View that has our slider HTML code in it. We can then use our video model to retrieve the videos we need. The controller on which our page resides simply needs to retrieve the desired videos and put them in the template data. Since our video objects have lots of details in them, and our image code needs a few indexing keywords in it, I decided to create a helper class that would do the “processing” of our videos in order to generate the appropriate image and caption content. That way if we needed to do some extra manipulation down the road, we only have to worry about the helper and not anything else.

Off to the code!!!!

So the meat of all of this lies in the view and the helper. Our view contains our slider code, like this:


<?php $this->load->helper('slider'); ?>

<!-- Load slider resources -->
<link rel="stylesheet" href="/css/nivo-slider.css" type="text/css" media="screen" />
<link rel="stylesheet" href="/css/nivo-slider-my-style.css" type="text/css" media="screen" />
<script src="/js/jquery.nivo.slider.pack.js" type="text/javascript"></script>

<div class="slider-wrapper">
 <div id="slider">
 <?php
 foreach(get_video_image_code($slider_videos) as $image)
 {
 echo($image);
 }
 ?>
 </div>

 <?php
 foreach(get_video_caption_code($slider_videos) as $caption)
 {
 echo($caption);
 }
 ?>
</div>

<script type="text/javascript">
$(window).load(function() {
 $('#slider').nivoSlider({
 effect:'fold', // Specify sets like: 'fold,fade,sliceDown'
 slices:15, // For slice animations
 boxCols: 8, // For box animations
 boxRows: 4, // For box animations
 animSpeed:500, // Slide transition speed
 pauseTime:6000, // How long each slide will show
 startSlide:0, // Set starting Slide (0 index)
 directionNav:true, // Next & Prev navigation
 directionNavHide:true, // Only show on hover
 controlNav:true, // 1,2,3... navigation
 controlNavThumbs:false, // Use thumbnails for Control Nav
 controlNavThumbsFromRel:false, // Use image rel for thumbs
 controlNavThumbsSearch: '.jpg', // Replace this with...
 controlNavThumbsReplace: '_thumb.jpg', // ...this in thumb Image src
 keyboardNav:true, // Use left & right arrows
 pauseOnHover:true, // Stop animation while hovering
 manualAdvance:false, // Force manual transitions
 captionOpacity:0.8, // Universal caption opacity
 prevText: 'Prev', // Prev directionNav text
 nextText: 'Next', // Next directionNav text
 beforeChange: function(){}, // Triggers before a slide transition
 afterChange: function(){}, // Triggers after a slide transition
 slideshowEnd: function(){}, // Triggers after all slides have been shown
 lastSlide: function(){}, // Triggers when last slide is shown
 afterLoad: function(){} // Triggers when slider has loaded
 });
});
</script>

This is pretty much the standard way the Nivo slider is setup. I’ve chosen to take all the “default” styling required to make things work and put them into a separate stylesheet for easier maintenance. I’ve also replaced the image and content sections with some PHP code that calls our helper method. Let’s take a look at that now.


function get_video_image_code($videos)
 {
 $results = array();
 $caption_count = 0;

 foreach($videos as $video)
 {
 $image_code = '';
 $img_path = $_SERVER['DOCUMENT_ROOT'] . '/images/videos/' . $video->id . '.jpg';

 if ($video->imageid == 0 || !file_exists($img_path))
 {
 $img_path = '/images/videos/default_video.jpg';
 }
 else
 {
 $img_path = '/images/videos/' . $video->id . '.jpg';
 }

 $image_code .= '<a href="/videos/' . $video->id . '">
 <img src="' . $img_path . '" alt="" title="#caption' . $caption_count . '" />
 </a>';

 $results[] = $image_code;
 $caption_count++;
 }

 return $results;
 }

function get_video_caption_code($videos)
 {
 $results = array();
 $caption_count = 0;

 foreach($videos as $video)
 {
 $caption_code = '<div id="caption' . $caption_count . '" class="nivo-html-caption">
 <span class="CaptionTitle">' . $video->title_billboard . '</span>
 <br/>
 <span class="CaptionDescription">' . nl2br($video->description) . '</span>
 </div>
 ';

 $results[] = $caption_code;
 $caption_count++;
 }

 return $results;
 }

You’ll notice that both methods have a caption count, which allows us to make sure our captions line up with our video images. You’ll also notice that the helpers take an array of videos as its input, because if we did our data query here, we risk the chance of a new video slipping in between method calls and then things are out of sync.

In our video model here, our slider images are named with the same Id as the video Id itself. In the event that our video images folder doesn’t have the image, or our Id specified is 0, we fall back to our default video image. One word of note. CodeIgniter’s application folder is locked out to the public, so you need to make sure that all of your CSS, Javascript, and image files reside under your public_html folder. Because of this issue, I like to use the server’s DocumentRoot property when building the file path for me to check. All the image references themselves can remain relative to the public_html folder.

In our video model, we’re using the caption field to display both the title and the description of the video they can link to. I wanted to be able to customize these a bit further than what would typically be seen, so I went ahead and wrapped each section up in a SPAN tag and gave them the class of CaptionTitle and CaptionDescription. Then in the “my-style” CSS file I can design this out a bit further.

Within our controller, we load the videos we need and call the View to render it.


$this->load->model('video_model');
$this->template_data['slider_videos'] = $this->video_model->get_recent_videos(5);

For those of you not familiar with CodeIgniter (I’m still fresh to it myself) the template_data array is what is passed down and parsed to the View for it to do its presentation with. That is why in the View code at the top it passes in the variable $slider_videos in order to process. It’s a simple “hand me down” type process, but very handy because the template_data is flushed out on every page load (preventing old data from lingering around) and handled automatically.

That’s how it all works! I wish I could put an entire “soup to nuts” functional solution here for you, but that would involved getting a lot of CodeIgniter stuff in place. However, I am including my view, helper, and the supporting image/slider files here so you should be able to modify and get this going on your own site pretty quickly. Code will be coming soon.

Enjoy!!!

Soup to Nuts - The Complete Package

Soup to Nuts: Extending the User Module in PyroCMS

Soup to Nuts - The Complete Package

I’ve been helping get a new site off the ground that uses the PyroCMS system. If you haven’t heard of it, it is a CMS (content management system) that is built on top of the CodeIgniter PHP framework. Having recently gone back into PHP and starting fresh with the MVC approach to web development, I’ve been quite impressed with how easy I’ve been able to get things up and running.

That said, I ran into one hurdle with our new site. We needed students to register on the site and track some additional information about them. I did a little digging in the forums and online, and the general recommendation was not to override the user module built into the system, because future updates might overwrite your changes or cause some incompatibilities. The preferred solution is to create your own module to store your student related data, and tie into the user module as needed.

Since there is a lot of flexibility available with MVC, this approach was easy to implement. What makes things really nice is that we can use the existing user module built into the PyroCMS system, which allows us to simply strip out the duplicate references (no need to rewrite the user model) and work from there. I like this “learn from an existing” model approach to things, because you can see how the code is supposed to generally flow within the framework.

That said, I dug down to the public/system/pyrocms/modules/users folder and copied it to a separate location for me to work with. The first thing to do was to load up the details.php file in the root of the folder and modify the basic details. It also allows you to specify an install and uninstall method, which we can leverage to create the necessary tables we need:


public function install()

{

// Create student tables and add student category to user groups.

$sql = 'CREATE TABLE IF NOT EXISTS ' . $this->db->dbprefix('student') . '

(

id int NOT NULL AUTO_INCREMENT,

user_id int NOT NULL,

age int NOT NULL,

grade_level int NOT NULL,

gender char NOT NULL,

esl char NOT NULL,

sport_id int NOT NULL,

sport_level_id int NOT NULL,

created datetime NOT NULL,

modified datetime NOT NULL,

PRIMARY KEY (id)

)

';

$this->db->query($sql);

$sql = 'CREATE TABLE IF NOT EXISTS ' . $this->db->dbprefix('student_secondary_sport') . '

(

id int NOT NULL AUTO_INCREMENT,

student_id int NOT NULL,

sport_id int NOT NULL,

created datetime NOT NULL,

modified datetime NOT NULL,

PRIMARY KEY (id)

)

';

$this->db->query($sql);

$sql = 'INSERT INTO ' . $this->db->dbprefix('groups') . ' (name, description)

VALUES (\'student\', \'Students\')';

$this->db->query($sql);

return TRUE;

}

public function uninstall()

{

// Remove student related data and module settings

$sql = 'DELETE FROM '. $this->db->dbprefix('groups') . ' WHERE name = \'student\'';

$this->db->query($sql);

$sql = 'DROP TABLE '. $this->db->dbprefix('student_secondary_sport');

$this->db->query($sql);

$sql = 'DROP TABLE '. $this->db->dbprefix('student');

$this->db->query($sql);

$sql = 'DELETE FROM '. $this->db->dbprefix('modules') . ' WHERE name = \'student\'';

$this->db->query($sql);

return TRUE;

}

Since we can call the appropriate user models and helpers, there’s no need to keep this code, so we remove a lot of files:

  • config/ion_auth.php
  • controllers/profile.php
  • language/* – leave the english folder, since you’ll want to update a few of your tags. Keep other languages if you plan on translate
  • libraries/*
  • models/profiles_m.php
  • models/ion_auth_model.php
  • flush most of your views, except for the register.php view and the admin, email, and settings subfolders

After removing the extra files, the next step is to go in and rename all of your user type files to student, or whatever you want to call them. You’ll want to go through the remaining files and weed out the methods that aren’t needed, such as login, since those are covered by the user model. After this, you need to inject the appropriate code into the appropriate methods. For instance, in the student controller, I need to retrieve all of the student related data from my view and insert that into the proper tables after a successful user insertion. The register method winds up looking like this:


/**

* Method to register a new student

* @access public

* @return void

*/

public function register()

{

// Validation rules

$validation = array(

array(

'field' => 'first_name',

'label' => 'lang:user_first_name_label',

'rules' => 'required|utf8'

),

array(

'field' => 'last_name',

'label' => 'lang:user_last_name_label',

'rules' => 'required|utf8'

),

array(

'field' => 'email',

'label' => 'lang:user_email_label',

'rules' => 'required|valid_email'

),

array(

'field' => 'password',

'label' => 'lang:user_password_label',

'rules' => 'min_length[6]|max_length[20]'

),

array(

'field' => 'confirm_password',

'label' => 'lang:user_password_confirm_label',

'rules' => 'matches[password]'

),

array(

'field' => 'username',

'label' => 'lang:user_username',

'rules' => 'required|alphanumeric|min_length[3]|max_length[20]'

),

array(

'field' => 'display_name',

'label' => 'lang:user_display_name',

'rules' => 'alphanumeric|min_length[3]|max_length[50]'

),

array(

'field' => 'active',

'label' => 'lang:user_active_label',

'rules' => ''

),

array(

'field' => 'age',

'label' => 'lang:student_age',

'rules' => 'required|integer'

),

array(

'field' => 'grade_level',

'label' => 'lang:student_grade_level',

'rules' => 'required|integer'

),

array(

'field' => 'gender',

'label' => 'lang:student_gender',

'rules' => 'required|alpha'

),

array(

'field' => 'esl',

'label' => 'lang:student_esl',

'rules' => 'required|alpha'

),

array(

'field' => 'sport_id',

'label' => 'lang:student_sport',

'rules' => 'required|numeric'

)

);

// Set the validation rules

$this->form_validation->set_rules($validation);

$email = $this->input->post('email');

$password = $this->input->post('password');

$username = $this->input->post('username');

$group_id = (int)$this->input->post('group_id');

$age = (int)$this->input->post('age');

$grade_level = (int)$this->input->post('grade_level');

$gender = $this->input->post('gender');

$esl = $this->input->post('esl');

$sport_id = (int)$this->input->post('sport_id');

$sport_level_id = (int)$this->input->post('sport_level_id');

$secondary_sport_ids = array();

$sports = get_sports();

$sportids = array_keys($sports);

foreach ($sportids as $id)

{

$secondaryid = 'secondary_sport_' . $id;

if($this->input->post($secondaryid))

{

$secondary_sport_ids[] = $id;

}

}

$user_data_array = array(

'first_name' => $this->input->post('first_name'),

'last_name' => $this->input->post('last_name'),

'display_name' => $this->input->post('display_name'),

'group_id' => (int)$this->input->post('group_id'),

'age' => (int)$this->input->post('age'),

'grade_level' => (int)$this->input->post('grade_level'),

'gender' => $this->input->post('gender'),

'esl' => $this->input->post('esl'),

'sport_id' => (int)$this->input->post('sport_id'),

'sport_level_id' => (int)$this->input->post('sport_level_id'),

'secondary_sport_ids' => $secondary_sport_ids

);

// Convert the array to an object

$user_data = new stdClass();

$user_data->first_name = $user_data_array['first_name'];

$user_data->last_name = $user_data_array['last_name'];

$user_data->display_name = $user_data_array['display_name'];

$user_data->username = $username;

$user_data->email = $email;

$user_data->password = $password;

$user_data->confirm_email = $this->input->post('confirm_email');

$user_data->group_id = (int)$this->input->post('group_id');

$user_data->age = (int)$this->input->post('age');

$user_data->grade_level = (int)$this->input->post('grade_level');

$user_data->gender = $this->input->post('gender');

$user_data->esl = $this->input->post('esl');

$user_data->sport_id = (int)$this->input->post('sport_id');

$user_data->sport_level_id = (int)$this->input->post('sport_level_id');

$user_data->secondary_sport_ids = $secondary_sport_ids;

if ($this->form_validation->run())

{

$group = $this->group_m->get($this->input->post('group_id'));

// Try to create the user

if ($id = $this->ion_auth->register($username, $password, $email, $user_data_array, $group->name))

{

// Insert the student information to the proper table and add it to the user data object.

$sql = 'INSERT INTO student (user_id, age, grade_level, gender, esl, sport_id, sport_level_id, created, modified)

VALUES (' . $this->db->escape($id) . ', '

. $this->db->escape($age) . ', '

. $this->db->escape($grade_level) . ', '

. $this->db->escape($gender) . ', '

. $this->db->escape($esl) . ', '

. $this->db->escape($sport_id) . ', '

. $this->db->escape($sport_level_id) . ',

NOW(),

NOW()

)';

$this->db->query($sql);

$student_id = $this->db->insert_id();

$user_data->student_id = $student_id;

// Insert any secondary sports for the student.

if (isset($secondary_sport_ids) && count($secondary_sport_ids > 0))

{

foreach ($secondary_sport_ids as $sportid)

{

$sql = 'INSERT INTO student_secondary_sport (student_id, sport_id, created, modified)

VALUES (' . $this->db->escape($student_id) . ', '

. $this->db->escape($sportid) . ',

NOW(),

NOW()

)';

$this->db->query($sql);

}

}

$this->session->set_flashdata(array('notice' => $this->ion_auth->messages()));

redirect('/users/activate');

}

// Can't create the user, show why

else

{

$this->data->error_string = $this->ion_auth->errors();

}

}

else

{

// Return the validation error

$this->data->error_string = $this->form_validation->error_string();

}

$this->data->user_data =& $user_data;

$this->template->title(lang('student_register_title'));

$this->template->build('register', $this->data);

}

Obviously there’s a lot more to process, but it’s a lot simpler than it looks. It’s just tricky to piece things together, at least if you’re not too familiar with CodeIgniter, PyroCMS, or MVC in general. However, I made it through it and you can too!

Once you get your module code complete, you can copy it into your addons/modules folder and then login to your site. In your Add-Ons section you should see where you can install the module, which will create your tables and get you going. PyroCMS makes it really nice this way to plug new stuff in to your site. Students can register using the proper path of /students/register, and standard users can still register using the path of /register or /users/register. In addition, with the latest 1.3 release of PyroCMS, there is an event model that has been updated. With the new event model, you could detect a user login, and then do some additional processing, such as grab the student information and add it to the $this->user object that is available in the system.

The next step for this, is to be able to abstract the module more, so that you could create custom fields for as many groups as you need. Then you could share these properties across multiple groups. For instance, you may have a property called “School” that would be needed by teachers and students, but only the “primary sport” property would be needed by the students.

I’ve gone ahead and attached the module code I’ve written, in hopes of helping you get off the ground with extending the user model in PyroCMS to meet your own needs. This code is functional on our site, but I’m sure there’s always a few tweaks or updates that would make things nicer. Please feel free to drop me a line if you see any of those.

Enjoy!

Donwload the module from the git repository.