I have a function that loads data from a JSON file and enters it into the TYPO3 database. If I call this function via the backend Controller (indexAction), then everything works fine. However, when I call it from a task, the data is not saved. By means of test output I see that the object was changed correctly, only the Update or Add is not executed correctly, because the data in the database is not changed.
Here is my controller function:
class ImportController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
protected $siteRepository = null;
public function injectSiteRepository(SiteRepository $siteRepository)
{
$this->siteRepository = $siteRepository;
}
public function indexAction()
{
$this->dataImport();
}
public function dataImport() {
$file = "test.json";
$json = file_get_contents($file);
$jsonarray = json_decode($json);
foreach ($jsonarray->{'sites'} as $site) {
$newValue = false;
$dbSite = $this->siteRepository->getSiteByID($site->{'ID'});
if (empty($dbSite->getFirst())) {
$dbSite = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('test\test123\Domain\Model\Site');
$dbSite->setID($site->{'ID'});
$newValue = true;
} else {
$dbSite = $dbSite->getFirst();
}
//Set Data
$dbSite->setTest($site->{'TEST'});
//This object is correct, even in the Task
DebuggerUtility::var_dump(
$dbSite
);
//Update or Add new Data
if (!$newValue) {
$this->siteRepository->update($dbSite);
} else {
$this->siteRepository->add($dbSite);
}
}
$persistenceManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager');
$persistenceManager->persistAll();
return true;
}
}
Here is my task:
class JsonImportTask extends AbstractTask {
public function execute() {
$objectManager = GeneralUtility::makeInstance(
ObjectManager::class
);
$controller = $objectManager->get(ImportController::class);
$controller->dataImport();
return true;
}
}
Here my repository:
public function getSiteByID($id) {
$query = $this->createQuery();
$query->matching(
$query->equals("uid", $id),
);
return $query->execute();
}
Does anyone have an idea what this could be?
Ok I found my mistake myself. Here is the solution for all who have the same problem:
I added setRespectStoragePage in my getSiteByID function in SiteRepository:
$query->getQuerySettings()->setRespectStoragePage(false);
The error was that it was looking for the data at StoragePid 1. With this command he searches at the right place
Here is my correct repository function:
public function getSiteByID($id) {
$query = $this->createQuery();
$query->getQuerySettings()->setRespectStoragePage(false);
$query->matching(
$query->equals("uid", $id),
);
return $query->execute();
}
I had another problem. You have to set the PID number for new entries.
For example, my data is stored on Page ID 12.
I added this line here:
if (empty($dbSite->getFirst())) {
$dbSite = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('test\test123\Domain\Model\Site');
$dbSite->setID($site->{'ID'});
$newValue = true;
$dbSite->setPid(12); //New Line set PID (For me to PID 12)
} else {
$dbSite = $dbSite->getFirst();
}
I read too many questions and answers around but couldn't be sure.
I have 2 questions
1.I turned my db connection into a function and I am not sure if its
safe ?
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_NAME', 'demo');
function DB()
{
try {
$pdo = new PDO('mysql:host='.DB_SERVER.';dbname='.DB_NAME.'', DB_USERNAME, DB_PASSWORD);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $pdo;
} catch (PDOException $e) {
return "Error!: " . $e->getMessage();
die();
}
}
2.is my query done right way ?
query:
try {
$pdo = DB();
$stmt = $pdo->prepare("SELECT * FROM settings");
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$c = htmlspecialchars($row['site_url']);
$e = filterString($row['contact']);
}
unset($stmt);
} catch (PDOException $e) {
exit($e->getMessage());
}
Thanks for any help
Perhaps keep one connection, rather than opening multiple connections to the Database. You can look into a project PDOEasy that I created to make MVC easy with PDO or use the below static example.
class DB
{
private $_connection;
private static $_instance;
public static function getInstance() {
if(self::$_instance) return self::$_instance;
self::$_instance = new self();
return self::$_instance;
}
private function __construct() {
$this->_connection = new PDO('mysql:host='.DB_SERVER.';dbname='.DB_NAME.'', DB_USERNAME, DB_PASSWORD, array(
PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
));
}
public function getConnection() { return $this->_connection; }
}
Which can be used like so:
$stmt = DB::getInstance()
->getConnection()
->Prepare('SELECT * FROM settings');
$stmt->execute();
foreach($stmt->fetchAll() as $row) {
// ...
}
I want to auto save the sql query every time, I found this article, if I do everything by the page it will work, but the problem is, I have master and slave database, therefore I have to connect to database like:
model/Users.php
<?php
class Users extends CI_Model
{
protected $table = 'users';
public $master;
public $slave;
public function __construct()
{
$this->master = $this->load->database('master', true);
$this->slave = $this->load->database('slave', true);
}
public function save($datas)
{
$this->master->insert($this->table, $datas);
return $this->master;
}
}
Then I adjust demo code like:
<?php
class Query_log
{
public function log_query()
{
$ci =& get_instance();
$filepath = APPPATH . 'logs/Query-log-' . date('Y-m-d') . '.php';
$handle = fopen($filepath, "a+");
$times = $ci->master->query_times;
foreach ($ci->master->queries as $key => $query) {
$sql = $query . " \n Execution Time:" . $times[$key];
fwrite($handle, $sql . "\n\n");
}
fclose($handle);
}
}
Of course I got error message
A PHP Error was encountered
Severity: Notice
Message: Undefined property: Users::$master
Filename: hooks/query_log.php
How to make it right?
I wanted implement the new facebook API v 4.0.0 on my project laravel.
Setting all the necessary informations and credentials for access to my app, when is time to call the function for the login:
$helper = new FacebookRedirectLoginHelper('http://mywebsite.dev');
$loginUrl = $helper->getLoginUrl();
It throw me an exception
FacebookSDKException 'Session not active, could not store state.'
So I dig in to the SDK class of facebook on that line and there is a check about session precisely this one:
if (session_status() !== PHP_SESSION_ACTIVE) {
throw new FacebookSDKException(
'Session not active, could not store state.'
);
}
Then I didn't know why this happen so i tried to put the same check on a clean route and see the result
Route::get('test',function() {
if (session_status() !== PHP_SESSION_ACTIVE)
{
return "is not active";
}
return "is active";
});
And it return is not active why this happen? in this way I cannot use the new facebook API with laravel?
Sharing how I implemented Facebook SDK V4 on Laravel 4.
Here's what I added on default composer.json
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php"
],
"psr-4" : {
"Facebook\\":"vendor/facebook/php-sdk-v4/src/Facebook/"
}
},
Added Facebook initialization on my index.php, like this :
/*
|--------------------------------------------------------------------------
| Initialized Facebook PHP SDK V4
|--------------------------------------------------------------------------
|
*/
//Initialize
use Facebook\FacebookSession;
FacebookSession::setDefaultApplication(Config::get('facebook.AppId'),Config::get('facebook.AppSecret'));
And for the Session, Laravel doesn't use $_SESSION so you don't need to do session_start at all. For you to be able to use Laravel session on Facebook PHP SDK V4, you need to extend Facebook's FacebookRedirectLoginHelper class.
Here's how how to subclass FacebookRedirectLoginHelper and overwrite Session handling.
class LaravelFacebookRedirectLoginHelper extends \Facebook\FacebookRedirectLoginHelper
{
protected function storeState($state)
{
Session::put('state', $state);
}
protected function loadState()
{
$this->state = Session::get('state');
return $this->state;
}
protected function isValidRedirect()
{
return $this->getCode() && Input::has('state')
&& Input::get('state') == $this->state;
}
protected function getCode()
{
return Input::has('code') ? Input::get('code') : null;
}
//Fix for state value from Auth redirect not equal to session stored state value
//Get FacebookSession via User access token from code
public function getAccessTokenDetails($app_id,$app_secret,$redirect_url,$code)
{
$token_url = "https://graph.facebook.com/oauth/access_token?"
. "client_id=" . $app_id . "&redirect_uri=" . $redirect_url
. "&client_secret=" . $app_secret . "&code=" . $code;
$response = file_get_contents($token_url);
$params = null;
parse_str($response, $params);
return $params;
}
}
And one more step, you need to do a composer command to regenerate autoload files :
composer dump-autoload -o
Ok, if all goes right, you are now ready to start using the SDK, here's a sample
Here's an excerpt from one of my project classes :
namespace Fb\Insights;
//Facebook Classes
use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\FacebookSDKException;
//Our Facebook Controller
use FbController;
class PagePosts extends \Facebook\GraphObject {
/*
Get Page Posts Impression
https://developers.facebook.com/docs/graph-api/reference/v2.0/insights#post_impressions
*/
public static function getPagePostsImpressions($postid = null) {
$fbctrl = new FbController();
$metricNames = array(
'post_impressions',
'post_impressions_unique',
'post_impressions_paid',
'post_impressions_paid_unique',
'post_impressions_fan',
'post_impressions_fan_unique',
'post_impressions_fan_paid',
'post_impressions_fan_paid_unique',
'post_impressions_organic',
'post_impressions_organic_unique',
'post_impressions_viral',
'post_impressions_viral_unique',
'post_impressions_by_story_type',
'post_impressions_by_story_type_unique',
'post_impressions_by_paid_non_paid',
'post_impressions_by_paid_non_paid_unique'
);
$postsInsights = array();
$batch = array();
$limit = $fbctrl->FacebookGraphDateLimit();
//craft our batch API call
for($i=0; $i<count($metricNames); $i++) {
$batch[] = json_encode(array('method' => 'GET','relative_url' => $postid . '/insights/' . $metricNames[$i] . '?since=' . $limit['since'] . '&until=' . $limit['until'] ));
}
$params = array( 'batch' => '[' . implode(',',$batch ) . ']' );
$session = new FacebookSession($fbctrl->userAccessToken);
try {
$res = (new FacebookRequest($session,'POST','/',$params))
->execute()
->getGraphObject();
} catch(FacebookRequestException $ex) {
//log this error
echo $ex->getMessage();
} catch(\Exception $ex) {
//log this error
echo $ex->getMessage();
}
//Collect data
for($i=0; $i<count($batch); $i++) {
$resdata = json_decode(json_encode($res->asArray()[$i]),true);
$fbctrl->batchErrorDataChecker($resdata,$postsInsights,$metricNames[$i]);
}
return $postsInsights;
}
Feel free comment or suggest so I can also improve my code.
Happy coding.
I solve extending that class and overwriting the following 2 methods that require native sessions.
protected function storeState($state)
{
Session::put('facebook.state', $state);
}
protected function loadState()
{
return $this->state = Session::get('facebook.state');
}
I used follow steps using Composer and had problem "Session not active, could not store state" so session_start() fixed my issue.
require_once './vendor/autoload.php';
use Facebook\FacebookSession;
use Facebook\FacebookRedirectLoginHelper;
use Facebook\FacebookRequest;
session_start();
FacebookSession::setDefaultApplication('apid', 'appscret');
$helper = new FacebookRedirectLoginHelper("callbackurl", $apiVersion = NULL);
try {
$session = $helper->getSessionFromRedirect();
} catch (FacebookRequestException $ex) {
// When Facebook returns an error
} catch (\Exception $ex) {
// When validation fails or other local issues
}
if (isset($session)) {
$request = new FacebookRequest($session, 'GET', '/me');
$response = $request->execute();
$graphObject = $response->getGraphObject();
var_dump($graphObject);
} else {
echo 'Login with Facebook';
}
To solve problem call session_start php function after to inizialize FacebookRedirectLoginHelper somthing like this:
session_start();
$helper = new FacebookRedirectLoginHelper('http://mywebsite.dev');
$loginUrl = $helper->getLoginUrl();
kaixersoft's answer really saved my bacon a little while ago, and I got everything to work by following his instructions using the custom LaravelFacebookRedirectLoginHelper class. But today I went to do a 'composer update' and for some reason, it broke everything. I've modified kaixersoft's LaravelFacebookRedirectLoginHelper class so that it works now, specifically the isValidRedirect method. Here is the updated class:
class LaravelFacebookRedirectLoginHelper extends \Facebook\FacebookRedirectLoginHelper
{
protected function storeState($state)
{
Session::put('state', $state);
}
protected function loadState()
{
$this->state = Session::get('state');
return $this->state;
}
protected function isValidRedirect()
{
$savedState = $this->loadState();
if (!$this->getCode() || !isset($_GET['state'])) {
return false;
}
$givenState = $_GET['state'];
$savedLen = mb_strlen($savedState);
$givenLen = mb_strlen($givenState);
if ($savedLen !== $givenLen) {
return false;
}
$result = 0;
for ($i = 0; $i < $savedLen; $i++) {
$result |= ord($savedState[$i]) ^ ord($givenState[$i]);
}
return $result === 0;
}
protected function getCode()
{
return Input::has('code') ? Input::get('code') : null;
}
//Fix for state value from Auth redirect not equal to session stored state value
//Get FacebookSession via User access token from code
public function getAccessTokenDetails($app_id,$app_secret,$redirect_url,$code)
{
$token_url = "https://graph.facebook.com/oauth/access_token?"
. "client_id=" . $app_id . "&redirect_uri=" . $redirect_url
. "&client_secret=" . $app_secret . "&code=" . $code;
$response = file_get_contents($token_url);
$params = null;
parse_str($response, $params);
return $params;
}
}
session_status function is available on (PHP >=5.4.0) version. So if you are using older version of PHP then Please update it Or Just
// change this
if (session_status() !== PHP_SESSION_ACTIVE) {
throw new FacebookSDKException(
'Session not active, could not store state.'
);
}
//into this
if(session_id() === "") {
throw new FacebookSDKException(
'Session not active, could not load state.'
);
}
How Zend_Paginator can work according to the exchange of the variable query?
In line 8 performs a single fetch and does not change even by changing the query variable.
How to do paging function in accordance with the start-index from gdata feed?
The code: http://pastebin.com/rmxSP1Us
$yt = new Zend_Gdata_YouTube();
$limit = 12;
$offset = ($page - 1) * $limit + 1;
$query = "http://gdata.youtube.com/feeds/api/users/aculinario/favorites?start-index=$offset";
$paginator = Zend_Paginator::factory($yt->getVideoFeed($query));
$paginator->setCurrentPageNumber($page);
$paginator->setItemCountPerPage($limit);
$paginator->setPageRange(6);
$this->view->paginator = $paginator;
echo $query // query changes but paginator no, every time Zend_Paginator factory should check the returned array of getVideoFeed, but not this checking
Sry, my poor english, i'm Trying
I got something similar working using a quick & dirty paginator adapter.
It's worth noting there's probably nicer, more generic ways to achieve this. But this will get you going if you're in a hurry.
<?php
class Lib_Paginator_Adapter_YoutubeUser implements Zend_Paginator_Adapter_Interface
{
protected $_username;
protected $_results;
public function __construct($username)
{
$this->_username = $username;
}
public function getItems($offset, $itemCountPerPage)
{
$url = sprintf(
'%s/%s/%s',
Zend_Gdata_YouTube::USER_URI,
$this->_username,
Zend_Gdata_YouTube::UPLOADS_URI_SUFFIX
);
try
{
$query = new Zend_Gdata_Query($url);
$query->setMaxResults($itemCountPerPage)
->setStartIndex($offset);
$youtube = new Zend_Gdata_YouTube();
$this->_results = $youtube->getUserUploads(null, $query);
return $this->_results;
}
catch (Exception $ex)
{
echo $ex->getMessage();
exit;
}
}
public function count()
{
try
{
$youtube = new Zend_Gdata_YouTube();
return $youtube->getUserUploads($this->_username)->getTotalResults()->getText();
}
catch (Exception $ex)
{
echo $ex->getMessage();
exit;
}
}
}
Then in your controller
$page = $this->getRequest()->getParam("page");
$limit = 10;
$username = 'aculinario';
$paginator = new Zend_Paginator(new Lib_Paginator_Adapter_YoutubeUser($username));
$paginator->setItemCountPerPage($limit);
$paginator->setPageRange(10);
$paginator->setCurrentPageNumber($page);
$this->view->youtubeFeed = $paginator;