Understanding geolocation on tweets - php

I'm trying to get geolocation from tweets.
For my tests, I posted new tweets geo-referenced but when I got the json of them, the element 'geo' is null. Why? What's wrong with them?
I don't want to search by range and geolocation: I want to search some tweets indexed by a particular hashtag and then retrieve 'geo' json element.
I tried to search other tweets (not mine) and sometimes I got 'geo' element as a full object, with coordinates array.
So, what can I do to have 'geo' element not null?
I did 4 posts geo-referenced: my tweets
The location is: 44.694704,10.528611
Edit: Added geocode param
This is what I've done server-side (pure php):
$conn = new OAuth (CONSUMER_KEY, CONSUMER_SECRET);
$conn->setToken (ACCESS_TOKEN, ACCESS_TOKEN_SECRET);
$conn->fetch (API_URL, array ('q' => '#testhashtagandgeo', 'geocode' => '44.694704,10.528611,4km'));
echo $conn->getLastResponse ();
I used PHP OAuth base and each constant is defined correctly, so it works good.
Client-side (ExtJS):
Ext.onReady (function () {
Ext.Ajax.request ({
url: 'proxy.php' ,
disableCaching: false ,
success: function (xhr) {
var js = Ext.JSON.decode (xhr.responseText);
Ext.each (js.results, function (tweet) {
if (tweet.geo !== null) {
console.log ('lat = ' + tweet.geo.coordinates[0] + ' - lng = ' + tweet.geo.coordinates[1]);
}
});
console.log (js);
} ,
failure: function (xhr) {
console.log ('something\'s wrong!');
}
});
});
Thanks in advance.
Wilk

You need to read the documentation
Location data is only included if the query includes the geocode parameter, and the user Tweeted with Geo information.
So, you need to add something like this to your query
&geocode=37.781157,-122.398720,25mi
Or whichever location you want.

Related

How to run a helper function multiple times for checking live results from the DB

I have a forum project with Laravel 9, and I have made this helper function.
if(!function_exists('new_question')){
function new_question($c) {
$quelist = \DB::table('questions')->get();
$quecount = $quelist->count();
if($quecount > $c){
return 'A new question is added.. please refresh the page..';
}
}
}
So it gets the number of current questions like this:
{{ new_question($queCnt); }}
And then, it will check if the $quecount equals $queCnt or not. And if not, then print the statement A new question is added.. please refresh the page... Therefore the user will understand if any new question is added. But I need to run this helper function after some periods of time (for example, 10 seconds). However, I don't know how to call a function after a custom amount of time.
to run any function after a specific time, you have set the interval for example
// Call the new_question function every 10 seconds
setInterval(new_question, 10000);
// Use an AJAX request to call the new_question function on the
// server
function new_question(){
$.ajax({
url: '{{ url('/new_question') }}?c=10',
success: function(response) {
// Handle the response from the server
console.log(response);
}
});
}
</script>
// to receive get value update helper function
if(!function_exists('new_question')){
function new_question() {
// Get the value of the c parameter from the query string
$c = isset($_GET['c']) ? $_GET['c'] : 0;
// Your code here...
}
}
First, you have to figure out if the number of "content" has changed. Using Laravel, create a function that is accessible through a route, this function would return the number of posts, then, using javascript, you will call that function in an interval (example is 5 seconds) and if the number has changed since the last call, then there's new posts, so you should do some DOM manipulation to update your page to alert the user.
Your server side function would be simple, something like this:
function count_questions() {
$quelist = DB::table('questions')->get();
$quecount = $quelist->count();
$response = array('quecount' => $quecount);
echo json_encode($response);
}
Then, identify how to reach this function through your routing table, and use the below jquery functions:
var quecount = 0;
$(document).ready(function() {
setInterval(function() {
$.ajax({
// change this URL to your path to the laravel function
url: 'questions/count',
type: 'GET',
dataType: 'json',
success: function(response) {
// if queuecount is 0, then set its initial value to quecount
if(quecount == 0){
quecount = response.quecount;
}
if(response.quecount > quecount){
quecount = response.quecount;
new_question_found();
}
}
});
}, 5000);
});
function new_question_found(){
$("#new_questions").html("New questions found");
}
The solution that is coming to my mind is may be too advance or too complex.
This solution need
Laravel scheduler and queue (Jobs)
and web push notification (ex : one-signal)
To reduce the traffic in the back-end you can have job to run like every 10 seconds in the back-end (Laravel scheduler and Queue).
If the question count get increased. you can call a api in the push notification and you can say there is a new question added.
the above work-flow is not explained well but this is in very simple term.
For example:
on frontend side:
const check_new_questions = function() {
const message =
fetch('http://yourserver.com/new_questions_endpoint');
if (message) {
// show message
}
};
// call each 10 seconds.
setInterval(check_new_questions, 10000);
then on backend side:
create a route new_questions_endpoint which will call your function and return result as response.
But note, that receiving all the questions from the table each time could be expensive. Eloquent enables to make a count query without retrieving all the rows.
You can't have this behaviour happen without any form of javascript.
The main way you could do this is by setting an interval via front-end like others have said. If you have any familiarity with APIs and general HTTP protocol, I would recommend you make an API route that calls your helper function; I also recommend responding with an empty body, and using the http status code to determine whether a refresh is needed: 200 for success and no refresh, 205 for success and refresh needed.
So you simply set a fetch api call on timeout, don't even need to decode the body and just use the response status to determine whether you need to run location.reload().
To achieve your requirement as per the comment you need to create an ajax request to BE from FE to check the latest question and based on that response you need to do it.
setInterval(function()
{
$.ajax({
url: "{{url('/')}}/check/questions",
type: "POST",
dataType: "json",
data: {"action": "loadlatest", "id": id},
success: function(data){
console.log(data);
},
error: function(error){
console.log("Error:");
console.log(error);
}
});
}, 10000);//time in milliseconds
the above js code will create an ajax request to Backend, below code will get the latest question 'id'.
$latest_id = DB::table('Questions')->select('id')->order_by('created_at', 'desc')->first();
so either check it in BE and return a corresponding response to FE or return the latest id to FE and check it there.
then show the prompt to refresh or show a toast and refresh after 5 sec
Why do you use function_exists() ? I don't think it's useful in this case.
The easiest way to do what you want is to use ajax and setInterval
Front side:
const check_new_questions = function() {
const data =
fetch('http://yourserver.com/new_questions_endpoint?c=current');
if (data) {
alert(your_message);
}
};
// call each 10 seconds.
setInterval(check_new_questions, 10000);
Back side:
function new_question() {
// Get the value of the c parameter from the query string
$c = isset($_GET['c']) ? $_GET['c'] : 0;
$quelist = \DB::table('questions')->get();
$quecount = $quelist->count();
return ($quecount > $c);
}
I suggest to use c as the last id and to not count questions but just to get the last question id. If they are different, one question or more was inserted.
Attention if you use this solution ( Ajax pulling ) you'll get two requests per 10 seconds per connected users. One for the ajax call and one for for the database call. If you have 10 users a day, it's ok but not if you have 10 thousands. A better but more complex approach is to use Mercure protocol or similar ( https://mercure.rocks/ ).

Restful API Design Content Output

I finally got my API output ready with some great help of SO-members answering all my questions. Thank you by the way.
But I wonder about one thing in my output. When I call the URL to receive the API content I get something like this:
[
{
"data": [
{
"incidentReference": "R-20150405-887f93",
"latitude": 48.259698,
"longitude": 11.434679,
"archived": false
},
(...)
]
}
]
I read the book "Build APIs you won't hate" and it is a great resource for a lot of stuff. But I don't think, the output I see is right. I mean, the namespacing is something I would like to have. But shouldn't it look like this?
{
"data": [
{
"incidentReference": "R-20150405-887f93",
"latitude": 48.259698,
"longitude": 11.434679,
"archived": false
},
(...)
]
}
So shouldn't the whole thing be JSON only? in my case it is return additionally within an Array. The functions doing the job are these:
public function index()
{
$incidents = Incident::all();
if( ! $incidents) {
return Response::json([
'error' => [
'message' => 'There are no incidents in the database.',
'code' => 100
]
], 404);
} else {
return $this->respond([
$this->respondWithCollection($incidents, new IncidentTransformer)
]);
}
}
public function respond($data, $headers = []) {
return Response::json($data, $this->getStatusCode(), $headers);
}
protected function respondWithCollection($collection, $callback) {
$resource = new Collection($collection, $callback);
$rootScope = $this->fractal->createData($resource);
return $rootScope->toArray();
}
So yes, the respondWithCollection returns an array, but this is handled within the respond function which states return Response::json So I would expect a json output when calling the resource.
Is this ok?
The next structure
{"data" : [{}, {}]}
is good when you have an extra fields, such as total count of items, number of page, etc:
{"data" : [{}, {}], "page":1, "total": 100}
Otherwise, it is really good to use simple structure:
[{"incidentReference": "R-20150405-887f93", ...}, {...}]
I'd recommend you to avoid any deep-nested structures.
RESTful responses should be as simple as possible : Output pure json data only. Therefore, limit and offset should not be included in the server response since this client already knows that information. And if you format the response, you will have to interface all device / plateform / system that wants to interact with your resful service.
Server should return extra information that client doesn't know though, such as total elements when querying a part of a collection. But I would use header for that. That way, server still returns simple json array, wich can be handled not only by your client but lots of other devices / platforms / apps.
My opinion : Output only pure json and use header for extra info, like this example :
api/incidents/index.php :
// sanitize $_GET array, then output
$total = $incidents->getTotal();
$output = json_encode($incidents->fetch($GET['LIMIT'], $_GET['OFFEST'])); // pure example, I don't know how your framework works
// output
header('HTTP/1.1 200 OK');
header('Content-Type: application/json');
header('Collection-Total: '.$total);
header('Content-Length: ' . strlen($output));
echo $output;
For example, a web app using jquery accessing this ressource would look like this :
var limit = 10;
var offset = 200;
$.ajax({
type: 'GET',
url:'http://mywebsite.com/api/incidents/',
data: {
'LIMIT': limit,
'OFFSET': offset
},
success: function(data, textStatus, request){
console.log('Incidents received...');
console.log(data);
console.log('There is ' + request.xhr.getResponseHeader('Collection-Total') + ' incidents in total');
},
});
I would avoid nested structures, like Roman said. RESTful ressources need to have their own identifier (URI). It must return an object (item) or array of objects (collection of items), like this :
api/incidents // returns an array of objects
api/incident/[id] // returns a unique object (incident), using incident id in the URI
api/incidentreference/[id] // return an unique object (incident reference), usign incident reference id in URI
This approach also leads to interesting cache possibilities since all elements (item or collections) have their own identifier (URI). Web protocols / platforms / devices may cache all server results and optimize your entire app automatically if you work with URIs.
I would also recommend that your service return a 200 OK responses even if there is no elements to output. 404 says that the ressource is not found. The ressource is found, but contains no elements now. It may contains elements later. A 404 HTTP code may be handled differently by some device / broswers / platform. I am possibily wrong with that, but my REST services always return 200 OK / empty json arrays and I never has problems. Accessing a ressource (url) that doesn't exists will return 404 though.

jQuery full calendar $.ajax call issue ( using static events on page open )

So I am using Yii and full calendar as a widget which is called in a view of CalendarController. Uppon call for a widget, the widget retrives existing events from the DB and puts them inside the full calendar to display. Now I have also made a simple filter for filtering out events by category they are in ( dropdown with a submit ), so I want to send request to a calendarController method called actionEvents() which then takes what is passed to it ( the category of events for which we want to retrieve events ), gets them back to the jQuery which then calls the calendar again passing it a json_encode(d) array of needed properties to correctly render events under the selected category in the dropdown. The problem I have is that it seems fullcalendar is doing my wanted call ( POST ) as well as one another GET call along with it for some reason so it does return properly formatted json to the jQuery from the method of controller, but just shows an empty calendar without events in it on return. This is how the console looks like after the returned data.
This is the code that calls ajax call
$(document).ready(function() {
var date = new Date(),
d = date.getDate(),
m = date.getMonth(),
y = date.getFullYear();
$('form.eventFilter').submit(function() {
var selectedOption = $('form.eventFilter select').val(),
eventContainer = $('.fc-event-container');
var objectToSend = { "categories" : [selectedOption],"datefrom" : "september2013"/*month + "" + year*/ , "dateto" : "september2013"/*month + "" + year*/};
$.ajax({
url: '<?php echo Yii::app()->createUrl('calendar/events'); ?>',
type: "POST",
async:false,
data: {data : JSON.stringify(objectToSend)},
success: function(data) {
$('#fc_calendar').html('');
$('#fc_calendar').fullCalendar({
events: data
});
console.log(data);
},
error: function() {
console.log(data);
}
});
return false;
})
})
The code that renders initial calendar events on first page load ( open ) is this
<div id="fc_calendar"></div>
<script class="fc_calendar_script">
// gets calendar and its events working and shown
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#fc_calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
editable: true,
events: [
<?php foreach ($eventItems as $event): ?>
{
title: '<?php echo htmlentities($event['eventItems']['title']); ?>',
start: new Date(y,m,d + <?php echo $event['eventItems']['startdate_day_difference']; ?>),
end: new Date(y,m,d + <?php echo $event['eventItems']['enddate_day_difference']; ?>),
url: '<?php echo $event['eventItems']['url']; ?>',
className: [
<?php foreach($event['eventCategories'] as $category) { echo ''.json_encode($category['slug']).','; }?> // and categories slugs as classnames, same purpose
]
},
<?php endforeach; ?>
]
});
</script>
The code in controller is not that important since you can see what it returns in the screenshot :) If someone has an idea of how to get around this I would really be grateful :) Tried everything I know
Ok so bounty goes to whoever answers this question :)
I am having problems with full calendar month rendering when ajax data is returned and events populated. Since I have checkboxes for each category ( events have MANY_MANY relation with categories ) and each time a checkbox is checked or unchecked, JSON array of chosen categories of events is passed on to PHP method which queries DB for all events that go under chose categories and returns all events in a jquery encoded array to the view which then takes that events array and rerenders the calendar like shown in the upper code.
Problem is that when a checkbox is checked or unchecked and ajax returned the calendar always renders on the current month ( so right now it would always rerender itself to show events for september, untill the end of the month, then always for Ocbober and so on ), but what if a user was on lets say November 2013 when he checked event category for which he wanted to filter the events? The calendar would rerender on September still. How could I make it rerender on the month the user was on when he checked / unchecked a checkbox ?
The code that I have which keeps track ( or at least it should ) of the current month when prev or next month buttons are clicked is this
$('.fc-button-next span').click(function(){
start = $('#fc_calendar').fullCalendar('getView').visEnd;
console.log(start);
});
$('.fc-button-prev span').click(function(){
start = $('#fc_calendar').fullCalendar('getView').visStart;
console.log(start);
});
However this code is not tracking properly, sometimes it skips a month, sometimes it stays on the month without change and sometimes it returns propper month, which is bugging me so I cant call this function of the calendar properly which should set calendar to propper month on rerender.
$('#fc_calendar').fullCalendar('gotoDate', start);
I think what you might be looking for is something like
jQuery(function($){
$('form.eventFilter').submit(function() {
$('#fc_calendar').fullCalendar( 'refetchEvents' );
return false;
});
$('#fc_calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
editable: true,
events: function(start, end, callback) {
var selectedOption = $('form.eventFilter select').val(),
eventContainer = $('.fc-event-container');
//create the data to be sent
var objectToSend = {
"categories": [selectedOption],
"datefrom": start.getDate() + '-' + start.getMonth() + '-' + start.getYear(),
"dateto": end.getDate() + '-' + end.getMonth() + '-' + end.getYear()
};
//use jsonp based jQuery request
$.ajax({
url: 'events.json',
data: objectToSend,
cache: false
}).done(function(data){
//on success call `callback` with the data
callback(data)
})
}
});
});
Demo: Plunker
Note: The date param formatting and jsonp is not used here, you will have to change it to match your requirements
I see that you use JSON.stringify(data); this is what i tought your error was
maybe you need a jsonp, and below you have my example
$.ajax({
'url': 'http://domain.com/index.php/api/news?callback=?',
'data': {'data': JSON.stringify(data), callback: 'jsonPCallback'},
'success': function(data) {
// console.log(data);
},
jsonpCallback: jsonPCallback,
dataType: 'jsonp'
});
function jsonPCallback(cbdata){
console.log('callback2')
// console.log(cbdata);
return false;
}
now, do you also use something like
echo $_GET['callback'].'('.CJSON::encode(array('status_live' => 1, 'data' => $data_decoded)).')';
in the controller to return the results ?
also, createUrl might be wrong, because you need a absolute path
Actualy the problem solution is as weird as the problem itself and it is the following. You must use designated way of doing an ajax call to fetch json that is in the plugin documentation, any other way you send your own call ( GET or POST ) and the calendar after that makes yet another call ( hence the another GET call ) if you are using just a "regular" $.ajax, $.post or $.get call using jQueries native functionality
This should really be posted somewhere on the website in some section so that people do not get confused why their calendar is not making ajax calls and I wonder how noone else had similar problem before . So this is the "correct" documentation way of calling it with full calendar which you can find HERE
$('#fc_calendar').html('');
$('#fc_calendar').fullCalendar({
eventSources: [
// your event source
{
url: '?r=calendar/events',
type: 'POST',
data: { data : JSON.stringify(objectToSend)},
error: function(data) {
alert(data);
},
}
// any other sources...
]
});
So it will automaticly fetch any returned ( properly formatted data ) and use it to rerender new calendar with those events. It is very weird way of doing it, but the only way that will work.
I can't comment so, you have an assignment to variable:"nothing" in your last query parameter
double check if you have looked for ajax request in your controller(important!),
and also if this is this a 404 by the apache, you have url rewriting problems,
and it looks like index.php is missing from url?!

how to send object array in ext js 4 to server side?

i am working in extjs4 MVC where I have been working on task to create question answer page functionality.There are 4 questions to be displayed with there options.I have getting all the selected questions and answers in controller.But I didnot know how to send to srver side using models method.I am getting stuck at this point.
Here is my some controller code
1)
check:function()
{
console.log("Inside check function.");
//creating objects in javascript
var obj=new Object();
for(var i=0;i<=5;i++)
{
var inputs = document.getElementsByName(i);
var radio = "";
for (var j = 0; j < inputs.length; j++) {
if (inputs[j].checked) {
name = inputs[j].name;
value = inputs[j].value;
//obj[i].name1=name;
obj[i]={'questionId':name,'option':value};
console.log("questionId="+name +" value="+ value);
console.log("object name="+ obj[i].questionId+" Object value="+obj[i].option);
}// End of if statment
}// End of inner for loop
}//End of outer for loop
}// End of check function
2)here is I have getting some output in firebug
questionId=1 value=Aus QbqnsController.js:39
questionId=2 value=india QbqnsController.js:39
questionId=3 value=England QbqnsController.js:39
questionId=4 value=Srilanka
Actually i want to use model class methods save() . but how can I use it.
please give me some suggestions.
3)here is my model classs
Ext.define('Balaee.model.qb.QbqnsModel',{
extend: 'Ext.data.Model',
idproperty:'questionId',//fields property first position pk.
fields: ['questionId','question','languageId','userId','creationTime','questionStatusId','keyword'],
hasMany:{
model:'Balaee.model.qb.QbqnsoptionModel',
foreignKey:'questionId',
name:'options',
},
proxy:
{
type:'ajax',
api:
{
read:'http://localhost/balaee/balaee/index.php?r=QuestionBank/qbpaper/setuseranswer',
create:'http://localhost/balaee/balaee/index.php?r=QuestionBank/qbpaper/setuseranswer',
},//end of api
reader:
{
type:'json',
},//end of reader
writer:
{
type:'json',
root:'records',
},//End of writer
}
});
If you're using Ext MVC and you're questions are model instances stored inside a store, you can use store.sync() which will batch the data in different states (add, edit, deletes etc) and sync them with the relevant store or model proxy url, or the api urls specified.
This has the benefit of sending arrays of objects back in a single request, but then of course you need to separate them on the server side before processing.
Inside your function you can send them using Ext.Ajax.request
Ext.Ajax.request({
url: 'your_server_page.php ',
params: {
Your_Object_Name : JSON.stringify(Your_Object_Array)
}
});

JavaScript: Backbone.js populate collection of models

Here is what I have so far:
var Item = Backbone.Model.extend({
defaults: {
id: 0,
pid: 0,
t: null,
c: null
},
idAttribute: 'RootNode_', // what should this be ???
url: 'page.php'
});
var ItemList = Backbone.Collection.extend({
model: Item,
url: 'page.php',
parse: function(data) {
alert(JSON.stringify(data)); // returns a list of json objects, but does nothing with them ???
}
});
var ItemView = Backbone.View.extend({
initialize: function() {
this.list = new ItemList();
this.list.bind('all', this.render, this);
this.list.fetch();
},
render: function() {
// access this.list ???
}
});
var view = new ItemView();
Current (expected) json response:
{
"RootElem_0":{"Id":1,"Pid":1,"T":"Test","C":"Blue"},
"RootElem_1":{"Id":2,"Pid":1,"T":"Test","C":"Red"},
"RootElem_2":{"Id":3,"Pid":1,"T":"Test2","C":"Money"}
}
This successfully polls page.php and the backend acts on $_SERVER['REQUEST_METHOD'] and returns the required information, however I don't know why the collection is not filled.
In the parse function of ItemList it properly shows me all the output, but it does nothing with it.
I left some comments in the code for some more precise questions, but the main question is why doesn't the collection populate with the obviously received data?
Modify your parse method to:
parse: function(response){
var parsed = [];
for(var key in response){
parsed.push(response[key]);
}
return parsed;
}
To follow conventions, change list inside ItemView to model. Also in render():
render: function() {
var template = _.template("<div>some template</div>");
this.model.each(function(item){
this.$el.append(template(item.toJSON()));
}, this);
return this;
}
The parse method you're supposed to be returning the data after doing whatever necessary parsing is required for it.
The common use case for parse would be if you're sending back an object of a form like:
{ "id" : "NaN", "tasks": [ *all your models in a list here *] }
then you'd use parse like so:
parse: function (data) {
return data.tasks
}
Backbone then handles the rest.
Is there a particular reason why you're sending the data back in that dictionary format? It's not exactly clear how you intend to map that to each model of the collection. Is the key irrelevant? if so, you should be passing back a list of the objects in the values.(Although see note at bottom). If not, and you want to attach it to the models, it should be moved to the object you're using as a value and send back a list.
* Note: Don't actually send back a JSON list bare. There is an exploit for GET requests that relies on lists being valid javascript on their own, where a malicious site can use the Array object and override it to use a script tag to your API to use the users credentials to pull down whatever information is available in that call. Instead, when wanting to send back a list you should use something like this:
{ result: [*list here*] }
Then you just use the parse method above to extract the list.

Categories