A little more than a month ago I did a post involving the extraction the values of from a URL.
https://stackoverflow.com/questions/21231390/extracting-the-values-from-a-xml-url
It was a good answer and helped me a lot, but is there a way to generalize the code for any parameter given? The testing parameters won't be part of a formula, and this plugin I'm developing is supposed to be handled by Moodle teachers. They won't have access to my code to manually alter the parameters themselves. Here is the link.
By changing the rs parameter, I change the course. p(even/odd) and tp(semestral/anual/trimestral courses) parameters are about semesters and year is the year.
This is what I currently have.
function buildURL($year, $period, $typeperiod,$course)
{
return 'https://clip.unl.pt/sprs?lg=pt&year='.$year.'&uo=97747&srv=rsu&p='.$period.'&tp='.$typeperiod.'&md=3&rs='.$course.'&it=1030123459';
}
function doRequest_with_FileGetContents($url)
{
return download_file_content($url);
}
function processXML($xmlContent)
{
$xmlObj= new SimpleXMLElement($xmlContent);
$result=array();
foreach($xmlObj->unidade_curricular->inscritos->aluno as $aluno)
{
$result[]= $aluno->identificador;
}
return $result;
}
Testing parameters:
$year='2014';
$period='1';
$typeperiod='s';
$course='8145';
$url=buildURL($year,$period,$typeperiod,$course);
$content_b = doRequest_with_FileGetContents($url);
$dataClip = processXML($content_b);
I've tried to associate the id number of the course (course / course edit Settings/course id number) to the parameter rs, by typing:
$course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
$idnumber = $course->idnumber;
and replace it in $url=buildURL($year,$period,$typeperiod,$idnumber); but the XML doesn't even process. Is this even possible to pull it off without a formal interface?
Related
I have bought one android application with web service made in codeigniter. There API in this web service is like below.
<?php
if (!defined("BASEPATH"))
exit("No direct script access allowed");
class Site extends back {
public function __construct() {
parent::__construct();
$this->lang->load("site", "english");
$this->load->model("site_model", "site");
}
//=====================================================================
public function get_updates($last_author, $last_quote) {
$this->db->where("_auid > ", $last_author);
$this->db->where("au_status", 1);
$result["authors"] = $this->db->get("authors")->result_array();
$this->db->select("quotes.*, authors._auid, authors.au_status");
$this->db->from("quotes");
$this->db->join("authors", "authors._auid = quotes.qu_author AND authors.au_status = 1");
$this->db->where("_quid > ", $last_quote);
$this->db->where("qu_status", 1);
$result["quotes"] = $this->db->get()->result_array();
echo json_encode($result);
}
}
I am learning php yet. I have made another fresh corephp web service for use. I am not understanding above api and so not able to make similar api for my new web service. Both web service use same database...anyone can please suggest me how can I use above API in my new corephp web service ?
sorry for my bad knowledge.
Thanks
It is very simple
function get_updates get 2 parameter as input
1) $last_author //value of _auid(id) field belong to table author
2) $last_quote //value of _quid(id) field belong to table quotes
$this->db->where("_auid > ", $last_author);
$this->db->where("au_status", 1);
$result["authors"] = $this->db->get("authors")->result_array();
These lines fetch data from table author with matches value of $last_author parameter
And second query fetch data from table quotes and it is join with author with matches value of $last_quote parameter.
Join is use for smashing two or more tables into a single table.
$last_author and $last_quote is request parameter send from application.
Desired result will be stored in $result and return with json object as response data to application.
This class is fairly simple, it adds a twitter hashtag to a string if there is room for it. Twitter only allows 140 characters (minus 23 for a url). So the hashtags keep getting added if there is space for one.
I don't think it's 100% working as expected, but that is not relevant to my question which is located below.
class Hashtags {
private $url_character_count = 23;
private $characters_allowed = 140;
public function __construct(Article $article)
{
$this->article = $article;
$this->characters_remaining = $this->characters_allowed - $this->url_character_count;
}
public function createHashtagString()
{
$hashtags = '';
$hashtags .= $this->addEachNodeHashtag();
$hashtags .= $this->addHashtagIfSpace($this->article->topic_hashtag);
$hashtags .= $this->addHashtagIfSpace($this->article->pubissue_hashtag);
$hashtags .= $this->addHashtagIfSpace($this->article->subject_area_hashtag);
$hashtags .= $this->addHashtagIfSpace('#aviation');
return $hashtags;
}
private function addEachNodeHashtag()
{
//Returns a hashtag or calls hashtagString() if it is a comma separated list
}
private function hashtagString()
{
//Explodes a comma seperated string of hashtags and calls addHashtagIfSpace()
}
private function addHashtagIfSpace($hashtag_string)
{
if((strlen($hashtag_string) + 1) <= $this->characters_remaining)
{
$this->characters_remaining = $this->characters_remaining - strlen($hashtag_string);
if(empty($hashtag_string))
{
return '';
}
return ' ' . $hashtag_string;
}
}
}
Here is my test, my problem is that this only tests one specific case, where all the fields are filled in, and when there is enough space to fit them all. Should I just keep making a bunch of these test functions for different cases? I am guessing there will be about 10 of them. I have never done testing before, so I am a bit out of my element and need to to pointed in the correct direction.
Thank you
class HashtagsSpec extends ObjectBehavior
{
function it_creates_hashtag_string_with_all_fields_filled_in(Article $article)
{
$this->beConstructedWith($article);
$article->title = 'This is the article title';
$article->url = 'http://website.com/node/XXX';
$article->pubissue_hashtag = '#AHASHTAG';
$article->subject_area_hashtag = '#SUBAREA';
$article->topic_hashtag = '#TOPIC';
$article->node_hashtags = '#Test1,#Test2,#Test3';
$this->createHashtagString()->shouldReturn(' #Test1 #Test2 #Test3 #TOPIC #AHASHTAG #SUBAREA #aviation');
}
}
Step 0
Remove your class and start over by writing specs first.
When doing this you'll often find yourself writing a different (simpler) implementation, when driving it with specs. It won't take much time, but your class will benefit of a better design and testability.
I often use this practice when I don't know what code should look like. I prototype it first. Once the design starts to clarify, I remove the code and start over by speccing it.
You don't have to remove it for real, make a backup ;)
Step 1
Define your initial test list. This will be a list of behaviours you think you need to cover. It doesn't have to be complete and it will evolve as you go along.
You could start with:
it adds a topic hashtag if there is room for it in the message
it adds a pubissue hashtag if there is room for it in the message after adding a topic hashtag
it adds a subject area hashtag if there is room for it in the message after adding topic and pubissue hashtags
it does not add a topic hashtag if there is no room for it in the message
it does not add a pubissue hashtag if there is no room for it in the message after adding a topic hashtag
it does not add a subject area hashtag if there is no room for it in the message after adding topic and pubissue hashtags
Step 2
Write a first spec. Think of better naming as Hashtags might not be specific enough. Also consider a better API for your class. I chose to accept Article in a method call rather than passing it via the constructor:
class HashtagsSpec
{
function it_adds_a_topic_hashtag_if_there_is_room_for_it_in_the_message(Article $article)
{
$article->pubissue_hashtag = '#AHASHTAG';
$article->subject_area_hashtag = '#SUBAREA';
$article->topic_hashtag = '#TOPIC';
$article->node_hashtags = '#Test1,#Test2,#Test3';
$this->createHashtagString($article)->shouldMatch('/#TOPIC/');
}
}
Step 3
Run phpspec and write the simplest code to make specs pass.
class Hashtags
{
public function createHashtagString(Article $article)
{
return $article->topic_hashtag;
}
}
Step 4
Refactor - improve the design of code you wrote in Step 3.
It might be that there's nothing to improve, especially in the first iteration(s).
As you go along, your code will become more generic, while your specs become more specific.
Step 5
Repeat steps 2 to 5 until you're done. Simply pickup next behaviour you want to cover. It doesn't have to be the next one on your list. Whatever you feel is best to implement next.
During the whole process you'll often discover new behaviours or edge cases you haven't thought about before. Simply add them to your test list so it doesn't distract your flow.
I have been spending quiet some time figuring out how this works - so thought lets ask the question here.
I do understand how to customize URL's in Joomla with the help of router.php - at least I thought so. It is simple to create something like this
domain.com/country/id
example:
domain.com/germany/12
However, you wouldn't know that the id stands for a city. So in this example lets assume the city with id 12 is Berlin.
So for my custom component (named: countries) I would like that the following is displayed:
for view=countries (1st level)
domain.com/country
i.e.:
domain.com/germany
for view=city (2nd level)
domain.com/country/city-id
i.e.:
domain.com/country/berlin-12
(or perhaps just: domain.com/country/berlin - but I think the ID is required for the custom component to work - and any related modules on the page that read the ID to know what to do)
What do I have so far:
function CountriesBuildRoute(&$query)
{
$segments = array();
//if(isset($query['view'])) {
// $segments[] = $query['view'];
// unset( $query['view'] );
//}
if (isset($query['task'])) {
$segments[] = implode('/',explode('.',$query['task']));
unset($query['task']);
}
if (isset($query['id'])) {
$segments[] = $query['id'];
unset($query['id']);
}
if (isset($query['name'])) {
$segments[] = $query['name'];
unset($query['name']);
}
unset( $query['view'] );
return $segments;
}
function CountriesParseRoute( $segments )
{
$vars = array();
$app =& JFactory::getApplication();
$menu =& $app->getMenu();
$item =& $menu->getActive();
// Count segments
$count = count( $segments );
//Handle View and Identifier
switch( $item->query['view'] )
{
case 'countries':
if($count == 1) {
$vars['view'] = 'city';
}
break;
case 'city':
$id = explode( ':', $segments[$count-2] );
$name = explode( ':', $segments[$count-1] );
$vars['id'] = $id[0].'-'.$name;
break;
}
return $vars;
}
The way I am calling city pages from view countries is the following:
<a href="<?php echo JRoute::_('index.php?option=com_countries&view=city&id=' . (int)$item->id) .'&name='. $item->city_name; ?>">
Would be amazing if someone can help ! Cheers
If you want to get ride of IDs from urls you will have to add every country menu item or create rooter that will search for item id within database (bad idea with big websites). This will also require setting your homepage to one of your component views. Its easiest way.
When you build router you need two functions. First that will return SEF url CountriesBuildRoute and second that will translate SEF url back to query CountriesParseRoute. It is harder then you actually think to write SEF at this level. I will not write you whole router but only point you to right direction.
In Joomla 1.5 it was easier to make smth you want. If you have time look in rooter from some Joomla 1.5 component like (com_weblinks). CountriesBuildRoute returns array that will build your URL. For example when you return $query array looking like this: array('country','berlin') url will look like you want: domain.com/country/berlin. But reversing that process (something you will do in CountriesParseRoute) gonna be harder. You will have to check if first segment is a country (if it is second should be city).
So in function CountriesBuildRoute check what view is passed and build $segments array directly like you want for your url or selected view to be. Remember that single element from that array will be single segment from URL.
In function CountriesParseRoute check if first array element is a country (db checking, cached countries list, there are many ways to do it) then you will have to do the same with second element from array(if it exists).
I always created BuildRoute first as I wanted. Then spend hours on making parse route as precise and effective as only could be. You can spend hours or even few days if you want to make good router.
i have url like this :
http://quickstart.local/public/category1/product2
and in url (category1/product2) numbers are id , categorys and products fetched from database attention to the id
id is unique
i need to the sensitive url like zend framework url. for example :http://stackoverflow.com/questions/621380/seo-url-structure
how i can convert that url to the new url like this
is there any way?!!
You'll need to store a unique value in your database with a field name such as 'url' or something similar. Every time you generate a new product you will have to create this unique url and store it with the product information. A common way to do this is to take the name of the product and make it url friendly:
public function generateUrl($name)
{
$alias = str_replace(' ', '-', strtolower(trim($name)));
return preg_replace('/[^A-Za-z0-9-]/', '', $alias);
}
Calling this method:
$url = $this->generateUrl("My amazing product!");
echo $url;
will output:
my-amazing-product
You'll need to check that the output from this function does not already exist in the database as you will use this value to query on instead of the id.
If you apply this logic to the categories as well, you can have easily readable and descriptive urls like the one below. You may need to tweak your routing before this works correctly though.
http://quickstart.local/public/awesome-stuff/my-amazing-product
You could use ZF's Zend_Controller_Router_Route. For example, to make similar url to those used by SO, one could define a custom route in an application.ini as follows (assuming you have controller and action called questions and show respectively):
resources.router.routes.questions.route = '/questions/:id/:title'
resources.router.routes.questions.type = "Zend_Controller_Router_Route"
resources.router.routes.questions.defaults.module = default
resources.router.routes.questions.defaults.controller = questions
resources.router.routes.questions.defaults.action = show
resources.router.routes.questions.defaults.id =
resources.router.routes.questions.defaults.title =
resources.router.routes.questions.reqs.id = "\d+"
Having such a route, in your views you could generate an url as follows:
<?php echo $this->url(array('id'=>621380,'title' => 'seo url structure'),'questions');
// results in: /myapp/public/questions/621380/seo+url+structure
//OR if you really want to have dashes in your title:
<?php echo $this->url(array('id'=>621380,'title' => preg_replace('/\s+/','-','seo url structure'),'questions');
// results in: /myapp/public/questions/621380/seo-url-structure
Note that /myapp/public/ is in the url generated because I don't have virtual hosts setup on my localhost nor any modifications of .htaccess made. Also note that you don't need to have unique :title, because your real id is in :id variable.
As a side note, if you wanted to make it slightly more user friendly, it would be better to have your url as /question/621380/see-url-structure rather than /questions/621380/see-url-structure. This is because under this url you would have only one question, not many questions. This could be simply done by changing the route to the following resources.router.routes.questions.route = '/question/:id/:title'.
EDIT:
And what to do with categories and products that you have in your question? So, I would define a custom route, but this time using Zend_Controller_Router_Route_Regex:
resources.router.routes.questions.route = '/questions/(\d+)-(d+)/(\w*)'
resources.router.routes.questions.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.questions.defaults.module = default
resources.router.routes.questions.defaults.controller = questions
resources.router.routes.questions.defaults.action = show
resources.router.routes.questions.map.1 = category
resources.router.routes.questions.map.2 = product
resources.router.routes.questions.map.3 = title
resources.router.routes.questions.reverse = "questions/%d-%d/%s"
The url for this route would be then generated:
<?php echo $this->url(array('category' => 6213,'product' => 80,'title' => preg_replace('/\s+/', '-', 'seo url structure')),'questions' ); ?>
// results in: /myapp/public/questions/6213-80/seo-url-structure
Hope this will help or at least point you in the right direction.
I'm trying to display the subscriber count from a MailChimp mailing list using their API, and I've got it partially working, except the code below is currently spitting out the subscriber count for all lists, rather than for one specific list. I've specified the list id in the line $listId ='XXX'; but that doesn't seem to be working. Because I have five lists in total, the output from the PHP below shows this:
10 0 0 1 9
What do I need to do in my code below to get the subscriber count from a specific list id?
<?php
/**
This Example shows how to pull the Members of a List using the MCAPI.php
class and do some basic error checking.
**/
require_once 'inc/MCAPI.class.php';
$apikey = 'XXX';
$listId = 'XXX';
$api = new MCAPI($apikey);
$retval = $api->lists();
if ($api->errorCode){
echo "Unable to load lists()!";
echo "\n\tCode=".$api->errorCode;
echo "\n\tMsg=".$api->errorMessage."\n";
} else {
foreach ($retval['data'] as $list){
echo "\t ".$list['stats']['member_count'];
}
}
?>
I just came across this function (see below) that let's me return a single list using a known list_id. The problem is, I'm not sure how to add the list_id in the function.
I'm assuming I need to define it in this line? $params["filters"] = $filters;
The MailChimp lists() method documentation can be referred to here: http://apidocs.mailchimp.com/rtfm/lists.func.php
function lists($filters=array (
), $start=0, $limit=25) {
$params = array();
$params["filters"] = $filters;
$params["start"] = $start;
$params["limit"] = $limit;
return $this->callServer("lists", $params);
}
I'd strongly recommend not mucking with the internals of the wrapper as it's not going to be nearly as helpful as the online documentation and the examples included with the wrapper. Using the wrapper means the line you tracked down will effectively be filled when make the proper call.
Anywho, this is what you want:
$filters = array('list_id'=>'XXXX');
$lists = $api->lists($filters);
Mailchimp provides a pre-built php wrapper around their api at http://apidocs.mailchimp.com/downloads/#php. This api includes a function lists() which, according to its documentation, returns among other things:
int member_count The number of active members in the given list.
It looks like this is the function which you are referring to above. All you should have to do is iterate through the lists that are returned to find the one with the proper id. From there you should be able to query the subscriber count along with a number of other statistics about the list.