Thursday, July 31, 2014

How to sort string field in Solr


We want to allow site user to sort the old Indian Arts records based on title, id & date fields. We have used Apache Solr to store the records. Well!! Solr is a standalone pre-configured product/webapp which uses Lucene. Solr is ready-to-use out of box. It is a web application that offers infrastructure related and a lot more features in addition to what Lucene offers.You can read more about the Solr here.
Sorting on text/string field works strangely in Solr. Initially I realised it worked normally but later I found its strange behavior as explained below.
If the record contains "Aany ZeRasta", "David Book". Solr shows Aany ZeRasta after David Book by default. Why? Because there is Z in 2nd word of first string. Obviously this is something that we never want. We can't use abs function but we can't use on string type. I tried by changing field type to string form text_general.

alphaOnlySort

I read somewhere that there is a type alphaOnlySort in latest solr schema. alphaOnlySort uses KeywordTokenizer along with various TokenFilterFactories to produce a sortable field that does not include some properties of the source text. This KeywordTokenizer does no actual tokenizing, so the entire input string is preserved as a single token. It removes any leading or trailing whitespace & handles case sensitivity.

Schema.xml

I created a new field title_sort & copied the values from title field as like below.
 
 

We always have to restart the solr server after schema or solrconfig.xml files edited. After reindexing I just changed my solr sort query from tite field to title_sort. Phew!!!! I got the correct sorting result for title field.

Sunday, October 6, 2013

Initialize the Joomla Framework in an external script

Last week i had to write a Joomla code in external file. The code contained joomla database queries n other stuff which I don't wanted to convert into core php. I wanted to run the code in external php file by making few changes only. Searched on Google but i found many links of old code & some snippet posted on stackoverflow didn't work. The code which i found was very large containing configuration file & database details n all unwanted stuff to access Joomla classes. You can use following code when you want to load Joomla framework outside the Joomla.

Using above snippet you can load the necessary files so that you can use Joomla classes in your PHP script. Code properly worked on Joomla 2.5 version.

Tuesday, September 10, 2013

Zoo CSV Import - Assign fields automatically

Zoo is Joomla's one of the best CCK extension. It's flexible and powerful content application builder to manage your content. Zoo allows to import data in JASON or CSV format. Data import done in following 3 stages.
1) Upload CSV file.

2) Select delimiters.Type in the field separator and the field enclosure of the CSV file.

3) Assign the submission fields to the appropriate CSV files columns. Here you have to assign the data in your CSV file to an item type of the app.
1st & 2nd stage of data importing is very easy & straight forward where as 3rd stage will be depends on how many submission fields you have map to the appropriate CSV files columns. Its fine, if you have to map 4-5 fields but what if you wanna map 20-30 fields & you want to upload large data. This stage kills you. Here we have solution for you. You just have to override administrator/components/com_zoo/views/configuration/tmpl/importcsv.php file. Add a Auto Map button & some script on click of Auto Map button in the file. That's it. Lets add the button first. Put this code anywhere you want to see the Auto Map button on page.

Add the following Jquery script.
 
  $("#automap").click(function(){
  
    
    $("li.assign").each(function(){
      
      var catname = $(this).find("span.name").text();
           
      
      
      if($(this).find('select.assign option').filter(function () { return $(this).html().toLowerCase() == catname.toLowerCase(); }).val()){
       $(this).find('select.assign option').filter(function () { return $(this).html().toLowerCase() == catname.toLowerCase(); }).attr("selected","selected");
       //$(this).find('select.assign').css("border", "1px solid green");
      }else{
       $(this).find('select.assign option').each(function(){
         var crval = $(this).text().toLowerCase();
         catname = catname.toLowerCase();
         //console.log(crval.split(catname).length);
         
         if(crval.split(catname).length > 1 ){
           $(this).attr("selected","selected");
           $(this).closest("select.assign").css("border", "1px solid red");
           
         }else if(catname.split(crval).length > 1){
           $(this).attr("selected","selected");
           $(this).closest("select.assign").css("border", "1px solid red");
         }
       })
       
      }
      
    });
   
   
  });
  

Friday, August 30, 2013

Live site - Forget the fear & work with full freedom


We work on live site which must be using by many users of the site over the world wide. Many times problem occurs only on a live site so in such cases you can't do anything on your working instance & you want to debug only on live site to fix the issue. There are many CMS like Joomla, Drupal which easily allows debug or error reporting mode. However this is not just enough in many situation. There is possibility of site getting crashed if you have done any hacks or some patch work & this fails when you only want to see the errors or print any query & die statement.
Yesterday i was suffering from same problem. There was a Joomla site which was live & there were many users online & have to look the code by trial & error basis like print some queries & execute die statement. Simple & sweet idea came in my mind & i just added a parameter like testuser=atpatil in url & based on this parameter debug the code by executing die statement. This won't affect to anyone besides me. In php you can add following code.
if($_GET['testuser'] == "atpatil")
{
echo 'Write or echo anything you want to solve your issue here';
die;
}
When i show the exact problem on live site to my boss. He said, "How can you print query & such coding stuff on live site." When I told about this simple trick he just laughed. Just try this simple trick to debug the code & let me know whether it helps. You can use console.log as well but this blog post is all about die statement.

Sunday, August 4, 2013

How to copy & delete Zoo Items programmatically?

Usually we have to allow Joomla front-end users to delete or copy Zoo Items. However Zoo lacks this functionality.

How to delete zoo records programmatically.

Y'day wanted to build this functionality in one of the Zoo based project. I could delete Zoo Items in few minutes by executing some delete queries on zoo related tables but decided to dig Zoo API. Why to take initiatives if Zoo API handles very effectively. Instead of writing 20-30 lines code, you can finish it in 3-4 lines using Zoo API & its very easy.
$Zoo_Item_Id = 29029; // Zoo Item id which you want to remove.
$app = App::getInstance('zoo'); // Define Zoo app instance.
$item = $app->table->item->get($Zoo_Item_Id); // Get the info of $Zoo_Item_Id
$app->table->item->delete($item); // Removes the $Zoo_Item_Id record from all respective zoo tables.

How to copy Zoo Items Programmatically.

Now lets see how to copy zoo items programmatically. Copying zoo item is not as easy as deleting records. You should have all the details including zoo category of the zoo item which you wanna copy. First you should have all data of a zoo record. We have get item API which gives zoo item's data & getRelatedCategoryIds which tells the relation of a zoo item to the categories.
Lets get the zoo records data first.

$user  = JFactory::getUser(); // Get the current user info.
$app  = App::getInstance('zoo'); // Define Zoo Instance. 
$now   = $app->date->create()->toMySQL(); // Get Current date
$item  = $app->table->item->get($zoo_id); // Get Zoo Item info
$categories = $item->getRelatedCategoryIds(); // Get the Zoo category info
Now We have all the information of Zoo Item that we wanna copy.

$item->id = 0; // set id to 0, to force new item
$item->state = 0; // Set the state of Zoo Item. 1 - publish 0 - Unpublish 
$item->alias = $app->alias->item->getUniqueAlias($zoo_id, 'copy-'.$item->alias); 
// Alias should be unique for each Zoo Item.
$item->name  .= ' ('.JText::_('Copy').')'; // set copied name
$item->created   = $item->modified = $now; // Created & Modified date
$item->created_by  = $item->modified_by = $user->id;
$item->hits   = 0;
$item->setTags($app->table->tag->getItemTags($zoo_id)); // copy tags

$app->table->item->save($item); // Save $item in zoo_item table

$app->category->saveCategoryItemRelations($item->id, $categories);
// Save the category relation in zoo_category table.


Friday, April 12, 2013

Access Zoo element data anywhere in Joomla easily

Accessing zoo element data is quite difficult as Zoo stores data in JSON format. Normally you have to execute query on zoo_item table & get element column having JSON data, then decode this data & get record details based on Element Id. This is quite boring work. Lets access Zoo element data easily by calling Zoo API. You can use this code anywhere in Joomla.
You can get an element from an item & if you don't have the item, but the item id. Lets get item first using item id as follows.
$app = App::getInstance('zoo');  // Define Zoo app instance
$item = $app->table->item->get($ITEM_ID); // Zoo Record Id 
We have item now, lets get element. 
$Element_Id = "2c0332af-7c7b-4c85-82f7-4d4b7ff5b030"; // One of the text field element id
$element_value = $item->getElement($Element_Id)->getElementData()->get('value');

// $element_value contains the actual value of element id $Element_Id of item id $ITEM_ID.

I always wonder how flexible this way is as you should know the id of the element & how does zoo stores JSON data for that element.I have to write following line, to get the image path of the record.
$Img_Path = $item->getElement('1e50c141-9d05-4c8d-9c7e-2ce7d07e799f')->getElementData()->get('file');
However this method is completely useless for multiple values of each field. It gives you only first value of the element. You can refer zoo documentation of accessing zoo element here.


Monday, December 3, 2012

Importing all fields using Zoo CSV Importer


I don't know why Zoo skips radio, dropdown fields when it comes to CSV importer/Exporter.
We have used Zoo in our one of the project where we wanted to import records having almost everything from text to radio n dropdown even Related Items Pro fields as well. Lets check how to allow zoo to import Radio, Dropdown first. You should read this blog only if you want to hack some zoo files. You can't override these files.
You have to hack just two files which are as follows

Step 1 : Show all fields in dropdown of fields.
Go to Your Site/administrator/components/com_zoo/views/configuration/tmpl/importcsv.php
Add following the code jQuery snippet.


$('.type').change(function()
{
   
   var type = $(this).val();
   
   jQuery.ajax
   ({ 
   
    type : 'POST',
                url: 'index.php?option=com_import&task=get_cdts_fields&type='+type, 
                dataType : 'json',
                cache : 'false',
                success: function(data)
                {
   if(data)
   {
           $(".assign").append('<optgroup label="'+type+'" id="extra_fields">');
           for (i=0;i<data.length;i++)
           {
             var newarray = data[i].split(",");
             $(".assign").append(new Option(newarray[0], newarray[1])); 
           }
          }
          }
               
    });
   
   
});

Now paste the following function into your custom components controller as it is.
function get_cdts_fields()
{
  
 $config_type = JRequest::getVar('type');
 $file = file_get_contents(JPATH_SITE.DS.'media/zoo/applications/blog/types/'.$config_type.'.config');
 $decode = json_decode($file,true);
   
 $Pro_Fields = array();
 $i=0;
 foreach($decode['elements'] as $k=>$ele)
 {
  if($ele['type'] == "select" || $ele['type'] == "imagepro" || $ele['type'] == "relateditemspro" || $ele['type'] =="radio")
  {
   $Pro_Fields[$i] = $ele['name'].','.$k;
   $i++;
  }
 }
  
 echo json_encode($Pro_Fields); 
 jexit();

}

You can see all fields under selected type option group only if you done step first correctly.
Atlast you can see all fields as option in dropdown. So that you can map fields easily.
Step - II Tell zoo to bind all fields like radio, select etc
Open Your Site/administrator/components/com_zoo/helpers/import.php file & add following cases besides other cases in importCSV function. Make sure you have copy of original file.

case 'select':
case 'radio':
   $ele = array('option'=>array('0' => $data[$column]));
   $elements[$assignment]->bindData($ele);
 
break;


//For Image Pro you can add following case if your using imagepro field

case 'imagepro':
                 
$element_data = array();
$images = explode('|',$data[$column]); // We have used Pipe(|) to separate images from one another.
$i = 0;
foreach($images as $img)
{
 $img_ele[] = array('file'=>$img, 
      'title' => '', 
      'file2' => '',
      'spotlight_effect' => '', 
      'caption' => ''
      );
 $i++;
}
$elements[$assignment]->bindData($img_ele);
break; 



We have imported Related Pro fields as well but its completely hard-coded & client requirement dependent.