I have a page dashboard.php, which creates a merchant dashboard that shows deals submitted by the merchant. I'm simply trying to separate types of deals by checking to see if a deal is a suggested deal:
...
while ($deals->have_posts()) : $deals->the_post();
$suggested_deal = SA_Post_Type::get_instance( $post->ID );
$boolsuggesteddeal = $suggested_deal->is_suggested_deal();
...
However, the is_suggested_deal() line is causing the page to not display anything past that line.
The SA_POST_TYPE class is outlined below:
class SA_Post_Type extends Group_Buying_Deal {
...
public static function get_instance( $id = 0 ) {
if ( !$id ) {
return NULL;
}
if ( !isset( self::$instances[$id] ) || !self::$instances[$id] instanceof self ) {
self::$instances[$id] = new self( $id );
}
if ( self::$instances[$id]->post->post_type != parent::POST_TYPE ) {
return NULL;
}
return self::$instances[$id];
}
...
public function is_suggested_deal() {
$term = array_pop( wp_get_object_terms( $this->get_id(), self::TAX ) );
return $term->slug == self::TERM_SLUG;
}
...
Since the class and function are both public, why am I unable to call the function? Any help would be greatly appreciated.
EDIT: I can't figure out how to get error reporting on without showing all site users the errors, I'm on a live site. I tried creating an instance of SA_Post_Type(), but that alone cause the page to fail to load anything after that line.
You have not created an instance of the class, do so like this...
$SA_Post_Type = new SA_Post_Type();
Then you are able to access the function...
$boolsuggesteddeal = $SA_Post_Type->is_suggested_deal();
Since is_suggested_deal is not a static function, you have to create a new instance of the SA_Post_Type class firstly.
$sa_post_type = new SA_Post_Type();
$boolsuggesteddeal = $sa_post_type->is_suggested_deal();
Hope this helps.
Related
I have the following code in WordPress so as to try and achive a stage where I can use esc_url(get_permalink() . '?month=' . get_query_var('month'));.
In an attempt to learn more about WordPress and to make a class that would allow me to add more values as and when I need them, I created the following class and linked it into the query_vars filter:
//Create the needed GET vars //
$custom_query_values = array('month','day');
new _custom_query_vars($custom_query_values);
class _custom_query_vars
{
public $_custom_vars;
function __construct($custom_vars){
$this->_custom_vars = $custom_vars;
add_filter('query_vars',array(&$this, '_add_custom_querys'));
}
public function _add_custom_querys(){
// Return an array of values //
foreach($this->_custom_vars as $value)
{
$vars[] = $value;
}
print_r($vars);
return $vars;
}
}
/*function add_custom_query_var( $vars ){
$vars[] = "month";
$vars[] = "day";
return $vars;
}
add_filter( 'query_vars', 'add_custom_query_var' ); */
The above code does not work, instead, when the class is active and when I create a new instance all pages on my website will stop working and I will simple be directed to my root address. However, the function "seems" to be working as the print_r() will indeed print the values of Array ( [0] => month [1] => day ) so the method must be getting passed to the query_var hook in some shape or form.
The second part of the code that is commented out is me trying the standard function that simply returns static values. This works and using the normal esc_url(get_permalink() . '?month=' . get_query_var('month')); works as expected. Any ideas? (one last thing, is there a way of making this http://www.sitename/pagename/month).
Thank you for any and all help,
I am Not Sure But Try This.
public function _add_custom_querys(){
$vars = Array();
foreach($this->_custom_vars as $value){
array_push($vars,$value);
}
return $vars;
}
Im trying to use VisualCaptcha with my Laravel apps. I have tried to adapt this exemple with my code. But I dont know how to adapt this following callback to my controller :
$app->get( '/audio(/:type)', function( $type = 'mp3' ) use( $app ) {
$captcha = new \visualCaptcha\Captcha( $app->session );
if ( ! $captcha->streamAudio( $app->response, $type ) ) {
$app->pass();
}
} );
Here is my controller :
class CaptchaController extends BaseController {
/**
* Start Captcha
*/
public function start($params)
{
$session = new SessionCaptcha();
$captcha = new Captcha($session);
return $captcha->generate();
}
public function audio()
{
$session = new SessionCaptcha();
$captcha = new Captcha($session);
//$response = Response::make();
$response->header('Access-Control-Allow-Origin', '*');
//return var_dump($response);
return $captcha->streamAudio($response, 'mp3');
}
}
The start function works but not the audio function... I dont know how to add the first parameter to "$captcha->streamAudio($firstParam, $extension)".
Just in case other people land here first, this has been answered at https://github.com/emotionLoop/visualCaptcha-PHP/issues/16#issuecomment-53863330
The author mentioned not returning $captcha->generate(); but also some undisclosed modifications.
I want a global array that I can access through controller functions, they can either add or delete any item with particular key. How do I do this? I have made my custom controller 'globals.php' and added it on autoload library.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
$notification_array = array();
$config['notification'] = $notification_array;
?>
following function on controller should add new item to my array
function add_data(){
array_unshift($this->config->item('notification'), "sample-data");
}
after add_data adds to the global array, whenever following function is called from client, it should give the updated array to the client.
function send_json()
{
header('content-type: application/json');
$target = $this->config->item('notification');
echo json_encode($target);
}
But my client always gets empty array. How can I make this happen? Please help.
Hi take advantage of OOP, like this
// put MY_Controller.php under core directory
class MY_Controller extends CI_Controller{
public $global_array = array('key1'=>'Value one','key2'=>'Value2'):
public function __construct() {
parent::__construct();
}
}
//page controller
class Page extends MY_Controller{
public function __construct() {
parent::__construct();
}
function send_json()
{
header('content-type: application/json');
$target = $this->global_array['key1'];
echo json_encode($target);
}
}
One solution I came up is to use session, its easy to use and its "fast" you need to do some benchmarking.
As I commented on both answers above/below there is no way you get same data in different controllers just because with each request everything is "reset", and to get to different controller you need to at least reload tha page. (note, even AJAX call makes new request)
Note that sessions are limited by size, you have a limit of 4kb (CodeIgniter stores session as Cookie) but wait, there is way around, store them in DB (to allow this go to config file and turn it on $config['sess_use_database'] = TRUE; + create table you will find more here)
Well lets get to the answer itself, as I understand you tried extending all your controllers if no do it and place some code in that core/MY_Controller.php file
as follows:
private function _initJSONSession() { //this function should be run in MY_Controller construct() after succesful login, $this->_initJSONSession(); //ignore return values
$json_session_data = $this->session->userdata('json');
if (empty($json_session_data )) {
$json_session_data['json'] = array(); //your default array if no session json exists,
//you can also have an array inside if you like
$this->session->set_userdata($ses_data);
return TRUE; //returns TRUE so you know session is created
}
return FALSE; //returns FALSE so you know session is already created
}
you also need these few functions they are self explainatory, all of them are public so you are free to use them in any controller that is extended by MY_Controller.php, like this
$this->_existsSession('json');
public function _existsSession( $session_name ) {
$ses_data = $this->session->userdata( $session_name );
if (empty( $ses_data )) return FALSE;
return TRUE;
}
public function _clearSession($session_name) {
$this->session->unset_userdata($session_name);
}
public function _loadSession($session_name) {
return (($this->_existsSession( $session_name )) ? $this->session->userdata($session_name) : FALSE );
}
the most interesting function is _loadSession(), its kind of self explainatory it took me a while to fully understand session itself, well in a few words you need to get (load) data that are in session already, do something with it ([CRUD] like add new data, or delete some) and than put back (REWRITE) all data in the same session.
Lets go to the example:
keep in mind that session is like 2d array (I work with 4+5d arrays myself)
$session['session_name'] = 'value';
$session['json'] = array('id' => '1', 'name' => 'asok', 'some_array' => array('array_in_array' => array()), 'etcetera' => '...');
so to write new (rewrite) thing in session you use
{
$session_name = 'json';
$session_data[$session_name] = $this->_loadSession($session_name);
//manipulate with array as you wish here, keep in mind that your variable is
$session_data[$session_name]['id'] = '2'; // also keep in mind all session variables are (string) type even (boolean) TRUE translates to '1'
//or create new index
$session_data[$session_name]['new_index'] = FALSE; // this retypes to (string) '0'
//now put session in place
$this->session->set_userdata($session_data);
}
if you like to use your own function add_data() you need to do this
well you need to pass some data to it first add_data($arr = array(), $data = ''){}
eg: array_unshift( $arr, $data );
{
//your default array that is set to _initJSONSession() is just pure empty array();
$session_name = 'json';
$session_data[$session_name] = $this->_loadSession( $session_name );
// to demonstrate I use native PHP function instead of yours add_data()
array_unshift( $session_data[$session_name], 'sample-data' );
$this->session->set_userdata( $session_data );
unset( $session_data );
}
That is it.
You can add a "global" array per controller.
At the top of your controller:
public $notification_array = array();
Then to access it inside of different functions you would use:
$this->notification_array;
So if you want to add items to it, you could do:
$this->notification_array['notification'] = "Something";
$this->notification_array['another'] = "Something Else";
This has been bugging me all day and there is no end in sight.
When the user of my php application adds a new update and something goes wrong, I need to be able to undo a complex batch of mixed commands. They can be mysql update and insert queries, file deletes and folder renaming and creations.
I can track the status of all insert commands and undo them if an error is thrown.
But how do I do this with the update statements?
Is there a smart way (some design pattern?) to keep track of such changes both in the file structure and the database?
My database tables are MyISAM. It would be easy to just convert everything to InnoDB, so that I can use transactions. That way I would only have to deal with the file and folder operations.
Unfortunately, I cannot assume that all clients have InnoDB support. It would also require me to convert many tables in my database to InnoDB, which I am hesitant to do.
PDO's rowcount() returns eftected rows on updates. mysqli's afftected_rows does the same
I'm by clients you mean clients whose servers you will be placing this application on. If you weren't to require innoDB on the servers you'd have to do some more coding to rollback changes on MyISAM tables.
The best way would be to modularize everything into functions (or class methods)
pseudo code:
function updateThisThing() {
if ( !updateTable() ) {
rollbackUpdateTable();
return false;
}
if ( !updateFiles() ) {
rollbackUpdateFiles();
return false;
}
// more update statements
return true
}
If you're absolutely stuck with MyISAM, you should see if the code can be arranged so that UPDATES are the very last thing performed. If an error occurs before then, no UPDATEs will be made.
If that's not feasible, you'll have to lock the pertinent tables, grab the current records, update them. If error, restore with grabbed records. Unlock tables.
Not very practical which is why there's InnoDB (as you know).
I think that's the basis of this module which you can check out:
http://www.deepbluesky.com/blog/-/myisam-transactions_20/
Have you looked into the Unit of Work pattern?
Here's a really roughshod example of how you might get started.
The basic UnitOfWork container.
class UnitOfWork
{
protected $entities = array();
protected $completed = array();
final public function addEntity( IWorkUnitEntity $entity )
{
$this->entities[] = $entity;
}
final public function execute()
{
try {
foreach ( $this->entities as $entity )
{
$entity->execute();
$completed[] = $entity;
}
}
catch ( UnitOfWorkRollbackException $e )
{
$this->rollbackCompleted();
}
return $this->commitAll();
}
protected function rollbackCompleted()
{
while ( $entity = array_pop( $this->completed ) )
{
$entity->rollback();
}
}
protected function commitAll()
{
try {
foreach ( $this->entities as $entity )
{
$entity->commit();
}
}
catch ( UnitOfWorkRollbackException $e )
{
$this->rollbackCompleted();
return false;
}
return true;
}
}
A couple extras to help it along
class UnitOfWorkRollbackException extends Exception {};
interface IWorkUnitEntity
{
public function execute();
public function rollback();
}
Now, an example of a work entity
class FileMoverEntity implements IWorkUnitEntity
{
protected
$source
, $destination
, $newName
;
public function __construct( $source, $destination, $newName = null )
{
$this->source = $source;
$this->destination = dirname( $destination );
$this->newName = $newName;
}
public function execute()
{
if ( is_readable( $this->source ) && is_writable( $this->destination ) )
{
return true;
}
throw new UnitOfWorkRollbackException( 'File cannot be moved' );
}
public function commit()
{
$filename = ( null === $this->newName )
? basename( $this->source )
: $this->newName
;
if ( !rename( $this->source, $this->destination . DIRECTORY_SEPARATOR . $filename ) )
{
throw new UnitOfWorkRollbackException( 'File move failed' );
}
}
public function rollback()
{
// Nothing to do here since the file doesn't actually move until commit()
}
}
Putting it all together.
$UoW = new UnitOfWork();
$UoW->addEntity( new FileMoverEntity( '/tmp/foo', '/home/me', 'profile.jpg' ) );
$UoW->addEntity( new FileMoverEntity( '/tmp/bar', '/root', 'profile.jpg' ) );
if ( $UoW->execute() )
{
// all operations successful
}
Now, I didn't do some things you'd want to here - like keeping track of which exceptions were thrown so the client script can access that info - but I think you get the idea. And of course you can go on to make work entities for all sorts of operations - DB updates, API calls, whatever.
In terms of connecting to a database without transaction-safe tables - I don't have any insight.
I've been looking at this event-listeners page http://www.doctrine-project.org/documentation/manual/1_1/pl/event-listeners and I'm not sure which is the listener I have to use to make a change after the doSave() method in the BaseModelForm.class.php.
// PlaceForm.class.php
protected function doSave ( $con = null )
{
...
parent::doSave($con);
....
// Only for new forms, insert place into the tree
if($this->object->level == null){
$parent = Place::getPlace($this->getValue('parent'), Language::getLang());
...
$node = $this->object->getNode();
$method = ($node->isValidNode() ? 'move' : 'insert') . 'AsFirstChildOf';
$node->$method($parent); //calls $this->object->save internally
}
return;
}
What I want to do is to make a custom slug with the ancestors' name of that new place. So if I inserting "San Francisco", the slug would be "usa-california-san-francisco"
public function postXXXXXX($event)
{
...
$event->getInvoker()->slug = $slug;
}
The problem is that I'm inserting a new object with no reference to its parent. After it's saved, I insert it to the tree. So I can't change the slug until then.
I think a Transaction listener could work, but I'm use there is a better way I'm not seeing right now.
thanks!
You are looking at the wrong piece of code. As stated by benlumley, you should manage your slug directly in the model, not in the form. To achieve what you want (a recursive slug) is quite easy using doctrine's Sluggable behavior. You need to implement a getUniqueSlug() into your model so that it gets called by the behavior (it's automatic) and handle your slug specifities in there:
public function getUniqueSlug()
{
$slug = '';
$parent = $this->getParent();
if ($parent->exists())
{
$slug = $this->getParent()->getUniqueSlug().'-';
}
return $slug.$this->getName();
}
What we do here is basically traverse all the ancestors of the current object and append the slugs on the go (replace the getParent() by whatever method you use to retrieve an object's parent.
Firstly, I'd put this into the model rather than the form - that way if the object is ever edited/updated the behaviour would still happen.
In the form though, I'd use updateObject:
function updateObject($values = array()) {
parent::updateObject($values);
// do your stuff
}
In the model (looks like you are using doctrine ...) I'd put this into the postSave() method. As I say, I think its better there than the form.
I had the same problems, and the Doctrine_Record::postInsert(Doctrine_Event $event) method did not work for me. Indeed the node aren't hydrated yet.
I had to overwrite the sfFormObject::doSave method like this:
protected function doSave($con = null)
{
$is_new = $this->isNew();
parent::doSave($con);
$this->doSaveNestedSet($con);
$service = $this->getObject();
if( $is_new and ! $service->getClientId() and $parent = $service->getParent())
{
$service->setClient($parent->getClient());
$service->save();
}
}