I have this function that returns a json object:
function getMyFbEvents() {
global $facebook;
try {
$fb_events = $facebook->api('/me/events/');
foreach ($fb_events["data"] as $fb_event_data) {
$event_info = json_decode(file_get_contents('https://graph.facebook.com/' . $fb_event_data['id'] . '/?access_token=' . $facebook->getAccessToken()));
return $event_info;
}
} catch (FacebookApiException $e) {
error_log($e);
$fb_events = null;
return null;
}
}
Now if I want to call that object from another page of the script by calling the relative function, how do I do it?
I mean if I want to loop now $event_info as if it I was inside that function and get each given data, is there a way?
Maybe it may sound a bit "too much" :)
First of instead of returning from within the loop you need to accumulate all of the values then return
function getMyFbEvents() {
global $facebook;
try {
$fb_events = $facebook->api('/me/events/');
$eventDetails = array();
foreach ($fb_events["data"] as $fb_event_data) {
$event_info = json_decode(file_get_contents('https://graph.facebook.com/' . $fb_event_data['id'] . '/?access_token=' . $facebook->getAccessToken()));
$eventDetails[] = $event_info;
}
return $eventDetails;
} catch (FacebookApiException $e) {
error_log($e);
$fb_events = null;
return null;
}
}
Then when you want to use it just say (make sure you include_once the file that implements getMyFbEvents if it is in a different php file.)
$events = getMyFbEvents();
forearch($events as $event){
echo $event->description;
}
On a side note using the global keyword is considered bad practice. A cleaner implementation would just pass in the $facebook variable as a parameter to the function
function getMyFbEvents($facebook) {
try {
//..... the rest of your function
Then to call just
$var = getMyFbEvents($facebook);
Related
I am making an app that translates a word from one language to English and gets information about it (e.g. definition, use in a sentence, synonyms, sound representation)
What my function does:
Searches for the translation in the database. If it is found, we return it.
If it is not found we translate a word using google translate, or Yandex translate API.
If translation is found we download it's sound representation, save the translation to the database and add additional information from other API's
We return a json response with all of the information.
Now my controllers method is really big and I can't find a cleaner way to go about it.
Any help is appreciated.
public function store(Request $request)
{
$translated = $request->get('translated');
$translation = $this->translation->findBy('translated', $translated)->first();
if ($translation) {
return Response::json(['translation' => $this->translation->with(['examples', 'definitions', 'synonyms', 'images'])->find($translation->id)], ResponseCode::HTTP_CREATED);
}
$data = $request->all();
$data['translation'] = $this->translate($translated);
if ($translated == $data['translation']) {
Log::info('Translation not found: ' . $data['translation']);
return $this->translationNotFound();
}
$downloader = new Downloader(new GoogleSpeechDownloader());
$filename = $downloader->download($data['translation']);
if ($filename) $data['sound_name'] = $filename;
$translation = $this->translation->create($data);
$this->createDefinition($translation);
$this->createExample($translation);
$this->createSynonym($translation);
return Response::json(['translation' => $this->translation->with(['examples', 'definitions', 'synonyms', 'images'])->find($translation->id)], ResponseCode::HTTP_CREATED);
}
private function translationNotFound()
{
return Response::json(['error' => 'Vertimas nerastas.'], ResponseCode::HTTP_NOT_FOUND);
}
private function createDefinition($translation)
{
$definition = new Definition();
$definer = new Definer(new DictionaryApiDefiner());
try {
$definition->definition = $definer->getDefinition($translation->translation);
$definition->approved = true;
$translation->definitions()->save($definition);
} catch (\Exception $e) {
Log::alert('Definition for word ' . $translation->translation . ' not found.');
}
}
private function createExample($translation)
{
$example = new Example();
$exampler = new ExampleCreator(new YourDictionaryGouteParserExampler());
try {
$example->example = $exampler->getExample($translation->translation);
$example->approved = true;
$translation->examples()->save($example);
} catch (\Exception $e) {
Log::alert('Example for word ' . $translation->translation . ' not found.');
}
}
private function createSynonym($translation)
{
$creator = new SynonymCreator(new BigHugeLabsSynonymCreator());
foreach ($creator->getSynonyms($translation->translation) as $s) {
$synonym = new Synonym();
$synonym->synonym = $s;
$synonym->approved = true;
$translation->synonyms()->save($synonym);
}
}
private function translate($translated)
{
$translator = new Translator(new GoogleTranslator());
try {
return $translator->translate($translated);
} catch (\Exception $e) {
Log::critical($e->getMessage());
}
$translator = new Translator(new YandexTranslator());
return $translator->translate($translated);
}
If you want cleaner code, just make a class for this job. Two classes for this two API's and in the controller make the check for the word, if not exist in the database, check in the other two API's, just split every action to method in the new two classes that you will make.
I've searched on stackoverflow and other sources but I cant seem to find the issue that is preventing my PHP script from working.
Look at the echo_sql. It produces a healthy update statement which when run updates the database with no problem. Here is a sample:
update waste set waste_name=1 where id =82;
However, when the script is run, it does not apply changes to the database. Here is the script:
if ($_SERVER['REQUEST_METHOD'] == "POST") {
try {
$waste_id = $_POST['waste_id'];
$sql = new db;
$sql->beginTransaction();
$waste_name = $_POST['waste_name'];
$sql->query("update waste set waste_name=:waste_name where id =:waste_id;");
$echo_sql = "update waste set waste_name=$waste_name where id =$waste_id;";
echo $echo_sql;
$sql->bind(':waste_name', $waste_name);
$sql->execute();
$sql->endTransaction();
} catch (Exception $e) {
$sql->rollBack();
echo "Failed: " . $e->getMessage();
}
}
Additional details:
errorCode() = 00000
DB Class:
class db
{
private $stmt;
private $dbc;
public function __construct()
{
$u = "root";
$p = "";
try {
$this->dbc = new PDO('mysql:host=127.0.0.1;dbname=wimsdb', $u, $p);
$this->dbc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
$e->getMessage();
}
}
public function bind($param, $value, $type = NULL)
{
$this->stmt->bindParam($param, $value, $type);
}
public function beginTransaction()
{
return $this->dbc->beginTransaction();
}
public function rollBack()
{
return $this->dbc->rollBack();
}
public function endTransaction()
{
return $this->dbc->commit();
}
public function cancelTransaction()
{
return $this->dbc->rollBack();
}
public function execute()
{
try {
return $this->stmt->execute();
} catch (PDOException $e) {
return $e->errorInfo;
}
}
public function errorCode()
{
return $this->stmt->errorCode();
}
public function query($query)
{
$this->stmt = $this->dbc->prepare($query);
}
}
Please offer your suggestions on how this could be resolved.
You need to bind the :waste_id too:
$waste_id = $_POST['waste_id'];
$sql = new db;
$sql->beginTransaction();
$waste_name = $_POST['waste_name'];
$sql->query("update waste set waste_name=:waste_name where id =:waste_id;");
$sql->bind(':waste_name', $waste_name);
$sql->bind(':waste_id', $waste_id);
Any time you have an issue like this your error checking should return a meaningful message letting you know where the error is and likely what the error is. You should be able to check your error logs for details and/or output them to your screen during testing.
Add waste_id. To avoid missing parameters, I like putting the parameteers into the execute method. The bind method could be defined anywhere in the code so I had to look through your code and make sure waste_id binding wasn't defined somewhere else. When it's in the execute method, you can quickly see all parameters being defined there...it's also a tad more concise...but both have their uses.
if ($_SERVER['REQUEST_METHOD'] == "POST") {
try {
$waste_id = $_POST['waste_id'];
$sql = new db;
$sql->beginTransaction();
$waste_name = $_POST['waste_name'];
$sql->query("update waste set waste_name=:waste_name where id =:waste_id;");
$echo_sql = "update waste set waste_name=$waste_name where id =$waste_id;";
echo $echo_sql;
//just because I like this syntax for being concise and clear :)
$sql->execute(array(
'waste_id' => $waste_id,
'waste_name' => $waste_name
));
$sql->endTransaction();
} catch (Exception $e) {
$sql->rollBack();
echo "Failed: " . $e->getMessage();
}
I need to call Controller-methods dynamically. For this purpose I wrote the following code:
if(isset($method['postParams'])) {
foreach($method['postParams'] as $index => $param) {
$this->request->data[ $index ] = $param;
}
}
App::import('Controller', $method['controller']);
// get result
$method['controller'] = $method['controller'] . 'Controller';
$Controller = new $method['controller']();
try {
if(count($method['params'])) {
$varVal = call_user_func_array(array($Controller, $method['method']), $method['params']);
} else {
$varVal = call_user_func(array($Controller, $method['method']));
}
} catch(Exception $e) {
$varVal = $e;
}
$this->set($varName, $varVal);
Now I debug the function being called and see that $this->request->data is NULL.
How to solve this?
For the sake of completeness I'll post the answer to this problem for anyone having a similar issue to find the solution more easily.
Instead of:
$this->request->data
Use:
$Controller->request->data
After instanciating the $Controller object.
Take the following function for example:
private function connect($method, $target = $this->_config->db()) {
try {
if (!($this->_pointer = #fopen($target, $method)))
throw new Exception("Unable to connect to database");
} catch (Exception $e) {
echo $e->getMessage();
}
}
As you can see I inserted the function $this->_config->db() into the parameter $target as it's default value. I understand this is not the correct syntax and am just trying to explain my aim.
$this->_config->db() is a getter function.
Now I know I can use an anonymous function and call it via $target later, but I want $target to also accept direct string values.
How could I give it a default value of the whatever is returned by $this->_config->db() and still be able to overwrite it with a string value?
Why not accept NULL values by default (test with is_null()) and if so call your default function?
You can use is_callable() and is_string().
private function connect($method, $target = NULL) {
if (is_callable($target)) {
// We were passed a function
$stringToUse = $target();
} else if (is_string($target)) {
// We were passed a string
$stringToUse = $target;
} else if ($target === NULL) {
// We were passed nothing
$stringToUse = $this->_config->db();
} else {
// We were passed something that cannot be used
echo "Invalid database target argument";
return;
}
try {
if (!($this->_pointer = #fopen($stringToUse, $method)))
throw new Exception("Unable to connect to database");
} catch (Exception $e) {
echo $e->getMessage();
}
}
I would perform a check to see if a value was passed and call my function in a simple check inside the method:
private function connect($method, $target = '') {
try {
if ($target === '') {
$target = $this->_config->db()
}
if (!($this->_pointer = #fopen($target, $method))) {
throw new Exception("Unable to connect to database");
}
} catch (Exception $e) {
echo $e->getMessage();
}
}
I have been creating a helper class for the Facebook PHP API in order to avoid reusing a lot of code. The helper works but the only problem is that its very slow.. and I also figured out why! when I initialize the class, the constructor is called twice! I checked in my code and the other elements which use this class only call it once (It's something inside the class itself) Could you please help me figure out what the problems could be?? Thanks!
class FbHelper
{
private $_fb;
private $_user;
function __construct()
{
// Initalize Facebook API with keys
$this->_fb = new Facebook(array(
'appId' => 'xxxxxxxxxxx',
'secret' => 'xxxxxxxxxxxxxxxxxxxxxx',
'cookie' => true,
));
// set the _user variable
//
$this->doLog("Called Constructor");
//
$this->_user = $this->UserSessionAuthorized();
return $this;
}
function doLog($text)
{
// open log file <----- THIS GETS CALLED TWICE EVERY TIME I INITIALIZE THE CLASS!!
$filename = "form_ipn.log";
$fh = fopen($filename, "a") or die("Could not open log file.");
fwrite($fh, date("d-m-Y, H:i")." - $text\n") or die("Could not write file!");
fclose($fh);
}
function getUser() { return $this->_user; }
function getLoginUrl() { return $this->_fb->getLoginUrl(); }
function getLogoutUrl() { return $this->_fb->getLogoutUrl(); }
function UserSessionAuthorized()
{
// Checks if user is authorized, if is sends back user object
$user = null;
$session = $this->_fb->getSession();
if (!$session) return false;
try {
$uid = $this->_fb->getUser();
$user = $this->_fb->api('/me');
if ($user) return $user;
else return false;
}
catch (FacebookApiException $e) { return false; }
}
private function _rebuildSelectedFriends($selected_friends)
{
// Creates a new array with less data, more useful and less malicious
$new = array();
foreach ($selected_friends as $friend)
{
$f = array('id' => $friend['id'], 'name' => $friend['name']);
$new[] = $f;
}
return $new;
}
function GetThreeRandomFriends()
{
$friends = $this->_fb->api('/me/friends');
$n = rand(1, count($friends['data']) - 3);
$selected_friends = array_slice($friends['data'], $n, 3);
return $this->_rebuildSelectedFriends($selected_friends);
}
function UserExists($user_id)
{
try { $this->_fb->api('/' . $user_id . '/'); return true; }
catch (Exception $e) { return false; }
}
}
You must be calling the FbHelper class twice as your doLog function is in the constructor, therefore the repetition is somewhere higher up in your application and not in this class itself.