codeigniter attribute/filter system - php

I've searched a lot for answers to this question, but I can't find them. Maybe because I'm not searching for the right keywords (because I don't know the right name) or there might be few resources on this subject.
I'd like to build a 'sorting system' in codeigniter for database results. Much like the magento layered navigation or the sorting that's on this site: http://www.wintersporters.nl/skigebieden. On there you can filter ski resorts by price, country, amount of slopes etcetera and the results are automatically updated via AJAX.
another example -> http://www.beslist.nl/products/cddvdrom/cddvdrom_5035278/ where you can sort by date, publisher, genre etcetera.
I'd like the system to be able to pass multiple variables like on wintersporters.nl where you can select multiple countries instead of only one and this way you're able to narrow down your search more and more by selecting multiple attributes until you've found the ski resort that fits you best. So every time you select an option it's preserved in the URL.
How do I achieve something like this? Via the $_GET[] array, with uri's or something totally different? Can anyone point me to a tutorial, snippet of code, explanation or anything related as I can't find out the right way to do this.
I'd be really grateful!

I was also thinking about the component or control which will give me the same functioalities for my web portal but then I developed by own by HTML and Ajax.
In Ajax, you can use
var checkboxValueArray = [];
var val = [];
$('input[name="subcatcheckbox"]:checked').each(function(i){
val[i] = $(this).val();
checkboxValueArray.push($('#subcat'+val[i]).text());
});
checkboxValueString = checkboxValueArray.toString();
checkboxValueString = checkboxValueString.replace(/\ /g, "-");
checkboxValueString = checkboxValueString.replace(/\_/g, "-");
checkboxValueString = checkboxValueString.replace(/\,/g, ":");
var checkboxValueNumberString = val.toString();
var checkboxValueNumberString = checkboxValueNumberString.replace(/\,/g, ":");
var pathName ='';
if(checkboxValueNumberString != ''){
pathName = "events_categories="+checkboxValueString+"&catid="+checkboxValueNumberString;
}
if(pathName != ''){
window.location.hash = "#!" + pathName;
}
if(pathName == ''){
window.location.hash = '';
}
getEventsParsedJSON(val);
By this way, I am creating an array on onClick event and then passing to the string to the URL through window.location.hash(ajax method). I developed this in a day. It's easy to develop.

Related

Netsuite SuiteTalk - requesting list of invoices for a customer via PHP

I'm using the Netsuite PHP Toolkit to try to obtain a list of invoices for a customer. I can do the call (using a TransactionSearch) with no problem, but I'm struggling to understand how I'm supposed to get all details for an invoice - i.e. the invoice "header" details (e.g. grand total, currency, main menu line etc) as well as details for each line item (net value, taxable value, item etc).
I have tried a couple of approaches:
TransactionSearchAdvanced, with return columns specified and returnSearchColumns preference set to "false". This gives back all the separate lines (woo!) but things like currency and term aren't expanded out - you just get internalId specified and not the actual text (or the symbol). Also, with TSA, do you really have to specify every column you want? i.e. is the default really just an empty set of fields? Isn't there a way of just saying "give me all the details for all lines of each invoice?
TransactionSearch, with returnSearchColumns preference set to "true". This gives a list of single Invoice type records, with all the currency and term stuff correctly populated, but frustratingly, none of the individual line items. It's more of a summary.
So I am left with a couple of options, neither of which are very palatable, namely:
Do both calls for all invoices and combine the data. These searches take a long time (performance is another bugbear for me, so I really don't want to do this.
or
Figure out a way of requesting the data for terms, currency etc and also a way of obtaining invoice lines.
I have no idea how you're supposed to do this, and can't find anything on the internet about it. This is one of the worst interfaces I've used (and I've used some pretty bad ones).
Any help would be hugely appreciated.
Just like you I started out trying to do things with the Web Services API (aka SuiteTalk). Mostly it was an exercise in frustration because eventually what I found out was that I plain couldn't do what I wanted with them. That and the performance was pretty bad, which would have killed my project even if it had worked properly.
Like Faz, I've found it much easier and faster to use a combination of RESTlets and Saved Searches than deal with the web services framework.
Basically break your problem down into these parts:
Saved Search that returns the results that you want (keep track of the internal ID you'll need it later)
RESTlet it's just a Javascript file that defines the function you will use to return the results from the search
Client code to call the RESTlet and get the results.
Part I:
So the saved search is pretty straightforward. I'm going to assume you can make that happen and also that you can actually get all the fields you want in one place. That hasn't always been the case in my experience.
Part II:
The RESTlet involves a lot more steps even though it's really a very simple thing. What makes it complicated is getting it uploaded and deployed on your NetSuite site. If you don't already have the NetSuite IDE installed I highly recommend it if only to make deploying the scripts a little easier. The autocompletion and tooltips are extremely useful as well.
For instance here is code I use to get results from a search I cared about. This was adapted from some kind soul's posting somewhere on the internet but I forget where:
function getSearchResults(){
var max_rows = 1000;
var search_id = 1211;
var search = nlapiLoadSearch(null, search_id);
var results = search.runSearch();
var rows = [];
// add starting point for usage
var context = nlapiGetContext();
startingUsage = context.getRemainingUsage();
rows.push(["beginning usage", startingUsage]);
// now create the collection of result rows in 1000 row chunks
var index = 0;
do{
var chunk = results.getResults(index, index+1000);
if( ! chunk ) break;
chunk.forEach( function(row){
rows.push(row);
index++;
});
}while( chunk.length === max_rows);
// add a line that returns the remaining usage for this RESTlet
context = nlapiGetContext();
var remainingUsage = context.getRemainingUsage();
rows.push(["remaining usage",remainingUsage]);
// send back the rows
return rows;
}
This is where you get things primed by passing in your Saved Search Internal ID:
var search = nlapiLoadSearch(null, SEARCH_ID);
var resultSet = search.runSearch();
Then the code repeatedly calls getResults() to get chunks of 1000 results, this is a NetSuite limitation. Once you have this written you have to upload the script to NetSuite and configure and deploy it. The most important part is telling it what function to assign to each verb. In this case I assigned GET to execute the getSearchResults. There is a lot of work to do here, and I'm not going to type all of it out because it is worth your time to learn this part. At least enough to get the IDE to do it for you =D. You can read all about it in the "Introduction to RESTlets" guide.
Part III.
Client code can be in whatever you want that does REST the way you like to. Personally I like Python for this because the requests library is fantastic.
Here's some example Python code:
import requests
import json
url = 'https://rest.sandbox.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=1'
headers = {'Content-Type': 'application/json', 'Authorization':'NLAuth nlauth_account=1234567, nlauth_email=someone#somewhere.com, nlauth_signature=somepassword, nlauth_role=3'}
resp = requests.get(url, headers=headers)
data = resp.json()
The URL is going to be displayed to you as part of the deployment of the RESTlet. Then it's up to you to do what you want with the data that comes back.
So the things I would suggest you spend time with would be
Setting up the NetSuite IDE
Getting and reading the SuiteScript developer reference docs
Finding a good way to create REST client code in you language of choice.
I hope that helps.
I created a saved search in Netsuite and call that search using restlet. With this it is pretty lightweight and you can call the data as it is in the saved search.
Performance wise Restlet is much better than webservices.
Create a new suitelet script and deploy
Below script will give you invoice list by customer internal id
function customSearch(request, response) {
var rows = [];
var result;
var filters = [];
//9989 is customer internal id you can add more
// by pushing additional ids to array
filters.push(new nlobjSearchFilter('entity', null, 'anyOf', [9989] ));
var invoiceList = nlapiSearchRecord('invoice', null, filters, []);
// by default record limit is 1000
// taking 100 records
for (var i = 0; i < Math.min(100, invoiceList.length); i++)
{
if (parseInt(invoiceList[i].getId()) > 0) {
recordid = invoiceList[i].getId();
try {
result= nlapiLoadRecord(invoiceList[i].getRecordType(), recordid);
// pushing in to result
rows.push(result);
} catch (e) {
if (e instanceof nlobjError) {
nlapiLogExecution('DEBUG', 'system error', e.getCode() + '\n' + e.getDetails());
} else {
nlapiLogExecution('DEBUG', 'unexpected error', e.toString());
}
}
}
}
response.setContentType('JSON');
response.write(JSON.stringify({'records' : rows}));
return;
}
}
}
response.setContentType('JSON');
response.write(JSON.stringify({'records' : rows}));
return;
}
Here is what I have for getting a customer's invoices:
public function getCustomerInvoices($customer_id)
{
$service = new NetSuiteService($this->config);
$customerSearchBasic = new CustomerSearchBasic();
$searchValue = new RecordRef();
$searchValue->type = 'customer';
$searchValue->internalId = $customer_id;
$searchMultiSelectField = new SearchMultiSelectField();
setFields($searchMultiSelectField, array('operator' => 'anyOf', 'searchValue' => $searchValue));
$customerSearchBasic->internalId = $searchMultiSelectField;
$transactionSearchBasic = new TransactionSearchBasic();
$searchMultiSelectEnumField = new SearchEnumMultiSelectField();
setFields($searchMultiSelectEnumField, array('operator' => 'anyOf', 'searchValue' => "_invoice"));
$transactionSearchBasic->type = $searchMultiSelectEnumField;
$transactionSearch = new TransactionSearch();
$transactionSearch->basic = $transactionSearchBasic;
$transactionSearch->customerJoin = $customerSearchBasic;
$request = new SearchRequest();
$request->searchRecord = $transactionSearch;
$searchResponse = $service->search($request);
return $searchResponse->searchResult->recordList;
}

How to make search autocomplete faster?

I have implemented a basic auto-complete feature using jQuery autocomplete. I am querying DB every time which is making auto-complete thing quite slow. I am looking for ways to make it faster much like Quora.
Here is the code from front-end:
<script type="text/javascript">
var URL2 = '<?php e(SITE_URL); ?>fronts/searchKeywords';
jQuery(document).ready(function(){
var CityKeyword = jQuery('#CityKeyword');
CityKeyword.autocomplete({
minLength : 1,
source : URL2
});
});
</script>
Here is the code from server side:
function searchKeywords(){
if ($this->RequestHandler->isAjax() ) {
$this->loadModel('Expertise_area');
Configure::write ( 'debug',0);
$this->autoRender=false;
$expertise=$this->Expertise_area->find('all',array(
'conditions'=>array('Expertise_area.autocomplete_text LIKE'=>'%'.$_GET['term'].'%'),
'fields' => array('DISTINCT (Expertise_area.autocomplete_text) AS autocomplete_text'),
'limit'=>5
));
$i=0;
if(!empty($expertise)){
$len = strlen($_GET['term']);
foreach($expertise as $valueproductname){
$pos = stripos($valueproductname['Expertise_area']['autocomplete_text'],$_GET['term']);
$keyvalue = "";
if($pos == 0) {
$keyvalue= "<strong>".substr($valueproductname['Expertise_area']['autocomplete_text'],$pos,$len)."</strong>"
.substr($valueproductname['Expertise_area']['autocomplete_text'],$len);
}else {
$keyvalue= substr($valueproductname['Expertise_area']['autocomplete_text'],0,$pos)."<strong>"
.substr($valueproductname['Expertise_area']['autocomplete_text'],$pos,$len)."</strong>"
.substr($valueproductname['Expertise_area']['autocomplete_text'],$pos+$len);
}
$response[$i]['value']=$valueproductname['Expertise_area']['autocomplete_text'];
$response[$i]['label']="<span class=\"username\">".$keyvalue."</span>";
$i++;
}
echo json_encode($response);
}else{
}
}
}
I have researched a bit and so far following solutions are worth looking at:
Query data on page load and store it in COOKIE to be used in future.
Implement some caching mechanism (memcache??). But my website is on Cakephp which does it internal cahcing if I am right. So will it be worth to go in this direction.
Use some third party indexing mechanism like Solr, Lucene etc. Don't know much about this.
Implement a much complex "Prefix Search" myself
What is the right way to go about it? Please help me out here.
I've never tried this but will be doing it soon for a project I'm working on.
I always considered the possibility of during the initial page load recieveing some AJAX (or perhaps just including it in the page) the top 10 words for each alphabet letter.. e.g.
A - apples, anoraks, alaska, angela, aha, air, arrgh, any, alpha, america
B - butter, bob etc.....
This way when user presses A-Z you can instantly provide them with 10 of the most popular keywords without any further requests, as you already have them stored in an array in the JS.
I'm not sure of size/memory usage but this could be extended further to handle the first 2 letters, e.g. AA, AB, AC.....BA, BB, BC.... ZA, ZB, ZZ... of course many combinations such as words starting with ZZ won't have any data unless it's a music site and it's ZZ Top! This means it probably won't take up so much memory or bandwidth to send this data during initial page load. Only when the user types the 3rd letter do you need to do any further data lookups/transfers.
You auto-update this data every day, week or whatever depending on site usage and the most popular searches.
I am adding a solution to my question which I figured out after a lot of research.
Problem was:
I was using Ajax to fetch keywords from database every time a user changes text in search box
I was doing a wild card search to match search item within entire strings and not just starting of keywords for ex. "dev" would return "social development", "development" etc
Solution:
I have a fixed array of keywords (200) which is not going to increase exponentially in near future. So, instead of doing complex indexing I am currently sending all keywords in an array.
I am sending this data in an array on page load since it is small. If it becomes large, I will fetch it in background via some ajax in different indexed arrays.
I am using jQuery's Autocomplete widget to do rest of thing for me.
For highlighting search item, I am using a hack by working around __renderItem. (Copied from Stackoverflow. Thanks to that!!)
Code:
function monkeyPatchAutocomplete() { //Hack to color search item
jQuery.ui.autocomplete.prototype._renderItem = function( ul, item) {
var re = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + this.term + ")(?![^<>]*>)(?![^&;]+;)", "gi");
var t = item.label.replace(re,"<span style='font-weight:bold;color:#434343;'>" +
"$&" +
"</span>");
return jQuery( "<li></li>" )
.data( "item.autocomplete", item )
.append( "<a>" + t + "</a>" )
.appendTo( ul );
};
}
function getKeywords(){
//Function that returns list of keywords. I am using an array since my data is small.
//This function can be modified to fetch data in whatever way one want.
//I intend to use indexed arrays in future if my data becomes large.
var allKeywords = <?php echo json_encode($allKeywords); ?>;
return allKeywords;
}
jQuery(document).ready(function(){
monkeyPatchAutocomplete();
var CityKeyword = jQuery('#CityKeyword');
CityKeyword.autocomplete({
minLength : 1,
source : getKeywords()
});
});

Differentiate pages with same url

I have a script that runs on two different pages, one for orders and one for quotes. These pages have an identical url followed by a dynamic string. What can I do to have this script do one thing on one page and one thing on another?
Edit: I wasn't very clear on this looking back, the current selected answer does work well for what I asked, however it shouldn't be used with Magento. Magento has built in methods for determining this information, and you would want to override it rather than inject script into the adminhtml code.
Look at the parameters from the URL via $_REQUEST in PHP. See here: http://php.net/manual/en/reserved.variables.request.php
EDIT:
I see from your comments that your URL is like http://www.example.com/index.php/admin/sales_order/view/order_id/273151/.
If it's always this way without any query parameters, then you may want to parse the $_SERVER['PATH_INFO'] variable in PHP.
(see here: http://php.net/manual/en/reserved.variables.server.php).
You can get an array of these path parts by doing:
$myPathArray = explode($_SERVER['PATH_INFO'],'/');
Then you can get that last, differentiating, part of the path like this:
if (count($myPathArray)) {
$orderId = $myPathArray[count($myPathArray)-1];
} else {
$orderId = ''; // or whatever you please
}
You can check what's in the URL, for example with this :
function getUrlParameter = function(name, defaultValue) {
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( document.location.href );
if( results == null ) return defaultValue;
else return results[1];
};
If your URL is test.php?a=toto then you'll have toto in pageA :
var pageA = getUrlParameter("toto");
EDIT : if you just want the end of the path part, look at document.location.pathname
If your url variable names are different on each page you could use an if statement
if (isset($_GET['vara'])) {
// Do thing A
}
elseif (isset($_GET['varb'])) {
// Do thing b
}
Use $_GET to retrieve variables passed in the URL. If your new at this Tizag has some easy to read tutorials. With the values of variables being passed, you can figure out which page you are coming from.

Change all domains in links on a website

need some advice on how to fix an ugly situation. our forum has resided on a couple of different domains over the years. we lost one domain that was in use 5-6 yrs ago and apparently some posts on our forum still have links in the threads that point to the old domain. what would be the most efficient way to change all links that point to
http://www.olddomain.com/stuff
point to
http://www.newdomain.com/stuff
the only part that has changed is the domain name, all thread variables in the url remain the same. is this something that is best done client side with javascript/jquery or should it be handled on a server level with a PHP function (dont know where to begin here..)? some pseudocode that doesn't seem to do what I need it to on the client side...
$('a').each(function() {
var domanin = 'newdomain';
if(href.search('olddomain.com') != -1) {
$(this).attr('href', newdomain);
}
});
thank you
I think it will make more sense if you handle this in the back end. Search engines will not notice the change you make through JavaScript.
So I advise you search for those domains in your database and replace them there.
Well you should probably do this on the server side, as it was said before, but if you can't for whatever reason, here is what you could do on the javascript side of things.
$('a').each(function() {
this.host = 'www.newdomain.com';
});
Note that this example uses jQuery, but you could do the same in plain javascript with getElementsByTagName.
To do this in JavaScript (w/ jQuery):
$('a').each(function() {
var link = this.href;
if(link.search('olddomain.com') != -1) {
this.href = link.replace('olddomain.com', 'newdomain.com');
}
});
Here is a jsfiddle: http://jsfiddle.net/tHXxK/
However I would suggest changing the links in the database, just get rid of all the old references. To do this create a script that searches for the old URLs and replaces them, something like:
$query = mysql_query("SELECT [id], [link] FROM [table] WHERE [link] LIKE '%//olddomain.com/%' OR [link] LIKE '%//www.olddomain.com/%'", $db) or trigger_erroR(mysql_error());
while ($row = mysql_query($query)) {
$iQuery = mysql_query("UPDATE [table] SET [link]='" . mysql_real_escape_string(str_replace(array('//olddomain.com/', '//www.olddomain.com/'), array('//newdomain.com/', '//www.newdomain.com/'), $row['link']) . "' WHERE [id]=" . $row['id']), $db) or trigger_error(mysql_error());
}
If it'd be me, I would have used a server side script to replace all instances of the old domain with the new one and be done with it once and for all.
I assume your forum DB is rather a large one. For the sake of system resources you can write a multi-step script and do the job in multiple steps.
This is a better approach as it can improve the data consistency for search engines as well.

Auto suggest feature to search records

I don't know what is the exact name of this feature, but I need a feature where the user should be given a text box to search things. When they type in this text box, a matching list of values from database should be shown like a drop-down box.
The user can select one of the value and for will got submit.
I know this is already done on Internet anywhere, but what is this feature called?
Where can I find this feature to download and use for free?
Autocomplete from jQuery UI . SAYT opensource from Google.
http://jqueryui.com/demos/autocomplete/
http://code.google.com/p/search-as-you-type/
I found this code somewhere online, very very useful and very fast (tested for 30000 strings), have been using it ever since,
it uses regex
var rx = new RegExp('"([^"]*' + search + '[^"]*)"', 'gi');
var i = 0;
var num;
results = '';
while (result = rx.exec(string)) {
results += "\n" + result[1];
i += 1;
if (i >= 10) break;
}
I've put up the entire code on JSFiddle
NOTE: My code(The HTML part) is extremely messy, was trying too many things at once, just correct it to suit your requirements.
The easiest way to do this is to use the jQuery UI version here.

Categories