foreach() , array_walk() in the script - php

I have work to used this script in my centos server, but when i try to execute it , i have this Problems Line's.
[27-Nov-2016 14:37:15 UTC] PHP Warning: array_walk() expects parameter 1 to be array, boolean given in /root/facebook-live-reactions/src/Facebook.php on line 48
[27-Nov-2016 14:37:15 UTC] PHP Warning: Invalid argument supplied for foreach() in /root/facebook-live-reactions/src/Renderer.php on line 22
This is the file what he have problem >>
Renderer.php
<?php
namespace FBReactions;
class Renderer {
private $image;
private $settings;
public function __construct($image, $settings) {
$this->image = $image;
$this->settings = $settings;
}
/*
* Adds reaction counts to an image
*/
public function drawReactionCount($reactions)
{
$reactionSettings = $this->settings['REACTION_SETTINGS'];
foreach ($reactions as $index => $reactionCount)
{
$this->image->text(
$reactionCount,
$reactionSettings['REACTIONS'][$index]['XPOS'],
$reactionSettings['REACTIONS'][$index]['YPOS'],
function ($font) use ($reactionSettings) {
$font->file($reactionSettings['FONT']['FAMILY']);
$font->size($reactionSettings['FONT']['SIZE']);
$font->color($reactionSettings['FONT']['COLOR']);
$font->align('center');
}
);
}
}
/*
* Draws the shoutout text to image
*/
public function drawShoutout($user, $shoutout)
{
$shout = "#{$user}, {$shoutout}";
$this->image->text(
$shout,
$this->settings['SHOUTOUT_SETTINGS']['SHOUTOUT_TEXT']['XPOS'],
$this->settings['SHOUTOUT_SETTINGS']['SHOUTOUT_TEXT']['YPOS'],
function ($font) {
$font->file($this->settings['SHOUTOUT_SETTINGS']['SHOUTOUT_TEXT']['FONT']['FAMILY']);
$font->size($this->settings['SHOUTOUT_SETTINGS']['SHOUTOUT_TEXT']['FONT']['SIZE']);
$font->color($this->settings['SHOUTOUT_SETTINGS']['SHOUTOUT_TEXT']['FONT']['COLOR']);
$font->align('left');
}
);
}
/*
* Draws the profile image onto the shoutbox
*/
public function drawProfileImage($filename, $xpos, $ypos)
{
$this->image->insert($filename, 'bottom-left', $xpos, $ypos);
}
/*
* I don't like this! Might be better to return $this->image instead
*/
public function save($filename)
{
return $this->image->save($filename);
}
}
Facebook.php Code:
<?php
namespace FBReactions;
class Facebook {
private $fb;
private $accessToken;
public function __construct($fb, $accessToken) {
$this->fb = $fb;
$this->accessToken = $accessToken;
}
public function reactionCount($objectID, $reactions) {
foreach ($reactions as $key => $position) {
$fields[] = "reactions.type({$key}).limit(0).summary(total_count).as({$key})";
}
$reactionParams = ['ids' => $objectID, 'fields' => join(',', $fields)];
$endpoint = '/?' . http_build_query($reactionParams);
$request = $this->fb->request('GET', $endpoint, [], $this->accessToken);
/*
* Fetch the reactions count from Facebook
*/
try {
$response = $this->fb->getClient()->sendRequest($request);
$reactions = json_decode($response->getBody(), true);
$reactions = current($reactions);
} catch (\Exception $e) {
// die('Error getting reactions: ' . $e);
return [];
}
/*
* We don't need the id element. Remove it.
*/
unset($reactions['id']);
/*
* We're only interested in the reaction count
*/
array_walk($reactions, function(&$reaction) {
$reaction = $reaction['summary']['total_count'];
});
return $reactions;
}
/*
* Fetch latest comments
*/
function comments($objectID)
{
$commentParams = ['filter' => 'stream', 'order' => 'reverse_chronological'];
$request = $this->fb->request(
'GET',
"/{$objectID}/comments?" . http_build_query($commentParams),
[],
$this->accessToken
);
try {
$response = $this->fb->getClient()->sendRequest($request);
return json_decode($response->getBody(), true)['data'];
} catch (\Exception $e) {
// die('Error getting comments: ' . $e);
return [];
}
}
/*
* Returns an array of comments that contains a specific keyword
*/
function commentsByKeyword($objectID, $keyword, $caseSensitive = false)
{
$comments = $this->comments($objectID);
return array_filter($comments, function ($comment) use ($keyword, $caseSensitive) {
$message = $comment['message'];
if ($caseSensitive) {
return strpos($message, $keyword) > -1;
} else {
return strpos(strtolower($message), strtolower($keyword)) > -1;
}
});
}
/*
* Downloads and saves public profile image
*/
function saveProfileImage($uid, $width, $height, $filename)
{
$profileImageParams = [
'width' => $width,
'height' => $height,
];
$endpoint = "http://graph.facebook.com/{$uid}/picture?" . http_build_query($profileImageParams);
copy($endpoint, $filename);
}
}
i well be thankful if any one help me in this case, i work in it two day's without any solution , i try many way to fixed it..
Thank you

You do current in Facebook.php, line 32:
$reactions = current($reactions);
It might the place when you get boolean instead of array: if $reactions array is empty current() method will return false and you will get a warning 'array_walk() parameter 1 to be array, boolean given'. To fix it, before doing current() you should check if $reactions array is not empty

Related

PHP API return JSON and print itself into the DOM structure

I am trying to retrieve a response from Bittrex's rest API, i get a result but for some reason it prints, echo or w/e itself into the dom structure as soon as i recieve it, even if i just call and hold it in a variable?
Class
class Bittrex
{
private $m_baseUrl;
private $m_apiVersion = 'v1.1';
private $m_apiKey;
private $m_apiSecret;
public function __construct ($p_apiKey, $p_apiSecret)
{
$this->m_apiKey = $p_apiKey;
$this->m_apiSecret = $p_apiSecret;
$this->m_baseUrl = 'https://bittrex.com/api/'.$this->m_apiVersion;
}
private function Call($p_function, $p_parameters = array(), $p_usingApiKey = false)
{
$l_uri = $this->m_baseUrl.$p_function;
if($p_usingApiKey)
{
$p_parameters['apikey'] = $this->m_apiKey;
$p_parameters['nonce'] = time();
}
if (!empty($p_parameters))
{
$l_uri .= '?'.http_build_query($p_parameters);
}
$l_curl = curl_init($l_uri);
curl_setopt($l_curl, CURLOPT_HTTPHEADER, array('apisign:'.hash_hmac('sha512', $l_uri, $this->m_apiSecret)));
$l_curlResult = curl_exec($l_curl);
return json_decode($l_curlResult);
}
/*
Used to get the open and available trading markets at Bittrex along with other meta data.
*/
public function GetMarkets()
{
return $this->Call('/public/getmarkets');
}
/*
Used to get all supported currencies at Bittrex along with other meta data.
*/
public function GetCurrencies()
{
return $this->Call('/public/getcurrencies');
}
/*
Used to get the current tick values for a market.
*/
public function GetTicker($p_market)
{
return $this->Call('/public/getticker', array('market' => $p_market));
}
/*
Used to get the last 24 hour summary of all active exchanges.
*/
public function GetMarketSummaries()
{
return $this->Call('/public/getmarketsummaries');
}
/*
Used to get the last 24 hour summary for specific active exchanges.
*/
public function GetMarketSummary($p_market)
{
return $this->Call('/public/getmarketsummary', array('market' => $p_market));
}
/*
Used to get retrieve the orderbook for a given market.
*/
public function GetOrderBook($p_market, $p_type)
{
return $this->Call('/public/getorderbook', array('market' => $p_market, 'type' => $p_type));
}
/*
Used to retrieve the latest trades that have occured for a specific market.
*/
public function GetMarketHistory($p_market)
{
return $this->Call('/public/getmarkethistory', array('market' => $p_market));
}
/*
Used to place a buy order in a specific market.
Make sure you have the proper permissions set on your API keys for this call to work.
*/
public function BuyLimit($p_market, $p_quantity, $p_rate)
{
return $this->Call('/market/buylimit', array('market' => $p_market, 'quantity' => $p_quantity, 'rate' => $p_rate), true);
}
/*
Used to place an sell order in a specific market.
Make sure you have the proper permissions set on your API keys for this call to work.
*/
public function SellLimit($p_market, $p_quantity, $p_rate)
{
return $this->Call('/market/selllimit', array('market' => $p_market, 'quantity' => $p_quantity, 'rate' => $p_rate), true);
}
/*
Used to cancel a buy or sell order.
*/
public function Cancel($p_uuid)
{
return $this->Call('/market/cancel', array('uuid' => $p_uuid), true);
}
/*
Get all orders that you currently have opened.
A specific market can be requested.
*/
public function GetOpenOrders($p_market = null)
{
return $this->Call('/market/getopenorders', array('market' => $p_market), true);
}
/*
Used to retrieve all balances from your account.
*/
public function GetBalances()
{
return $this->Call('/account/getbalances', array(), true);
}
/*
Used to retrieve the balance from your account for a specific currency.
*/
public function GetBalance($p_currency)
{
return $this->Call('/account/getbalance', array('currency' => $p_currency), true);
}
/*
Used to retrieve or generate an address for a specific currency.
If one does not exist, the call will fail and return ADDRESS_GENERATING until one is available.
*/
public function GetDepositAddress($p_currency)
{
return $this->Call('/account/getdepositaddress', array('currency' => $p_currency), true);
}
/*
Used to withdraw funds from your account.
note: please account for txfee.
*/
public function Withdraw($p_currency, $p_quantity, $p_address, $p_paymentId = null)
{
$l_parameters = array(
'currency' => $p_currency,
'quantity' => $p_quantity,
'address' => $p_address
);
if($p_paymentId)
{
$l_parameters['paymentid'] = $p_paymentId;
}
return $this->Call('/account/withdraw', $l_parameters, true);
}
/*
Used to retrieve a single order by uuid.
*/
public function GetOrder($p_uuid)
{
return $this->Call('/account/getorder', array('uuid' => $p_uuid), true);
}
/*
Used to retrieve your order history.
*/
public function GetOrderHistory($p_market = null)
{
$l_parameters = array();
if($p_market)
{
$l_parameters['market'] = $p_market;
}
return $this->Call('/account/getorderhistory', $l_parameters, true);
}
/*
Used to retrieve your withdrawal history.
*/
public function GetWithdrawalHistory($p_currency = null)
{
$l_parameters = array();
if($p_currency)
{
$l_parameters['currency'] = $p_currency;
}
return $this->Call('/account/getwithdrawalhistory', $l_parameters, true);
}
/*
Used to retrieve your deposit history.
*/
public function GetDepositHistory($p_currency = null)
{
$l_parameters = array();
if($p_currency)
{
$l_parameters['currency'] = $p_currency;
}
return $this->Call('/account/getdeposithistory', $l_parameters, true);
}
}
PHP code
$public = "My public key";
$private = "My private key";
require_once 'classes/bittrex.php';
$request = new Bittrex($public, $private);
$markets = $request->GetMarkets();
This is how the dom look like after the PHP
I have tried this aswell but it keeps printing itself into the whole structure, i don't know if i miss remember something or simply just do not know what is going on
Tried
$public = "My public key";
$private = "My private key";
require_once 'classes/bittrex.php';
$request = new Bittrex($public, $private);
$markets = $request->GetMarkets();
$data = json_decode($markets, true);
Can someone tell me how i can tame this data and maybe just hold it in a variable and loop through the data?
curl_setopt($l_curl, CURLOPT_RETURNTRANSFER, true);
http://php.net/manual/en/function.curl-setopt.php
CURLOPT_RETURNTRANSFER
TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it out directly.

Manage files and directories in browser

I'm using a PHP based CMS called Couch (CouchCMS).
The interface is pretty simple. It's easy to edit page content and that's basically it.
I'm now trying to add functionality. I want to add a tab called "files". This tab when activated is going to display all my files. For example it will show me my "images" folder and all the other files located in my website's folder.
Is it possible to somehow with PHP show all my directories on my web page and from there add and remove them?
Try using this function: http://php.net/manual/en/function.readdir.php
But I think you can use jQuery + PHP libraries that do this for you:
https://www.sitepoint.com/10-jquery-file-manager-plugins/
This is a php code used for the Silverstripe cms, don't know if it might work on your side.
<?php
/**
* AssetAdmin is the 'file store' section of the CMS.
* It provides an interface for manipulating the File and Folder objects in the system.
*
* #package cms
* #subpackage assets
*/
class AssetAdmin extends LeftAndMain implements PermissionProvider{
private static $url_segment = 'assets';
private static $url_rule = '/$Action/$ID';
private static $menu_title = 'Files';
private static $tree_class = 'Folder';
/**
* Amount of results showing on a single page.
*
* #config
* #var int
*/
private static $page_length = 15;
/**
* #config
* #see Upload->allowedMaxFileSize
* #var int
*/
private static $allowed_max_file_size;
private static $allowed_actions = array(
'addfolder',
'delete',
'AddForm',
'DeleteItemsForm',
'SearchForm',
'getsubtree',
'movemarked',
'removefile',
'savefile',
'deleteUnusedThumbnails' => 'ADMIN',
'doSync',
'filter',
);
/**
* Return fake-ID "root" if no ID is found (needed to upload files into the root-folder)
*/
public function currentPageID() {
if(is_numeric($this->request->requestVar('ID'))) {
return $this->request->requestVar('ID');
} elseif (is_numeric($this->urlParams['ID'])) {
return $this->urlParams['ID'];
} elseif(Session::get("{$this->class}.currentPage")) {
return Session::get("{$this->class}.currentPage");
} else {
return 0;
}
}
/**
* Set up the controller, in particular, re-sync the File database with the assets folder./
*/
public function init() {
parent::init();
// Create base folder if it doesnt exist already
if(!file_exists(ASSETS_PATH)) Filesystem::makeFolder(ASSETS_PATH);
Requirements::javascript(CMS_DIR . "/javascript/AssetAdmin.js");
Requirements::javascript(CMS_DIR . '/javascript/CMSMain.GridField.js');
Requirements::add_i18n_javascript(CMS_DIR . '/javascript/lang', false, true);
Requirements::css(CMS_DIR . "/css/screen.css");
$frameworkDir = FRAMEWORK_DIR;
Requirements::customScript(<<<JS
_TREE_ICONS = {};
_TREE_ICONS['Folder'] = {
fileIcon: '$frameworkDir/javascript/tree/images/page-closedfolder.gif',
openFolderIcon: '$frameworkDir/javascript/tree/images/page-openfolder.gif',
closedFolderIcon: '$frameworkDir/javascript/tree/images/page-closedfolder.gif'
};
JS
);
CMSBatchActionHandler::register('delete', 'AssetAdmin_DeleteBatchAction', 'Folder');
}
/**
* Returns the files and subfolders contained in the currently selected folder,
* defaulting to the root node. Doubles as search results, if any search parameters
* are set through {#link SearchForm()}.
*
* #return SS_List
*/
public function getList() {
$folder = $this->currentPage();
$context = $this->getSearchContext();
// Overwrite name filter to search both Name and Title attributes
$context->removeFilterByName('Name');
$params = $this->request->requestVar('q');
$list = $context->getResults($params);
// Don't filter list when a detail view is requested,
// to avoid edge cases where the filtered list wouldn't contain the requested
// record due to faulty session state (current folder not always encoded in URL, see #7408).
if(!$folder->ID
&& $this->request->requestVar('ID') === null
&& ($this->request->param('ID') == 'field')
) {
return $list;
}
// Re-add previously removed "Name" filter as combined filter
// TODO Replace with composite SearchFilter once that API exists
if(!empty($params['Name'])) {
$list = $list->filterAny(array(
'Name:PartialMatch' => $params['Name'],
'Title:PartialMatch' => $params['Name']
));
}
// Always show folders at the top
$list = $list->sort('(CASE WHEN "File"."ClassName" = \'Folder\' THEN 0 ELSE 1 END), "Name"');
// If a search is conducted, check for the "current folder" limitation.
// Otherwise limit by the current folder as denoted by the URL.
if(empty($params) || !empty($params['CurrentFolderOnly'])) {
$list = $list->filter('ParentID', $folder->ID);
}
// Category filter
if(!empty($params['AppCategory'])
&& !empty(File::config()->app_categories[$params['AppCategory']])
) {
$exts = File::config()->app_categories[$params['AppCategory']];
$list = $list->filter('Name:PartialMatch', $exts);
}
// Date filter
if(!empty($params['CreatedFrom'])) {
$fromDate = new DateField(null, null, $params['CreatedFrom']);
$list = $list->filter("Created:GreaterThanOrEqual", $fromDate->dataValue().' 00:00:00');
}
if(!empty($params['CreatedTo'])) {
$toDate = new DateField(null, null, $params['CreatedTo']);
$list = $list->filter("Created:LessThanOrEqual", $toDate->dataValue().' 23:59:59');
}
return $list;
}
public function getEditForm($id = null, $fields = null) {
$form = parent::getEditForm($id, $fields);
$folder = ($id && is_numeric($id)) ? DataObject::get_by_id('Folder', $id, false) : $this->currentPage();
$fields = $form->Fields();
$title = ($folder && $folder->exists()) ? $folder->Title : _t('AssetAdmin.FILES', 'Files');
$fields->push(new HiddenField('ID', false, $folder ? $folder->ID : null));
// File listing
$gridFieldConfig = GridFieldConfig::create()->addComponents(
new GridFieldToolbarHeader(),
new GridFieldSortableHeader(),
new GridFieldFilterHeader(),
new GridFieldDataColumns(),
new GridFieldPaginator(self::config()->page_length),
new GridFieldEditButton(),
new GridFieldDeleteAction(),
new GridFieldDetailForm(),
GridFieldLevelup::create($folder->ID)->setLinkSpec('admin/assets/show/%d')
);
$gridField = GridField::create('File', $title, $this->getList(), $gridFieldConfig);
$columns = $gridField->getConfig()->getComponentByType('GridFieldDataColumns');
$columns->setDisplayFields(array(
'StripThumbnail' => '',
// 'Parent.FileName' => 'Folder',
'Title' => _t('File.Name'),
'Created' => _t('AssetAdmin.CREATED', 'Date'),
'Size' => _t('AssetAdmin.SIZE', 'Size'),
));
$columns->setFieldCasting(array(
'Created' => 'Date->Nice'
));
$gridField->setAttribute(
'data-url-folder-template',
Controller::join_links($this->Link('show'), '%s')
);
if($folder->canCreate()) {
$uploadBtn = new LiteralField(
'UploadButton',
sprintf(
'<a class="ss-ui-button ss-ui-action-constructive cms-panel-link" data-pjax-target="Content" data-icon="drive-upload" href="%s">%s</a>',
Controller::join_links(singleton('CMSFileAddController')->Link(), '?ID=' . $folder->ID),
_t('Folder.UploadFilesButton', 'Upload')
)
);
} else {
$uploadBtn = null;
}
if(!$folder->hasMethod('canAddChildren') || ($folder->hasMethod('canAddChildren') && $folder->canAddChildren())) {
// TODO Will most likely be replaced by GridField logic
$addFolderBtn = new LiteralField(
'AddFolderButton',
sprintf(
'<a class="ss-ui-button ss-ui-action-constructive cms-add-folder-link" data-icon="add" data-url="%s" href="%s">%s</a>',
Controller::join_links($this->Link('AddForm'), '?' . http_build_query(array(
'action_doAdd' => 1,
'ParentID' => $folder->ID,
'SecurityID' => $form->getSecurityToken()->getValue()
))),
Controller::join_links($this->Link('addfolder'), '?ParentID=' . $folder->ID),
_t('Folder.AddFolderButton', 'Add folder')
)
);
} else {
$addFolderBtn = '';
}
if($folder->canEdit()) {
$syncButton = new LiteralField(
'SyncButton',
sprintf(
'<a class="ss-ui-button ss-ui-action ui-button-text-icon-primary ss-ui-button-ajax" data-icon="arrow-circle-double" title="%s" href="%s">%s</a>',
_t('AssetAdmin.FILESYSTEMSYNCTITLE', 'Update the CMS database entries of files on the filesystem. Useful when new files have been uploaded outside of the CMS, e.g. through FTP.'),
$this->Link('doSync'),
_t('AssetAdmin.FILESYSTEMSYNC','Sync files')
)
);
} else {
$syncButton = null;
}
// Move existing fields to a "details" tab, unless they've already been tabbed out through extensions.
// Required to keep Folder->getCMSFields() simple and reuseable,
// without any dependencies into AssetAdmin (e.g. useful for "add folder" views).
if(!$fields->hasTabset()) {
$tabs = new TabSet('Root',
$tabList = new Tab('ListView', _t('AssetAdmin.ListView', 'List View')),
$tabTree = new Tab('TreeView', _t('AssetAdmin.TreeView', 'Tree View'))
);
$tabList->addExtraClass("content-listview cms-tabset-icon list");
$tabTree->addExtraClass("content-treeview cms-tabset-icon tree");
if($fields->Count() && $folder->exists()) {
$tabs->push($tabDetails = new Tab('DetailsView', _t('AssetAdmin.DetailsView', 'Details')));
$tabDetails->addExtraClass("content-galleryview cms-tabset-icon edit");
foreach($fields as $field) {
$fields->removeByName($field->getName());
$tabDetails->push($field);
}
}
$fields->push($tabs);
}
// we only add buttons if they're available. User might not have permission and therefore
// the button shouldn't be available. Adding empty values into a ComposteField breaks template rendering.
$actionButtonsComposite = CompositeField::create()->addExtraClass('cms-actions-row');
if($uploadBtn) $actionButtonsComposite->push($uploadBtn);
if($addFolderBtn) $actionButtonsComposite->push($addFolderBtn);
if($syncButton) $actionButtonsComposite->push($syncButton);
// List view
$fields->addFieldsToTab('Root.ListView', array(
$actionsComposite = CompositeField::create(
$actionButtonsComposite
)->addExtraClass('cms-content-toolbar field'),
$gridField
));
$treeField = new LiteralField('Tree', '');
// Tree view
$fields->addFieldsToTab('Root.TreeView', array(
clone $actionsComposite,
// TODO Replace with lazy loading on client to avoid performance hit of rendering potentially unused views
new LiteralField(
'Tree',
FormField::create_tag(
'div',
array(
'class' => 'cms-tree',
'data-url-tree' => $this->Link('getsubtree'),
'data-url-savetreenode' => $this->Link('savetreenode')
),
$this->SiteTreeAsUL()
)
)
));
// Move actions to "details" tab (they don't make sense on list/tree view)
$actions = $form->Actions();
$saveBtn = $actions->fieldByName('action_save');
$deleteBtn = $actions->fieldByName('action_delete');
$actions->removeByName('action_save');
$actions->removeByName('action_delete');
if(($saveBtn || $deleteBtn) && $fields->fieldByName('Root.DetailsView')) {
$fields->addFieldToTab(
'Root.DetailsView',
CompositeField::create($saveBtn,$deleteBtn)->addExtraClass('Actions')
);
}
$fields->setForm($form);
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
// TODO Can't merge $FormAttributes in template at the moment
$form->addExtraClass('cms-edit-form cms-panel-padded center ' . $this->BaseCSSClasses());
$form->setAttribute('data-pjax-fragment', 'CurrentForm');
$form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
$this->extend('updateEditForm', $form);
return $form;
}
public function addfolder($request) {
$obj = $this->customise(array(
'EditForm' => $this->AddForm()
));
if($request->isAjax()) {
// Rendering is handled by template, which will call EditForm() eventually
$content = $obj->renderWith($this->getTemplatesWithSuffix('_Content'));
} else {
$content = $obj->renderWith($this->getViewer('show'));
}
return $content;
}
public function delete($data, $form) {
$className = $this->stat('tree_class');
$record = DataObject::get_by_id($className, Convert::raw2sql($data['ID']));
if($record && !$record->canDelete()) return Security::permissionFailure();
if(!$record || !$record->ID) throw new HTTPResponse_Exception("Bad record ID #" . (int)$data['ID'], 404);
$parentID = $record->ParentID;
$record->delete();
$this->setCurrentPageID(null);
$this->response->addHeader('X-Status', rawurlencode(_t('LeftAndMain.DELETED', 'Deleted.')));
$this->response->addHeader('X-Pjax', 'Content');
return $this->redirect(Controller::join_links($this->Link('show'), $parentID ? $parentID : 0));
}
/**
* Get the search context
*
* #return SearchContext
*/
public function getSearchContext() {
$context = singleton('File')->getDefaultSearchContext();
// Namespace fields, for easier detection if a search is present
foreach($context->getFields() as $field) $field->setName(sprintf('q[%s]', $field->getName()));
foreach($context->getFilters() as $filter) $filter->setFullName(sprintf('q[%s]', $filter->getFullName()));
// Customize fields
$context->addField(
new HeaderField('q[Date]', _t('CMSSearch.FILTERDATEHEADING', 'Date'), 4)
);
$context->addField(
DateField::create(
'q[CreatedFrom]',
_t('CMSSearch.FILTERDATEFROM', 'From')
)->setConfig('showcalendar', true)
);
$context->addField(
DateField::create(
'q[CreatedTo]',
_t('CMSSearch.FILTERDATETO', 'To')
)->setConfig('showcalendar', true)
);
$appCategories = array(
'image' => _t('AssetAdmin.AppCategoryImage', 'Image'),
'audio' => _t('AssetAdmin.AppCategoryAudio', 'Audio'),
'mov' => _t('AssetAdmin.AppCategoryVideo', 'Video'),
'flash' => _t('AssetAdmin.AppCategoryFlash', 'Flash', 'The fileformat'),
'zip' => _t('AssetAdmin.AppCategoryArchive', 'Archive', 'A collection of files'),
'doc' => _t('AssetAdmin.AppCategoryDocument', 'Document')
);
$context->addField(
$typeDropdown = new DropdownField(
'q[AppCategory]',
_t('AssetAdmin.Filetype', 'File type'),
$appCategories
)
);
$typeDropdown->setEmptyString(' ');
$context->addField(
new CheckboxField('q[CurrentFolderOnly]', _t('AssetAdmin.CurrentFolderOnly', 'Limit to current folder?'))
);
$context->getFields()->removeByName('q[Title]');
return $context;
}
/**
* Returns a form for filtering of files and assets gridfield.
* Result filtering takes place in {#link getList()}.
*
* #return Form
* #see AssetAdmin.js
*/
public function SearchForm() {
$folder = $this->currentPage();
$context = $this->getSearchContext();
$fields = $context->getSearchFields();
$actions = new FieldList(
FormAction::create('doSearch', _t('CMSMain_left_ss.APPLY_FILTER', 'Apply Filter'))
->addExtraClass('ss-ui-action-constructive'),
Object::create('ResetFormAction', 'clear', _t('CMSMain_left_ss.RESET', 'Reset'))
);
$form = new Form($this, 'filter', $fields, $actions);
$form->setFormMethod('GET');
$form->setFormAction(Controller::join_links($this->Link('show'), $folder->ID));
$form->addExtraClass('cms-search-form');
$form->loadDataFrom($this->request->getVars());
$form->disableSecurityToken();
// This have to match data-name attribute on the gridfield so that the javascript selectors work
$form->setAttribute('data-gridfield', 'File');
return $form;
}
public function AddForm() {
$folder = singleton('Folder');
$form = CMSForm::create(
$this,
'AddForm',
new FieldList(
new TextField("Name", _t('File.Name')),
new HiddenField('ParentID', false, $this->request->getVar('ParentID'))
),
new FieldList(
FormAction::create('doAdd', _t('AssetAdmin_left_ss.GO','Go'))
->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept')
->setTitle(_t('AssetAdmin.ActionAdd', 'Add folder'))
)
)->setHTMLID('Form_AddForm');
$form->setResponseNegotiator($this->getResponseNegotiator());
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
// TODO Can't merge $FormAttributes in template at the moment
$form->addExtraClass('add-form cms-add-form cms-edit-form cms-panel-padded center ' . $this->BaseCSSClasses());
return $form;
}
/**
* Add a new group and return its details suitable for ajax.
*
* #todo Move logic into Folder class, and use LeftAndMain->doAdd() default implementation.
*/
public function doAdd($data, $form) {
$class = $this->stat('tree_class');
// check create permissions
if(!singleton($class)->canCreate()) return Security::permissionFailure($this);
// check addchildren permissions
if(
singleton($class)->hasExtension('Hierarchy')
&& isset($data['ParentID'])
&& is_numeric($data['ParentID'])
&& $data['ParentID']
) {
$parentRecord = DataObject::get_by_id($class, $data['ParentID']);
if(
$parentRecord->hasMethod('canAddChildren')
&& !$parentRecord->canAddChildren()
) return Security::permissionFailure($this);
} else {
$parentRecord = null;
}
$parent = (isset($data['ParentID']) && is_numeric($data['ParentID'])) ? (int)$data['ParentID'] : 0;
$name = (isset($data['Name'])) ? basename($data['Name']) : _t('AssetAdmin.NEWFOLDER',"NewFolder");
if(!$parentRecord || !$parentRecord->ID) $parent = 0;
// Get the folder to be created
if($parentRecord && $parentRecord->ID) $filename = $parentRecord->FullPath . $name;
else $filename = ASSETS_PATH . '/' . $name;
// Actually create
if(!file_exists(ASSETS_PATH)) {
mkdir(ASSETS_PATH);
}
$record = new Folder();
$record->ParentID = $parent;
$record->Name = $record->Title = basename($filename);
// Ensure uniqueness
$i = 2;
$baseFilename = substr($record->Filename, 0, -1) . '-';
while(file_exists($record->FullPath)) {
$record->Filename = $baseFilename . $i . '/';
$i++;
}
$record->Name = $record->Title = basename($record->Filename);
$record->write();
mkdir($record->FullPath);
chmod($record->FullPath, Filesystem::config()->file_create_mask);
if($parentRecord) {
return $this->redirect(Controller::join_links($this->Link('show'), $parentRecord->ID));
} else {
return $this->redirect($this->Link());
}
}
/**
* Custom currentPage() method to handle opening the 'root' folder
*/
public function currentPage() {
$id = $this->currentPageID();
if($id && is_numeric($id) && $id > 0) {
$folder = DataObject::get_by_id('Folder', $id);
if($folder && $folder->exists()) {
return $folder;
}
}
$this->setCurrentPageID(null);
return new Folder();
}
public function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $numChildrenMethod = null, $filterFunction = null, $minNodeCount = 30) {
if (!$childrenMethod) $childrenMethod = 'ChildFolders';
if (!$numChildrenMethod) $numChildrenMethod = 'numChildFolders';
return parent::getSiteTreeFor($className, $rootID, $childrenMethod, $numChildrenMethod, $filterFunction, $minNodeCount);
}
public function getCMSTreeTitle() {
return Director::absoluteBaseURL() . "assets";
}
public function SiteTreeAsUL() {
return $this->getSiteTreeFor($this->stat('tree_class'), null, 'ChildFolders', 'numChildFolders');
}
//------------------------------------------------------------------------------------------//
// Data saving handlers
/**
* Can be queried with an ajax request to trigger the filesystem sync. It returns a FormResponse status message
* to display in the CMS
*/
public function doSync() {
$message = Filesystem::sync();
$this->response->addHeader('X-Status', rawurlencode($message));
return;
}
/**
* #################################
* Garbage collection.
* #################################
*/
/**
* Removes all unused thumbnails from the file store
* and returns the status of the process to the user.
*/
public function deleteunusedthumbnails($request) {
// Protect against CSRF on destructive action
if(!SecurityToken::inst()->checkRequest($request)) return $this->httpError(400);
$count = 0;
$thumbnails = $this->getUnusedThumbnails();
if($thumbnails) {
foreach($thumbnails as $thumbnail) {
unlink(ASSETS_PATH . "/" . $thumbnail);
$count++;
}
}
$message = _t(
'AssetAdmin.THUMBSDELETED',
'{count} unused thumbnails have been deleted',
array('count' => $count)
);
$this->response->addHeader('X-Status', rawurlencode($message));
return;
}
/**
* Creates array containg all unused thumbnails.
*
* Array is created in three steps:
* 1. Scan assets folder and retrieve all thumbnails
* 2. Scan all HTMLField in system and retrieve thumbnails from them.
* 3. Count difference between two sets (array_diff)
*
* #return array
*/
private function getUnusedThumbnails() {
$allThumbnails = array();
$usedThumbnails = array();
$dirIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(ASSETS_PATH));
$classes = ClassInfo::subclassesFor('SiteTree');
if($dirIterator) {
foreach($dirIterator as $file) {
if($file->isFile()) {
if(strpos($file->getPathname(), '_resampled') !== false) {
$pathInfo = pathinfo($file->getPathname());
if(in_array(strtolower($pathInfo['extension']), array('jpeg', 'jpg', 'jpe', 'png', 'gif'))) {
$path = str_replace('\\','/', $file->getPathname());
$allThumbnails[] = substr($path, strpos($path, '/assets/') + 8);
}
}
}
}
}
if($classes) {
foreach($classes as $className) {
$SNG_class = singleton($className);
$objects = DataObject::get($className);
if($objects !== NULL) {
foreach($objects as $object) {
foreach($SNG_class->db() as $fieldName => $fieldType) {
if($fieldType == 'HTMLText') {
$url1 = HTTP::findByTagAndAttribute($object->$fieldName,array('img' => 'src'));
if($url1 != NULL) {
$usedThumbnails[] = substr($url1[0], strpos($url1[0], '/assets/') + 8);
}
if($object->latestPublished > 0) {
$object = Versioned::get_latest_version($className, $object->ID);
$url2 = HTTP::findByTagAndAttribute($object->$fieldName, array('img' => 'src'));
if($url2 != NULL) {
$usedThumbnails[] = substr($url2[0], strpos($url2[0], '/assets/') + 8);
}
}
}
}
}
}
}
}
return array_diff($allThumbnails, $usedThumbnails);
}
/**
* #param bool $unlinked
* #return ArrayList
*/
public function Breadcrumbs($unlinked = false) {
$items = parent::Breadcrumbs($unlinked);
// The root element should explicitly point to the root node.
// Uses session state for current record otherwise.
$items[0]->Link = Controller::join_links(singleton('AssetAdmin')->Link('show'), 0);
// If a search is in progress, don't show the path
if($this->request->requestVar('q')) {
$items = $items->limit(1);
$items->push(new ArrayData(array(
'Title' => _t('LeftAndMain.SearchResults', 'Search Results'),
'Link' => Controller::join_links($this->Link(), '?' . http_build_query(array('q' => $this->request->requestVar('q'))))
)));
}
// If we're adding a folder, note that in breadcrumbs as well
if($this->request->param('Action') == 'addfolder') {
$items->push(new ArrayData(array(
'Title' => _t('Folder.AddFolderButton', 'Add folder'),
'Link' => false
)));
}
return $items;
}
public function providePermissions() {
$title = _t("AssetAdmin.MENUTITLE", LeftAndMain::menu_title_for_class($this->class));
return array(
"CMS_ACCESS_AssetAdmin" => array(
'name' => _t('CMSMain.ACCESS', "Access to '{title}' section", array('title' => $title)),
'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')
)
);
}
}
/**
* Delete multiple {#link Folder} records (and the associated filesystem nodes).
* Usually used through the {#link AssetAdmin} interface.
*
* #package cms
* #subpackage batchactions
*/
class AssetAdmin_DeleteBatchAction extends CMSBatchAction {
public function getActionTitle() {
// _t('AssetAdmin_left_ss.SELECTTODEL','Select the folders that you want to delete and then click the button below')
return _t('AssetAdmin_DeleteBatchAction.TITLE', 'Delete folders');
}
public function run(SS_List $records) {
$status = array(
'modified'=>array(),
'deleted'=>array()
);
foreach($records as $record) {
$id = $record->ID;
// Perform the action
if($record->canDelete()) $record->delete();
$status['deleted'][$id] = array();
$record->destroy();
unset($record);
}
return Convert::raw2json($status);
}
}

Logging SOAP envelope in third party library

I am attempting to add logging for the envelope generated by a third party library. I am modifying the updateMetadataField() method below.
I am creating $client like so:
$client = new UpdateClient($UPDATE_END_POINT, $USER_AUTH_ARRAY);
I have tried both $this->client->__getLastRequest() and $this->__getLastRequest() with the same error as a result.
When the SoapClient is instantiated trace is set to true.
Error is
Fatal error: Call to undefined method UpdateClient::__getLastRequest()
So how do I correctly access the __getLastRequest() method?
$USER_AUTH_ARRAY = array(
'login'=>"foo",
'password'=>"bar",
'exceptions'=>0,
'trace'=>true,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
);
class UpdateClient {
private $client;
public function __construct($endpoint, $auth_array) {
$this->client = new SoapClient($endpoint, $auth_array);
}
public function updateMetadataField($uuid, $key, $value) {
$result = $this->client->updateMetadataField(array(
'assetUuid' => $uuid,
'key' => $key,
'value' => $value)
);
if(is_soap_fault($result)) {
return $result;
}
return $result->return . "\n\n" . $this->client->__getLastRequest();
} // updateMetadataField()
} // UpdateClient
UPDATE - adding calling code This code iterates over an array which maps our data to the remote fields.
What I am hoping to do is begin storing the envelope we send to aid in debugging.
$client = new UpdateClient($UPDATE_END_POINT, $USER_AUTH_ARRAY);
foreach ($widen_to_nool_meta_map as $widen => $nool) { // array defined in widen.php
if ($nool != '') {
// handle exceptions
if ($nool == 'asset_created') { // validate as date - note that Widen pulls exif data so we don't need to pass this
if (!strtotime($sa->$nool)) {
continue;
}
} else if ($nool == 'people_in_photo' || $nool == 'allow_sublicensing' || $nool == 'allowed_use_pr_gallery') {
// we store as 0/1 but GUI at Widen wants Yes/No
$sa->$nool = ($sa->$nool == '1') ? 'Yes' : 'No';
} else if ($nool == 'credit_requirements') {
$sa->$nool = $sa->credit_requirements()->label;
}
$result = $client->updateMetadataField($sa->widen_id, $widen, $sa->$nool);
if(is_soap_fault($result)) {
$sync_result = $sync_result . "\n" . $result->getMessage();
} else {
$sync_result = $sync_result . "\n" . print_r($result, 1);
}
} // nool field set
} // foreach mapped field
If you want to access UpdateClient::__getLastRequest() you have to expose that method on the UpdateClient class since the $client is a private variable. The correct way of calling it is $this->client->__getLastRequest().
Take a look at this working example, as you can see I'm consuming a free web service for testing purposes.
<?php
$USER_AUTH_ARRAY = array(
'exceptions'=>0,
'trace'=>true,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
);
class TestClient {
private $client;
public function __construct($endpoint, $auth_array) {
$this->client = new SoapClient($endpoint, $auth_array);
}
public function CelsiusToFahrenheit( $celsius ) {
$result = $this->client->CelsiusToFahrenheit(array(
'Celsius' => $celsius
)
);
if(is_soap_fault($result)) {
return $result;
}
return $result;
}
public function __getLastRequest() {
return $this->client->__getLastRequest();
}
}
try
{
$test = new TestClient( "http://www.w3schools.com/webservices/tempconvert.asmx?wsdl", $USER_AUTH_ARRAY);
echo "<pre>";
var_dump($test->CelsiusToFahrenheit( 0 ));
var_dump($test->__getLastRequest());
var_dump($test->CelsiusToFahrenheit( 20 ));
var_dump($test->__getLastRequest());
echo "</pre>";
}
catch (SoapFault $fault)
{
echo $fault->faultcode;
}
?>

how to return json encoded form errors in symfony

I want to create a webservice to which I submit a form, and in case of errors, returns a JSON encoded list that tells me which field is wrong.
currently I only get a list of error messages but not an html id or a name of the fields with errors
here's my current code
public function saveAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new TaskType(), new Task());
$form->handleRequest($request);
$task = $form->getData();
if ($form->isValid()) {
$em->persist($task);
$em->flush();
$array = array( 'status' => 201, 'msg' => 'Task Created');
} else {
$errors = $form->getErrors(true, true);
$errorCollection = array();
foreach($errors as $error){
$errorCollection[] = $error->getMessage();
}
$array = array( 'status' => 400, 'errorMsg' => 'Bad Request', 'errorReport' => $errorCollection); // data to return via JSON
}
$response = new Response( json_encode( $array ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
}
this will give me a response like
{
"status":400,
"errorMsg":"Bad Request",
"errorReport":{
"Task cannot be blank",
"Task date needs to be within the month"
}
}
but what I really want is something like
{
"status":400,
"errorMsg":"Bad Request",
"errorReport":{
"taskfield" : "Task cannot be blank",
"taskdatefield" : "Task date needs to be within the month"
}
}
How can I achieve that?
I am using this, it works quiet well:
/**
* List all errors of a given bound form.
*
* #param Form $form
*
* #return array
*/
protected function getFormErrors(Form $form)
{
$errors = array();
// Global
foreach ($form->getErrors() as $error) {
$errors[$form->getName()][] = $error->getMessage();
}
// Fields
foreach ($form as $child /** #var Form $child */) {
if (!$child->isValid()) {
foreach ($child->getErrors() as $error) {
$errors[$child->getName()][] = $error->getMessage();
}
}
}
return $errors;
}
I've finally found the solution to this problem here, it only needed a small fix to comply to latest symfony changes and it worked like a charm:
The fix consists in replacing line 33
if (count($child->getIterator()) > 0) {
with
if (count($child->getIterator()) > 0 && ($child instanceof \Symfony\Component\Form\Form)) {
because, with the introduction in symfony of Form\Button, a type mismatch will occur in serialize function which is expecting always an instance of Form\Form.
You can register it as a service:
services:
form_serializer:
class: Wooshii\SiteBundle\FormErrorsSerializer
and then use it as the author suggest:
$errors = $this->get('form_serializer')->serializeFormErrors($form, true, true);
This does the trick for me
$errors = [];
foreach ($form->getErrors(true, true) as $formError) {
$errors[] = $formError->getMessage();
}
PHP has associative arrays, meanwhile JS has 2 different data structures : object and arrays.
The JSON you want to obtain is not legal and should be :
{
"status":400,
"errorMsg":"Bad Request",
"errorReport": {
"taskfield" : "Task cannot be blank",
"taskdatefield" : "Task date needs to be within the month"
}
}
So you may want to do something like this to build your collection :
$errorCollection = array();
foreach($errors as $error){
$errorCollection[$error->getId()] = $error->getMessage();
}
(assuming the getId() method exist on $error objects)
By reading other people's answers I ended up improving it to my needs. I use it in Symfony 3.4.
To be used in a controller like this:
$formErrors = FormUtils::getErrorMessages($form);
return new JsonResponse([
'formErrors' => $formErrors,
]);
With this code in a separate Utils class
<?php
namespace MyBundle\Utils;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
class FormUtils
{
/**
* #param FormInterface $form
* #return array
*/
public static function getErrorMessages(FormInterface $form)
{
$formName = $form->getName();
$errors = [];
/** #var FormError $formError */
foreach ($form->getErrors(true, true) as $formError) {
$name = '';
$thisField = $formError->getOrigin()->getName();
$origin = $formError->getOrigin();
while ($origin = $origin->getParent()) {
if ($formName !== $origin->getName()) {
$name = $origin->getName() . '_' . $name;
}
}
$fieldName = $formName . '_' . $name . $thisField;
/**
* One field can have multiple errors
*/
if (!in_array($fieldName, $errors)) {
$errors[$fieldName] = [];
}
$errors[$fieldName][] = $formError->getMessage();
}
return $errors;
}
}
This will do the trick. This static method runs recursively through the Symfony\Component\Form\FormErrorIterator delivered by calling $form->getErrors(true, false).
<?php
namespace App\Utils;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormErrorIterator;
class FormUtils
{
public static function generateErrorsArrayFromForm(FormInterface $form)
{
$result = [];
foreach ($form->getErrors(true, false) as $formError) {
if ($formError instanceof FormError) {
$result[$formError->getOrigin()->getName()] = $formError->getMessage();
} elseif ($formError instanceof FormErrorIterator) {
$result[$formError->getForm()->getName()] = self::generateErrorsArrayFromForm($formError->getForm());
}
}
return $result;
}
}
Here is the result :
{
"houseworkSection": "All the data of the housework section must be set since the section has been requested.",
"foodSection": {
"requested": {
"requested": "This value is not valid."
}
}
}

Creating helper for my application

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.

Categories