Pimcore: Retrieve Single Object List by Multiple Class Types - custom-lists

I currently have a controller that pulls objects from the Pimcore Objects exactly how the sample data demonstrated.
What we need to accomplish with this build, is to allow for a "Featured" category to be assigned to any NewsArticle object or EventsArticle object. We need to pull a combined list from both NewsArticle and EventsArticle objects that also have the Featured category assigned to them. We need to keep track of all the IDs returned in this list, and exclude them from the single track lists so that they aren't displayed twice on the same page.
These are our two single track lists which work as expected, limited by custom properties that live on the document.
Requirements:
Filter by featured category.
Prevent any post from being listed twice.
Able to sort by date asc or desc.
// TODO: List Featured News and Events Objects...
// $this->view->featured = $featuredList->getObjects();
// List News Objects...
$newsList = new Object\NewsArticle\Listing();
$newsList->setOrderKey( "date" );
$newsList->setOrder( "DESC" );
$newsList->setLimit( $this->document->getProperty( 'newsLimit' ) );
// TODO: Exclude any IDs in $this->view->featured
$this->view->news = $newsList->getObjects();
// List Events Objects...
$eventsList = new Object\EventsArticle\Listing();
$eventsList->setOrderKey( "date" );
$eventsList->setOrder( "DESC" );
$eventsList->setLimit( $this->document->getProperty( 'eventsLimit' ) );
// TODO: Exclude any IDs in $this->view->featured
$this->view->events = $eventsList->getObjects();

This approach will give you the featured list:
$featuredListObj = \Pimcore\Model\Object::getByPath("featured-list");
$featuredListObjId = $featuredListObj->getId();
$eventClassId = \Pimcore\Model\Object\ClassDefinition::getByName("news")->getId();
$newsClassId = \Pimcore\Model\Object\ClassDefinition::getByName("event")->getId();
$combinedListing = new Pimcore\Model\Object\Listing();
$combinedListing->setCondition("o_className IN ('event','news') AND o_id IN (
SELECT o_id FROM object_$eventClassId WHERE categories LIKE '%,$featuredListObjId,%'
UNION SELECT o_id FROM object_$newsClassId WHERE categories LIKE '%,$featuredListObjId,%'
)");
foreach ($combinedListing as $item) {
echo get_class($item) . "<br>";
}

After some toil I've figured out a way to do this. It may not be optimal, but it works and gets the job done.
The reason why I've found this way to be most effective is because setCondition will also check non-target classes for columns they might not have, causing the list to fail.
#
# Hybridized Featured Articles List
#
# Get News and Events Objects...
$hybridList = new Object\Listing();
$hybridList->setCondition( "o_className IN ( 'newsArticle', 'eventsArticle' )" );
# Get a list of IDs for News and Events that have the "featured" category...
$featuredList = array();
foreach( $hybridList->getObjects() as $obj ) {
foreach( $obj->categories as $obj_cat ) {
if( $obj_cat->o_key == 'featured' ) {
$key = strtotime( $obj->date->date );
$key .= str_pad( $obj->o_id, 8, "0", STR_PAD_LEFT );
$featuredList[ $key ] = $obj;
break;
}
}
}
# Sort and Slice the list...
if( $this->document->getProperty( 'featuredSort' ) == 'asc' ) {
ksort( $featuredList ); // Oldest First
} else {
krsort( $featuredList ); // Newest First
}
$this->view->featured = array_slice( $featuredList, 0, $this->document->getProperty( 'featuredLimit' ) );
#
# Audit the Hybridized Featured Articles List for IDs
#
$block_ids = array();
foreach( $this->view->featured as $featured ) {
$block_ids[] = (int)$featured->o_id;
}
#
# News Articles List...
#
$newsList = new Object\NewsArticle\Listing();
$newsList->setOrderKey( "date" );
$newsList->setOrder( $this->document->getProperty( 'newsSort' ) == 'asc' ? 'asc' : 'desc' );
$newsList->setCondition( 'o_id NOT IN ('.implode( ',', $block_ids ).')' );
$newsList->setLimit( $this->document->getProperty( 'newsLimit' ) );
$this->view->news = $newsList->getObjects();
#
# Events Articles List...
#
$eventsList = new Object\EventsArticle\Listing();
$eventsList->setOrderKey( "date" );
$eventsList->setOrder( $this->document->getProperty( 'eventsSort' ) == 'asc' ? 'asc' : 'desc' );
$eventsList->setCondition( 'o_id NOT IN ('.implode( ',', $block_ids ).')' );
$eventsList->setLimit( $this->document->getProperty( 'eventsLimit' ) );
$this->view->events = $eventsList->getObjects();

Related

Perl Gtk2 CellRendererCombo: get selected item index

I have Gtk2::TreeView, some of columns are using CellRendererCombo. I have everything work ok, except of I can't get integer index of selected item in CellRendererCombo. Not a text, but the integer value.
As a workaround, it could be useful to associate somehow a hash with combo_model, but I don't know how.
Could somebody help me? Trying and googling for a couple of days already.
Here's the code:
#!/usr/bin/perl
package uform;
use utf8;
use warnings;
use strict;
use Gtk2 -init;
use Glib qw/TRUE FALSE/;
use Glib ':constants';
use Data::Dumper;
use constant col0 => 0;
use constant col1 => 1;
use constant col2 => 2;
use constant colC => 3;
binmode(STDOUT,':utf8');
my $model; my $treeview; my #attr_models;
sub create_window ($$) {
my ($width,$height)=(shift,shift);
my $window = Gtk2::Window->new( "toplevel" );
$window->signal_connect( "destroy", sub { Gtk2->main_quit(); } );
$window->set_default_size($width,$height);
my $vbox = Gtk2::VBox->new( 0, 5 );
$model = Gtk2::ListStore->new(
"Gtk2::Gdk::Pixbuf", #0 pic
"Glib::String", #1 product
"Glib::String", #2 attr
"Gtk2::ListStore" #combo values list
);
#sample_data
#some combo lists
foreach my $d (
[qw(fast medium slow)],
[qw(greay orange black white rainbow)],
[qw(fat with_wholes molded)],
[qw(long short jeans)]
)
{
my $cmodel = Gtk2::ListStore->new('Glib::String');
foreach my $str (#$d) {$cmodel->set($cmodel->append,0,$str);}
push #attr_models,$cmodel;
}
#some pixbufs to play with
my $pixbuf2 = Gtk2::Button->new->render_icon ('gtk-info', 'large-toolbar');
#add some rows
my #data = (
[$pixbuf2,'Shirt',1,$attr_models[0]],
[$pixbuf2,'Pants',0,$attr_models[0]],
[$pixbuf2,'Cheese',2,$attr_models[1]],
[$pixbuf2,'Cola',1,$attr_models[2]],
[$pixbuf2,'Laptop',0,$attr_models[3]]
);
foreach my $st(#data) {
$st->[2]=$st->[3]->get($st->[3]->iter_nth_child(undef,$st->[2]), 0);
$model->set( $model->append,
0, $st->[0],
1, $st->[1],
2, $st->[2],
3, $st->[3],
);
}
#Column0 setup
my $combo_model0 = Gtk2::ListStore->new( 'Gtk2::Gdk::Pixbuf' );
my $renderer_0 = Gtk2::CellRendererPixbuf->new;
my $column_0 = Gtk2::TreeViewColumn->new_with_attributes(
"Pic",
$renderer_0,
pixbuf => col0
);
#Column1 setup
my $renderer_1 = Gtk2::CellRendererText->new;
$renderer_1->set( editable => FALSE );
my $column_1 = Gtk2::TreeViewColumn->new_with_attributes(
"Product",
$renderer_1,
text => col1
);
#Column2 setup
my $renderer_2 = Gtk2::CellRendererCombo->new;
$renderer_2->set(
editable => TRUE,
text_column => 0,
has_entry => FALSE
);
$renderer_2->signal_connect (changed => sub {
my ($renderer, $str, $iter)=#_;
print Dumper (#_) . "\n";
}
);
$renderer_2->signal_connect (edited =>
sub {
my ($renderer, $text_path, $new_text) = #_;
my $combo_model = $renderer->get("model");
$model->set ($model->get_iter_from_string ($text_path), col2, $new_text);
}
);
my $column_2 = Gtk2::TreeViewColumn->new_with_attributes(
"Attr",
$renderer_2,
text => col2,
model => colC
);
# main program starts
$treeview = Gtk2::TreeView->new( $model );
$treeview->get_selection->set_mode ('single');
$treeview->set_rules_hint( TRUE );
$treeview->append_column( $column_0 );
$treeview->append_column( $column_1 );
$treeview->append_column( $column_2 );
my $sw = Gtk2::ScrolledWindow->new( undef, undef );
$sw->set_shadow_type( "etched-in" );
$sw->set_policy( "never", "always" );
$sw->add( $treeview );
$vbox->pack_start( $sw, 1, 1, 0 );
$window->add( $vbox );
$window->show_all;
}
So, looks like there isn't any direct answer for this question.
As a workaround, you may create array of hashes. Each element corresponds to one TreeView's row and have e.g. fields like 'combo_hash' and 'current_index'.
'current_index' is self-explained, 'combo_hash' is array which consists of hashes with some fields like 'text' and e.g. 'index' (or other id).
On CellRendererCombo's 'edited' signal you get current TreeView's index by $treeview->get_selection()->get_selected_rows()->get_indices() (it's simple int), and search for selected in CellRendererCombo's 'text' field through 'combo_hash' array. Don't forget to store finded 'index' to 'current_index'.
This workaround allows non-unique text in different TreeView's rows, but can't handle non-unique text in one CellRendererCombo's ListStore.
Another workaround is to inherite subclass from CellRenderer and embed ComboBox, which provides simple integer index. Looks better and have no limitations by non-unique data, but if array of hashes is unavoidable by design (you need to store lots of other info not visible in TreeView), first workaround should be more relevant.

Gravity Forms Multi Page Losing POST value

I have a complex Gravity Form built, it has 10 pages. I am using fields to build a "string" that I then match to a CPT name to get meta data from to display a selection, based on user choices in the form.
One field I have is not holding its value in POST. I can see it when I select the value on the page, then when I click to next page the value is still there. However, after two pages the value ( and field ) disappear from POST.
This is the function I have put together that builds my product string.
add_filter( 'gform_pre_render_12', 'display_choice_result' );
function display_choice_result( $form ) {
$current_page = GFFormDisplay::get_current_page( $form['id'] );
$html_content = "";
$prod_string = "";
if ( $current_page >= 10 ) {
foreach ( $form['fields'] as &$field ) {
// Check for a class of "product-builder-item" on the field
// I use this as another way to denote what fields to add to string
if ( strpos( $field->cssClass, 'product-builder-item' ) === false ) {
continue;
}
//gather form data to save into html field (Field ID 14 on Form ID 12)
//exclude page break and any hidden fields
if ( $field->id != 14 && $field->type != 'page' ) {
$is_hidden = RGFormsModel::is_field_hidden( $form, $field, array() );
$populated = rgpost( 'input_' . $field->id );
// Make sure the field we are getting the value from is not hidden and has a value
if ( !$is_hidden && $populated !='' ) {
$html_content .= '<li>' . $field->label . ': ' . rgpost( 'input_' . $field->id ) . '</li>';
$prod_string .= rgpost( 'input_' . $field->id );
}
}
}
// Do a bunch of stuff here with the $prod_string variable
// ...
// ...
// ...
}
return $form;
}
Screenshots showing the POST disappearing..The POST field in question is input_22 with a value of 18000
This is one page after I choose from the field
This is two pages after,
Anyone run into this before or have any idea why it would be disappearing?
Thank you.
I was having the same exact issue as you described. I realized that a jQuery function was interfering with Gravity Form process. The jQuery function was set to change a zip code field from type text to tel so the number pad would open up on mobile devices. This is what was causing my issue.

How to add multiple custom fields to a wp_query in a shortcode?

In a shortcode I can limit wp_query results by custom field values.
Example:
[my-shortcode meta_key=my-custom-field meta_value=100,200 meta_compare='IN']
And obviously it's possible to use multiple custom fields in a wp_query like WP_Query#Custom_Field_Parameters
But how can I use multiple custom fields in my shortcode? At the moment I do pass all the shortcode parameters with $atts.
On of a few different solutions might be to use a JSON encoded format for the meta values. Note that this isn't exactly user-friendly, but certainly would accomplish what you want.
You would of course need to generate the json encoded values first and ensure they are in the proper format. One way of doing that is just using PHP's built in functions:
// Set up your array of values, then json_encode them with PHP
$values = array(
array('key' => 'my_key',
'value' => 'my_value',
'operator' => 'IN'
),
array('key' => 'other_key',
'value' => 'other_value',
)
);
echo json_encode($values);
// outputs: [{"key":"my_key","value":"my_value","operator":"IN"},{"key":"other_key","value":"other_value"}]
Example usage in the shortcode:
[my-shortcode meta='[{"key":"my_key","value":"my_value","operator":"IN"},{"key":"other_key","value":"other_value"}]']
Which then you would parse out in your shortcode function, something like so:
function my_shortcode($atts ) {
$meta = $atts['meta'];
// decode it "quietly" so no errors thrown
$meta = #json_decode( $meta );
// check if $meta set in case it wasn't set or json encoded proper
if ( $meta && is_array( $meta ) ) {
foreach($meta AS $m) {
$key = $m->key;
$value = $m->value;
$op = ( ! empty($m->operator) ) ? $m->operator : '';
// put key, value, op into your meta query here....
}
}
}
Alternate Method
Another method would be to cause your shortcode to accept an arbitrary number of them, with matching numerical indexes, like so:
[my-shortcode meta-key1="my_key" meta-value1="my_value" meta-op1="IN
meta-key2="other_key" meta-value2="other_value"]
Then, in your shortcode function, "watch" for these values and glue them up yourself:
function my_shortcode( $atts ) {
foreach( $atts AS $name => $value ) {
if ( stripos($name, 'meta-key') === 0 ) {
$id = str_ireplace('meta-key', '', $name);
$key = $value;
$value = (isset($atts['meta-value' . $id])) ? $atts['meta-value' . $id] : '';
$op = (isset($atts['meta-op' . $id])) ? $atts['meta-op' . $id] : '';
// use $key, $value, and $op as needed in your meta query
}
}
}

Codeigniter 3 get a specific session data by id

Codeigniter 3 session table looks like the following
CREATE TABLE IF NOT EXISTS `ci_sessions` (
`id` varchar(40) NOT NULL,
`ip_address` varchar(45) NOT NULL,
`timestamp` int(10) unsigned DEFAULT 0 NOT NULL,
`data` blob NOT NULL,
KEY `ci_sessions_timestamp` (`timestamp`)
);
I can access my current session by
$this->session
But If I'd like to access a specific session how would I do that.
I can get the session like
$this->db->where('id', 'db256c0b82f8b6ba1e857d807ea613792817157a');
$res = $this->db->get('ci_sessions');
echo $res->row()->data;
I get the following
__ci_last_regenerate|i:1450694483;email|s:18:"amzadfof#gmail.com";user_code|s:7:"AAA1787";loginInId|i:8;users_id|s:11:"00000000002";active|s:1:"1";username|s:13:"amzadmojumder";fname|s:5:"Amzad";lname|s:8:"Mojumder";phone|s:11:"07900642131";title|s:1:"#";created_on|s:19:"2015-12-17 16:31:56";last_login|s:19:"0000-00-00 00:00:00";in_group|s:15:"2,1,3,4,5,6,7,8";
How could I convert this to an php object or array? I have tried to
unserialize($res->row()->data);
Also tried
session_decode($res->row()->data);
none of this worked. Any help will be appreciated.
Old question, yeah but this worked for me.
https://github.com/wikimedia/php-session-serializer
After fetching the session data from database, I just did
$array = PhpSessionSerializer::decode($session);
Firstly, the CodeIgniter sessions table should look a bit more like this:
CREATE TABLE IF NOT EXISTS `ci_sessions` (
session_id varchar(40) DEFAULT '0' NOT NULL,
ip_address varchar(45) DEFAULT '0' NOT NULL,
user_agent varchar(120) NOT NULL,
last_activity int(10) unsigned DEFAULT 0 NOT NULL,
user_data text NOT NULL,
PRIMARY KEY (session_id),
KEY `last_activity_idx` (`last_activity`)
);
You'll also need to edit your config.php to ensure the following are set properly for CI Sessions to use a table for storage
$config['sess_use_database'] = TRUE;
$config['sess_table_name'] = 'ci_sessions';
The other issue you'll face is that you aren't really using sessions how they're supposed to be used. If you want to mimic sessions of another individual through an admin switch or something like that, you're probably best off creating a new session and duplicating the information in your table. If you actually assume the session, you risk breaking it or letting it expire while another user is accessing it. So I would write your own parsing function to duplicate a specific session in the database, like so:
Your session data is broken up like this in your dB:
__ci_last_regenerate|i:1450694483;
email|s:18:"amzadfof#gmail.com";
user_code|s:7:"AAA1787";
loginInId|i:8;
users_id|s:11:"00000000002";
active|s:1:"1";
username|s:13:"amzadmojumder";
fname|s:5:"Amzad";
lname|s:8:"Mojumder";
phone|s:11:"07900642131";
title|s:1:"#";
created_on|s:19:"2015-12-17 16:31:56";
last_login|s:19:"0000-00-00 00:00:00";
in_group|s:15:"2,1,3,4,5,6,7,8";
The basic architecture is as such:
{session_key}|{information type s=string, i=int}:{length}:"{value}";
So we can grab it from the database and parse through it
<?php
duplicateSession( $id_to_duplicate ) {
// Kill any current sessions we're in to prevent conflicts
$this->session->sess_destroy();
// Get the Session we want to duplicate
$this->db->where( 'id', $id_to_duplicate );
$session = $this->db->get( 'ci_sessions' );
$data = $session->row()->data;
// Turn our data into an array so we can parse through it
$data_arr = explode( ';', $data );
// Loop through each of our items to parse it out
foreach( $data_arr as $session_key ) {
// Explode out to separate our key name from our values
$session_key_arr = explode( '|', $session_key );
$key_index = $session_key_arr[0];
// Explode out to parse our values
$session_value_arr = explode( ':', $session_key_arr[1] );
$key_value = $session_value_arr[2];
// Build our new session index
$this->session->set_userdata( $key_index, $key_value );
}
}
?>
I have solved this problem by creating helper function to update session from existing session id.
Reference : https://forum.codeigniter.com/thread-61330-post-322814.html#pid322814
function updateSession( $session_id='' ) {
$ci =& get_instance();
// Kill any current sessions we're in to prevent conflicts
$ci->session->sess_destroy();
// Get the Session we want to duplicate
$ci->db->where( 'id', $session_id );
$session = $ci->db->get( 'ci_sessions' );
$row = $session->row();
if($row){
$session_db_data = $row->data;
$session_data = array(); // array where you put your "BLOB" resolved data
$offset = 0;
while ($offset < strlen($session_db_data))
{
if (!strstr(substr($session_db_data, $offset), "|"))
{
throw new Exception("invalid data, remaining: " . substr($session_db_data, $offset));
}
$pos = strpos($session_db_data, "|", $offset);
$num = $pos - $offset;
$varname = substr($session_db_data, $offset, $num);
$offset += $num + 1;
$data = unserialize(substr($session_db_data, $offset));
$session_data[$varname] = $data;
$offset += strlen(serialize($data));
}
$ci->session->set_userdata($session_data);
}
}

Laravel Restful API - How to create custom query based on multiples params

I am new to Laravel. I have created a Restful API with this route : (with Laravel 5)
Route::get('api/clubs', 'Api\ClubsController#getClubs');
Calling /public/api/clubs will retrieve all clubs
$clubs = Club::all();
With the same route I am trying to filter clubs based on many params :
$filter_lat = Request::get( 'fi_lat' );
$filter_long = Request::get( 'fi_long' );
$filter_distance = Request::get( 'fi_distance' );
$filter_key_word = Request::get( 'fi_key_word' );
$filter_date = Request::get( 'fi_date' );
$filter_city_id = Request::get( 'fi_city_id' );
$filter_order_by = Request::get( 'fi_order_by' );
$filter_offset = Request::get( 'fi_offset' );
$filter_limit = Request::get( 'fi_limit' );
I want to filter my clubs based on those params, but I don't know what is the best way to build the query using Eloquent. I want to be able to run the query even if I have only 1 param. example1 : I want to filter my clubs by city and my query will looks like :
$clubs = Club::where( 'city_id', $filter_city_id )->get();
If I have more params my query will looks like :
$clubs = Club::where( condition 1 )
->where( condition 2 )
->where( condition 3 )
etc ..
->get();
How to build my query this way and put together all conditions ?
if( !empty ( $my_param ) ){
$query += where ( condition .. )
}
then run $query ..
What I don't want to do, is doing 10 "if() tests" and build 10 queries depending on params because this will be really a big code hacking and duplicated query ..
I am open to any suggestions, I want to have an object of clubs as result. Thanks!
It's quite simple, just check that each condition was passed and if it did, add a where clause.
$query = Club::newQuery();
if($my_param) {
$query->where('my_param', $my_param);
}
if($my_param2) {
$query->where('my_param2', $my_param2);
}
$clubs = $query->get();
You should check that the variable is set simply because it's good practice when dealing with user submitted data. If there are some parameters which you need to validate further, be sure to use the validation class.
You can use array inside where() . like this:
User::where(['id' => $id, 'name' => $name, 'etc' => $etc])->get();
:)...