CiviCRM Community Forums (archive)

*

News:

Have a question about CiviCRM?
Get it answered quickly at the new
CiviCRM Stack Exchange Q+A site

This forum was archived on 25 November 2017. Learn more.
How to get involved.
What to do if you think you've found a bug.



  • CiviCRM Community Forums (archive) »
  • Discussion »
  • Extensions (Moderators: mathieu, totten, kasiawaka) »
  • Adding php scripts without being encumbered by smarty and CRM_Core_Page
Pages: [1]

Author Topic: Adding php scripts without being encumbered by smarty and CRM_Core_Page  (Read 2882 times)

awasson

  • I post frequently
  • ***
  • Posts: 230
  • Karma: 7
  • Living in a world of Drupal / CiviCRM
    • My Company: Luna Design
  • CiviCRM version: Latest
  • CMS version: Drupal 6/7/8
  • MySQL version: 5.x
  • PHP version: 5.3.x
Adding php scripts without being encumbered by smarty and CRM_Core_Page
December 23, 2012, 04:14:16 pm
Hey all,

In my latest creation which I hope to get out for testing in the next week, I need to create and call some php scripts that don't need all of the trimmings that come with a page in civiCRM.

1) One is a PHP script that I'm calling with a jQuery ajax call to change a session variable. The code is quite simple and returns a one or a zero

Currently, in order to add this page to civiCRM's routing table, I used civix generate:page which in turn stubbed out the page.php and page.tpl files. I'm not using the tpl file and I stripped the php file of everything except for require_once 'CRM/Core/Page.php';

This actually works fine and the session variable is changed by the ajax call however if I look at the console in Firebug, the page I am requesting errors out with a Page 500 error so I wonder if something is going on than needs to be dealt with in another way.

* If I avoid the civix created URL, add session_start(), remove require_once 'CRM/Core/Page.php' and call the URL directly via a long URL (/sites/all/extensions/my_extension_name/CRM/Civicpd/Page/ReportYear.php) it works without the 500 error but the session variable is not affected so it would appear that in order to work with the session variable that is specific to this session, I must access the URL via the CRM_Utils_System.


2) My second script will be a page that is called via a "Contact Record" tab that I have added using function civicpd_civicrm_tabs( &$tabs, $contactID ); The idea is to provide the ability for Admins to be able to click on the tab and review/edit a member's Continuing Professional Development log. The code I'm using is as follows:

Code: [Select]
// Adding a tab to the contact record
function civicpd_civicrm_tabs( &$tabs, $contactID ) {
    // let's add a new tab... In the real world, you would create a url which would
    // return an html snippet etc.
    $url = CRM_Utils_System::url('civicrm/civicdp/report');
    $tabs[] = array( 'id'    => 'CDP Activities',
                     'url'   => $url,
                     'title' => 'CDP Activities',
                     'weight' => 300 );
}

This indeed creates my tab but when I click on it it loads a page within a page so that the content area has a full page within it. I just want to be able to load the guts of my page in so I can produce a report that can be edited.

 
I realize that this has gotten into some of the murky details of what I'm doing so hopefully it makes sense and you can provide some direction.

Thanks,
Andrew
 
My CiviCRM Extension Workshop: https://github.com/awasson

Donald Lobo

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 15963
  • Karma: 470
    • CiviCRM site
  • CiviCRM version: 4.2+
  • CMS version: Drupal 7, Joomla 2.5+
  • MySQL version: 5.5.x
  • PHP version: 5.4.x
Re: Adding php scripts without being encumbered by smarty and CRM_Core_Page
December 23, 2012, 05:22:02 pm

1. can u clarify with "page i am requesting errors out ..."? is this the page that is making the ajax call?

2. try sending the params:

$url = CRM_Utils_System::url( 'civicrm/civicdp/report', "reset=1&snippet=2");

basically that call tells civi to just send the contents of the page knowing it will be rendered in an existing context

lobo
A new CiviCRM Q&A resource needs YOUR help to get started. Visit our StackExchange proposed site, sign up and vote on 5 questions

awasson

  • I post frequently
  • ***
  • Posts: 230
  • Karma: 7
  • Living in a world of Drupal / CiviCRM
    • My Company: Luna Design
  • CiviCRM version: Latest
  • CMS version: Drupal 6/7/8
  • MySQL version: 5.x
  • PHP version: 5.3.x
Re: Adding php scripts without being encumbered by smarty and CRM_Core_Page
December 23, 2012, 05:55:00 pm
Thanks Lobo,

$url = CRM_Utils_System::url( 'civicrm/civicpd/report', "reset=1&snippet=2"); works perfectly!

Can I use that to form URLS from within that report so that can link from the report to an editing page that will also be wrapped in the Contact Record? That would be ideal  ;D

Regarding the page with the 500 Error... Here's the details:

On the report page I have a drop-down select tag populated with years (2012, 2011, etc...) When a year is selected it makes the following call:

Code: [Select]
<script>
var jq = jQuery.noConflict();

jq('#select_year').change(function() {
var reportyear = jq(this).attr('value');

jq.post("/civicrm/civicpd/reportyear",
{ new_year: reportyear }

// At the moment this is posting the report year page
// but the response header returns a 500 Internal Server Error


);

});
</script>
 

In Firebug the actual response HTML message looks correct... It returns a 1 when it is successful and it is returning a 1 in the Response HTML according to the Firebug console. If I call it directly (http://localhost/civicrm/civicpd/reportyear?new_year=2012) it responds just fine and returns a 1 

The code to make it happen is equally as simple:

Code: [Select]
<?php
require_once 
'CRM/Core/Page.php';

if(isset($_REQUEST['new_year'])) {
$new_year = $_REQUEST['new_year'];
$_SESSION["report_year"] = $new_year;
$output = 1;
} else {
$output = 0;
}

print $output;

?>

« Last Edit: December 24, 2012, 08:33:51 am by awasson »
My CiviCRM Extension Workshop: https://github.com/awasson

Donald Lobo

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 15963
  • Karma: 470
    • CiviCRM site
  • CiviCRM version: 4.2+
  • CMS version: Drupal 7, Joomla 2.5+
  • MySQL version: 5.5.x
  • PHP version: 5.4.x
Re: Adding php scripts without being encumbered by smarty and CRM_Core_Page
December 24, 2012, 07:43:20 am

1. sorry dont know about the 500 error

2. pretty sure u can use that url for links, since a link renders the whole page. you can however use that url within a javascript snippet etc

lobo
A new CiviCRM Q&A resource needs YOUR help to get started. Visit our StackExchange proposed site, sign up and vote on 5 questions

awasson

  • I post frequently
  • ***
  • Posts: 230
  • Karma: 7
  • Living in a world of Drupal / CiviCRM
    • My Company: Luna Design
  • CiviCRM version: Latest
  • CMS version: Drupal 6/7/8
  • MySQL version: 5.x
  • PHP version: 5.3.x
Re: Adding php scripts without being encumbered by smarty and CRM_Core_Page
December 24, 2012, 08:55:43 am
Thanks Lobo.

I'll keep plugging away at it. It might be something to do with the Apache setup I have on my local machine that's causing the trouble. I'll take it to a hosted test site and see if there's a difference.

Andrew


My CiviCRM Extension Workshop: https://github.com/awasson

awasson

  • I post frequently
  • ***
  • Posts: 230
  • Karma: 7
  • Living in a world of Drupal / CiviCRM
    • My Company: Luna Design
  • CiviCRM version: Latest
  • CMS version: Drupal 6/7/8
  • MySQL version: 5.x
  • PHP version: 5.3.x
Re: Adding php scripts without being encumbered by smarty and CRM_Core_Page
December 24, 2012, 10:28:13 am
Ok, I'm going to approach this from a different direction.

I'll assume that I can't use jQuery to post to the URL that has been created through civiCRM's menu routing system so I'll use PHP to get the virtual path to the script I need and then call it via the jQuery function. The URL is something like: /sites/all/extensions/civicpd/CRM/Civicpd/Page/ReportYear.php 

Using that in the following jQuery call works and returns a 1 in the data:

Code: [Select]
var jq = jQuery.noConflict();

jq('#select_year').change(function() {
var reportyear = jq(this).attr('value');

jq.post("/sites/all/extensions/ca.lunahost.civicpd/CRM/Civicpd/Page/ReportYear.php",
{ new_year : reportyear }

, function(data) {
      alert("Data Loaded: " + data);
  }

);

});

The PHP is as follows:

Code: [Select]
<?php

// This script is called via jQuery.post() and sets the session year variable 

session_start();

if(isset($_REQUEST['new_year'])) {
$new_year = $_REQUEST['new_year'];
$_SESSION["report_year"] = $new_year;
$output = 1;
} else {
$output = 0;
}
print $output; 

?>



The problem now is that the session that the jQuery script runs in appears to be a different session for the one that civiCRM is running in because although it apparently changes the session as defined by the php script, it is not the same session in civiCRM.

Any ideas about this?

Andrew
My CiviCRM Extension Workshop: https://github.com/awasson

awasson

  • I post frequently
  • ***
  • Posts: 230
  • Karma: 7
  • Living in a world of Drupal / CiviCRM
    • My Company: Luna Design
  • CiviCRM version: Latest
  • CMS version: Drupal 6/7/8
  • MySQL version: 5.x
  • PHP version: 5.3.x
Re: Adding php scripts without being encumbered by smarty and CRM_Core_Page
December 24, 2012, 02:18:32 pm
Well, I think I'm at a good place with this for the moment. I've gotten rid of the Error 500.
 
Since I can't really do this any other way, I've gone back to dealing with the ReportYear.php script as a proper MV page within civiCRM:

ReportYear.php
Code: [Select]
<?php

require_once 
'CRM/Core/Page.php';

class CRM_Civicpd_Page_ReportYear extends CRM_Core_Page {
  function run() {
  
  // This script is called via jQuery.post() and sets the session year variable 
  if(isset($_REQUEST['new_year'])) {
$new_year = $_REQUEST['new_year'];
$_SESSION['report_year'] = $new_year;
$output = 1;
  } else {
$output = 0;
  }

  $this->assign('output', $output);

  parent::run();

}
}

ReportYear.tpl
Code: [Select]
{$output}

This is called in the jQuery.onchange function as follows:
Code: [Select]
<script type="text/javascript">
<!--
var jq = jQuery.noConflict();

jQuery(function(){


jq('#select_year').change(function() {
var reportyear = jq(this).attr('value');

jq.post("/civicrm/civicpd/reportyear?new_year=" + reportyear,

jq('.report-year').text(reportyear),

function(data) {
      /**
      * I would like to pull data from the response and then refresh the page content
      * but I can't really post to the page without an error so I'm sending the arguments
      * via the querystring for now and just refreshing the page.
      */
      window.setTimeout('location.reload()', 0);
  }

);

});

});

//-->
</script>

My next trick will be to query the database with ReportYear.php and then grab the updated data from the jQuery call and repopulate the report page without a refresh.

Wish me luck!
My CiviCRM Extension Workshop: https://github.com/awasson

totten

  • Administrator
  • Ask me questions
  • *****
  • Posts: 695
  • Karma: 64
Re: Adding php scripts without being encumbered by smarty and CRM_Core_Page
January 05, 2013, 03:23:45 pm
It may be too late for this comment to be useful, but...

It makes sense that the session-management issue is addressed by putting the code inside the CRM_Civicpd_Page_ReportYear::run() function. When the logic runs outside the page-controller class, the behavior is a bit undefined -- it basically runs as soon as the .php file is parsed, which could come before some of the bootstrapping/environment-setup is complete. Moreover, a basic PHP session_start() may disagree with the CMS's session-management practices. When putting the code inside run(), it's guaranteed to run at the right time.

For AJAX callbacks, there are two conventions that can be helpful:

1. If you implement a PHP function which follows the API conventions (e.g. with "civix generate:api"), then the function can be invoked easily with a jQuery helper (or via REST, PHP, CLI, drush, ...). See also:

http://wiki.civicrm.org/confluence/display/CRMDOC42/Create+a+Module+Extension#CreateaModuleExtension-AddanAPIfunction
http://wiki.civicrm.org/confluence/display/CRMDOC42/API+Reference#APIReference-AJAX

2.  In a lot of core code, the convention is to implement a page-controller that ends with "echo $output; CRM_Utils_System::civiExit();". This short-circuits processing so that neither Smarty nor the CMS will manipulate the output.

You can see examples like CRM_Case_Page_AJAX (CRM/Case/xml/Menu/Case.xml) or CRM_Mailing_Page_AJAX (CRM/Mailing/xml/Menu/Mailing.xml).

Aside: These examples deviate a bit from civix templates. In civix templates, the routing rules specify the page-controller as a class ("CRM_Myextension_Page_Mypage"). In these examples, the routing rules specify the page-controller as a static function ("CRM_Myextension_Page_AJAX::myCallback()"). The routing system supports both, and the functionality is largely equivalent.

awasson

  • I post frequently
  • ***
  • Posts: 230
  • Karma: 7
  • Living in a world of Drupal / CiviCRM
    • My Company: Luna Design
  • CiviCRM version: Latest
  • CMS version: Drupal 6/7/8
  • MySQL version: 5.x
  • PHP version: 5.3.x
Re: Adding php scripts without being encumbered by smarty and CRM_Core_Page
January 05, 2013, 10:18:44 pm
Thanks for the reply Totten,

I'm back to using the standard civix templates and have used the print argument in my URL (?reset=1&snippet=2) to reduce the amount of html clutter sent back in the AJAX data. It looks a bit like this:

The jQuery onchange code to call the PHP page that sets the session:
Code: [Select]
<script type="text/javascript">
<!--
var jq = jQuery.noConflict();

var reportyear = jq(this).attr('value');
 
  jq.ajax({
  type: 'POST',
  url: '/civicrm/civicpd/reportyear?reset=1&snippet=2',
  data: { new_year : reportyear },
  success: function(data){
    // THIS WORKS... I CAN RETRIEVE ANY PROCESSED DATA FROM THE PHP PAGE AT THE URL ABOVE HERE WITH LIMITED CLUTTER
  }
});

//-->
</script>


At the moment I'm just refreshing the page and letting the new Session variable do it's thing but I intend to use my target to re-query the database based on the new report_year and then repopulate the page without a full refresh. Thanks for the examples, I'll have a look at them as I'm sure they will come in handy. I have 3 more modules to build once this one rolls out  :P

Thanks again!

Andrew
My CiviCRM Extension Workshop: https://github.com/awasson

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Discussion »
  • Extensions (Moderators: mathieu, totten, kasiawaka) »
  • Adding php scripts without being encumbered by smarty and CRM_Core_Page

This forum was archived on 2017-11-26.