<?php
/**
* This file implements the Post Type class.
*
* This file is part of the evoCore framework - {@link http://evocore.net/}
* See also {@link https://github.com/b2evolution/b2evolution}.
*
* @license GNU GPL v2 - {@link http://b2evolution.net/about/gnu-gpl-license}
*
* @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
* Parts of this file are copyright (c)2005-2006 by PROGIDISTRI - {@link http://progidistri.com/}.
*
* @package evocore
*/
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
load_class( '_core/model/dataobjects/_dataobject.class.php', 'DataObject' );
/**
* ItemType Class
*
* @package evocore
*/
class ItemType extends DataObject
{
var $name;
var $description;
var $usage;
var $template_excerpt;
var $template_normal;
var $template_full;
var $template_name;
var $schema = '';
var $add_aggregate_rating = 1;
var $back_instruction = 0;
var $instruction = '';
var $text_template;
var $use_short_title = 'never';
var $use_title = 'required';
var $use_url = 'optional';
var $podcast = 0;
var $use_parent = 'never';
var $use_text = 'optional';
var $allow_html = 1;
var $allow_breaks = 1;
var $allow_attachments = 1;
var $use_excerpt = 'optional';
var $use_title_tag = 'optional';
var $use_meta_desc = 'optional';
var $use_meta_keywds = 'optional';
var $use_tags = 'optional';
var $allow_featured = 1;
var $allow_switchable = 1;
var $use_country = 'never';
var $use_region = 'never';
var $use_sub_region = 'never';
var $use_city = 'never';
var $use_coordinates = 'never';
var $use_comments = 1;
var $comment_form_msg = '';
var $allow_comment_form_msg = 0;
var $allow_closing_comments = 1;
var $allow_disabling_comments = 0;
var $use_comment_expiration = 'optional';
var $perm_level = 'standard';
var $evobar_link_text = NULL;
var $skin_btn_text = NULL;
var $short_title_maxlen = 30;
var $title_maxlen = 100;
var $front_order_title = 10;
var $front_order_short_title = NULL;
var $front_order_instruction = NULL;
var $front_order_attachments = 30;
var $front_order_text = 80;
var $front_order_tags = NULL;
var $front_order_excerpt = NULL;
var $front_order_url = NULL;
var $front_order_location = NULL;
var $front_order_workflow = 50;
/**
* Custom fields
*
* @var array
*/
var $custom_fields = NULL;
/**
* What fields should be updated/inserted/deleted
*
* @var array
*/
var $update_custom_fields = NULL;
var $insert_custom_fields = NULL;
var $delete_custom_fields = NULL;
/**
* Constructor
*
*
* @param table Database row
*/
function __construct( $db_row = NULL )
{
// Call parent constructor:
parent::__construct( 'T_items__type', 'ityp_', 'ityp_ID' );
// Allow inseting specific IDs
$this->allow_ID_insert = true;
if( $db_row != NULL )
{
$this->ID = $db_row->ityp_ID;
$this->name = $db_row->ityp_name;
$this->description = $db_row->ityp_description;
$this->usage = $db_row->ityp_usage;
$this->template_excerpt = isset( $db_row->ityp_template_excerpt ) ? $db_row->ityp_template_excerpt : NULL;
$this->template_normal = isset( $db_row->ityp_template_normal ) ? $db_row->ityp_template_normal : NULL;
$this->template_full = isset( $db_row->ityp_template_full ) ? $db_row->ityp_template_full : NULL;
$this->template_name = $db_row->ityp_template_name;
$this->schema = isset( $db_row->ityp_schema ) ? $db_row->ityp_schema : $this->schema;
$this->add_aggregate_rating = isset( $db_row->ityp_add_aggregate_rating ) ? $db_row->ityp_add_aggregate_rating : $this->add_aggregate_rating;
$this->back_instruction = $db_row->ityp_back_instruction;
$this->instruction = $db_row->ityp_instruction;
$this->text_template = isset( $db_row->ityp_text_template ) ? $db_row->ityp_text_template : $this->text_template;
$this->use_short_title = isset( $db_row->ityp_use_short_title ) ? $db_row->ityp_use_short_title : $this->use_short_title;
$this->use_title = $db_row->ityp_use_title;
$this->use_url = $db_row->ityp_use_url;
$this->podcast = $db_row->ityp_podcast;
$this->use_parent = $db_row->ityp_use_parent;
$this->use_text = $db_row->ityp_use_text;
$this->allow_html = $db_row->ityp_allow_html;
$this->allow_breaks = $db_row->ityp_allow_breaks;
$this->allow_attachments = $db_row->ityp_allow_attachments;
$this->use_excerpt = $db_row->ityp_use_excerpt;
$this->use_title_tag = $db_row->ityp_use_title_tag;
$this->use_meta_desc = $db_row->ityp_use_meta_desc;
$this->use_meta_keywds = $db_row->ityp_use_meta_keywds;
$this->use_tags = $db_row->ityp_use_tags;
$this->allow_featured = $db_row->ityp_allow_featured;
$this->allow_switchable = $db_row->ityp_allow_switchable;
$this->use_country = $db_row->ityp_use_country;
$this->use_region = $db_row->ityp_use_region;
$this->use_sub_region = $db_row->ityp_use_sub_region;
$this->use_city = $db_row->ityp_use_city;
$this->use_coordinates = $db_row->ityp_use_coordinates;
$this->use_comments = $db_row->ityp_use_comments;
$this->comment_form_msg = $db_row->ityp_comment_form_msg;
$this->allow_comment_form_msg = $db_row->ityp_allow_comment_form_msg;
$this->allow_closing_comments = $db_row->ityp_allow_closing_comments;
$this->allow_disabling_comments = $db_row->ityp_allow_disabling_comments;
$this->use_comment_expiration = $db_row->ityp_use_comment_expiration;
$this->perm_level = $db_row->ityp_perm_level;
$this->evobar_link_text = isset( $db_row->ityp_evobar_link_text ) ? $db_row->ityp_evobar_link_text : $this->evobar_link_text;
$this->skin_btn_text = isset( $db_row->ityp_skin_btn_text ) ? $db_row->ityp_skin_btn_text : $this->skin_btn_text;
$this->short_title_maxlen = isset( $db_row->ityp_short_title_maxlen ) ? $db_row->ityp_short_title_maxlen : $this->short_title_maxlen;
$this->title_maxlen = isset( $db_row->ityp_title_maxlen ) ? $db_row->ityp_title_maxlen : $this->title_maxlen;
$this->front_order_title = isset( $db_row->ityp_front_order_title ) ? $db_row->ityp_front_order_title : NULL;
$this->front_order_short_title = isset( $db_row->ityp_front_order_short_title ) ? $db_row->ityp_front_order_short_title : NULL;
$this->front_order_instruction = isset( $db_row->ityp_front_order_instruction ) ? $db_row->ityp_front_order_instruction : NULL;
$this->front_order_attachments = isset( $db_row->ityp_front_order_attachments ) ? $db_row->ityp_front_order_attachments : NULL;
$this->front_order_workflow = isset( $db_row->ityp_front_order_workflow ) ? $db_row->ityp_front_order_workflow : NULL;
$this->front_order_text = isset( $db_row->ityp_front_order_text ) ? $db_row->ityp_front_order_text : NULL;
$this->front_order_tags = isset( $db_row->ityp_front_order_tags ) ? $db_row->ityp_front_order_tags : NULL;
$this->front_order_excerpt = isset( $db_row->ityp_front_order_excerpt ) ? $db_row->ityp_front_order_excerpt : NULL;
$this->front_order_url = isset( $db_row->ityp_front_order_url ) ? $db_row->ityp_front_order_url : NULL;
$this->front_order_location = isset( $db_row->ityp_front_order_location ) ? $db_row->ityp_front_order_location : NULL;
}
}
/**
* Get delete restriction settings
*
* @return array
*/
static function get_delete_restrictions()
{
return array(
array( 'table'=>'T_items__item', 'fk'=>'post_ityp_ID', 'msg'=>T_('%d related items') ), // "Lignes de visit reports"
array( 'table'=>'T_categories', 'fk'=>'cat_ityp_ID', 'msg'=>T_('%d related categories') ),
);
}
/**
* Get delete cascade settings
*
* @return array
*/
static function get_delete_cascades()
{
return array(
array( 'table' => 'T_items__type_coll', 'fk' => 'itc_ityp_ID', 'msg' => T_('%d Post type associations with collections') ),
array( 'table' => 'T_items__type_custom_field', 'fk' => 'itcf_ityp_ID', 'msg' => T_('%d Custom field definitions') ),
array( 'table' => 'T_items__status_type', 'fk' => 'its_ityp_ID', 'msg' => T_('%d Item status associations') )
);
}
/**
* Load data from Request form fields.
*
* @return boolean true if loaded data seems valid.
*/
function load_from_Request()
{
global $admin_url, $current_User;
// Name
param_string_not_empty( 'ityp_name', T_('Please enter a name.') );
$this->set_from_Request( 'name' );
// Description
param( 'ityp_description', 'text' );
$this->set_from_Request( 'description', NULL, true );
// Permission level
param( 'ityp_perm_level', 'string' );
$this->set_from_Request( 'perm_level' );
// Usage
param( 'ityp_usage', 'string' );
$this->set_from_Request( 'usage', NULL, true );
// Template for Excerpt display
param( 'ityp_template_excerpt', 'string' );
$this->set_from_Request( 'template_excerpt', NULL, true );
// Template for Teaser display
param( 'ityp_template_normal', 'string' );
$this->set_from_Request( 'template_normal', NULL, true );
// Template for Full content display
param( 'ityp_template_full', 'string' );
$this->set_from_Request( 'template_full', NULL, true );
// PHP Template name
param( 'ityp_template_name', 'string' );
$this->set_from_Request( 'template_name', NULL, true );
// Schema
param( 'ityp_schema', 'string' );
$this->set_from_Request( 'schema', NULL, true );
// Add aggregateRating
param( 'ityp_add_aggregate_rating', 'integer', 0 );
$this->set_from_Request( 'add_aggregate_rating' );
// New item link in evobar text
param( 'ityp_evobar_link_text', 'string' );
$this->set_from_Request( 'evobar_link_text' );
// New item button in skin text
param( 'ityp_skin_btn_text', 'string' );
$this->set_from_Request( 'skin_btn_text' );
// Show instruction in back-office
param( 'ityp_back_instruction', 'integer' );
$this->set_from_Request( 'back_instruction' );
// Instructions:
param( 'ityp_instruction', 'html', NULL );
param_check_html( 'ityp_instruction', T_('Invalid instruction format.').' '.sprintf( T_('You can loosen this restriction in the <a %s>Group settings</a>.'), 'href='.$admin_url.'?ctrl=groups&action=edit&grp_ID='.$current_User->grp_ID ), '#', 'posting' );
$this->set_from_Request( 'instruction', NULL, true );
// Front-Office Order (Instructions)
param( 'ityp_front_order_instruction', 'integer', NULL );
$this->set_from_Request( 'front_order_instruction' );
// Template:
param( 'ityp_text_template', 'html', NULL );
param_check_html( 'ityp_text_template', T_('Invalid template.') );
$this->set_from_Request( 'text_template', NULL, true );
// Use short title
param( 'ityp_use_short_title', 'string' );
$this->set_from_Request( 'use_short_title' );
// Short title max length
param( 'ityp_short_title_maxlen', 'integer' );
$this->set_from_Request( 'short_title_maxlen' );
// Front-Office Order (Short title)
param( 'ityp_front_order_short_title', 'integer', NULL );
$this->set_from_Request( 'front_order_short_title' );
// Use title
param( 'ityp_use_title', 'string' );
$this->set_from_Request( 'use_title' );
// Title max length
param( 'ityp_title_maxlen', 'integer' );
$this->set_from_Request( 'title_maxlen' );
// Front-Office Order (Title)
param( 'ityp_front_order_title', 'integer', NULL );
$this->set_from_Request( 'front_order_title' );
// Use URL
param( 'ityp_use_url', 'string' );
$this->set_from_Request( 'use_url' );
// Front-Office Order (URL)
param( 'ityp_front_order_url', 'integer', NULL );
$this->set_from_Request( 'front_order_url' );
// Treat as Podcast Media
param( 'ityp_podcast', 'integer', 0 );
$this->set_from_Request( 'podcast' );
// Use Parent ID
param( 'ityp_use_parent', 'string' );
$this->set_from_Request( 'use_parent' );
// Use text
param( 'ityp_use_text', 'string' );
$this->set_from_Request( 'use_text' );
// Front-Office Order (Text)
param( 'ityp_front_order_text', 'integer', NULL );
$this->set_from_Request( 'front_order_text' );
// Allow HTML
param( 'ityp_allow_html', 'integer', 0 );
$this->set_from_Request( 'allow_html' );
// Allow Teaser and Page breaks
param( 'ityp_allow_breaks', 'integer', 0 );
$this->set_from_Request( 'allow_breaks' );
// Allow attachments
param( 'ityp_allow_attachments', 'integer', 0 );
$this->set_from_Request( 'allow_attachments' );
// Front-Office Order (Attachments)
param( 'ityp_front_order_attachments', 'integer', NULL );
$this->set_from_Request( 'front_order_attachments' );
// Front-Office Order (Workflow)
param( 'ityp_front_order_workflow', 'integer', NULL );
$this->set_from_Request( 'front_order_workflow' );
// Use excerpt
param( 'ityp_use_excerpt', 'string' );
$this->set_from_Request( 'use_excerpt' );
// Front-Office Order (Excerpt)
param( 'ityp_front_order_excerpt', 'integer', NULL );
$this->set_from_Request( 'front_order_excerpt' );
// Use title tag
param( 'ityp_use_title_tag', 'string' );
$this->set_from_Request( 'use_title_tag' );
// Use meta description
param( 'ityp_use_meta_desc', 'string' );
$this->set_from_Request( 'use_meta_desc' );
// Use meta keywords
param( 'ityp_use_meta_keywds', 'string' );
$this->set_from_Request( 'use_meta_keywds' );
// Use tags
param( 'ityp_use_tags', 'string' );
$this->set_from_Request( 'use_tags' );
// Front-Office Order (Tags)
param( 'ityp_front_order_tags', 'integer', NULL );
$this->set_from_Request( 'front_order_tags' );
// Allow featured
param( 'ityp_allow_featured', 'integer', 0 );
$this->set_from_Request( 'allow_featured' );
// Allow switchable
param( 'ityp_allow_switchable', 'integer', 0 );
$this->set_from_Request( 'allow_switchable' );
// Use country, region, sub-region, city:
$use_country = param( 'ityp_use_country', 'string', 'never' );
$use_region = param( 'ityp_use_region', 'string', 'never' );
$use_sub_region = param( 'ityp_use_sub_region', 'string', 'never' );
$use_city = param( 'ityp_use_city', 'string', 'never' );
if( $use_city == 'required' )
{ // If city is required - all location fields also are required
$use_country = $use_region = $use_sub_region = 'required';
}
else if( $use_sub_region == 'required' )
{ // If subregion is required - country & region fields also are required
$use_country = $use_region = 'required';
}
else if( $use_region == 'required' )
{ // If region is required - country field also is required
$use_country = 'required';
}
$this->set( 'use_country', $use_country );
$this->set( 'use_region', $use_region );
$this->set( 'use_sub_region', $use_sub_region );
$this->set( 'use_city', $use_city );
// Use coordinates
param( 'ityp_use_coordinates', 'string' );
$this->set_from_Request( 'use_coordinates' );
// Front-Office Order (Location:Country/Region/Sub-region/City)
param( 'ityp_front_order_location', 'integer', NULL );
$this->set_from_Request( 'front_order_location' );
// Use comments
param( 'ityp_use_comments', 'integer', 0 );
$this->set_from_Request( 'use_comments' );
// Message before comment form:
param( 'ityp_comment_form_msg', 'text' );
$this->set_from_Request( 'comment_form_msg', NULL, true );
// Allow custom message for each post
param( 'ityp_allow_comment_form_msg', 'integer', 0 );
$this->set_from_Request( 'allow_comment_form_msg' );
// Allow closing comments
param( 'ityp_allow_closing_comments', 'integer', 0 );
$this->set_from_Request( 'allow_closing_comments' );
// Allow disabling comments
param( 'ityp_allow_disabling_comments', 'integer', 0 );
$this->set_from_Request( 'allow_disabling_comments' );
// Use comment expiration
param( 'ityp_use_comment_expiration', 'string' );
$this->set_from_Request( 'use_comment_expiration' );
// Load custom fields from request
$this->load_custom_fields_from_Request();
return ! param_errors_detected();
}
/**
* Load custom fields from request
*/
function load_custom_fields_from_Request()
{
global $Messages;
// Initialize the arrays
$this->update_custom_fields = array();
$this->insert_custom_fields = array();
$this->delete_custom_fields = trim( param( 'deleted_custom_fields', 'string', '' ), ', ' );
$this->delete_custom_fields = empty( $this->delete_custom_fields ) ? array() : explode( ',', $this->delete_custom_fields );
// Field names array is used to check the diplicates
$field_names = array();
// Get previous computed custom fields:
$old_computed_custom_fields = $this->get_custom_fields( 'computed' );
// Empty and Initialize the custom fields from POST data
$this->custom_fields = array();
$empty_title_error = false; // use this to display empty title fields error message only ones
$custom_field_count = param( 'count_custom_fields', 'integer', 0 ); // all custom fields count ( contains even deleted fields )
if( empty( $custom_field_count ) )
{ // No custom fields to insert/update:
return;
}
// Decode data of all custom fields which were posted as single JSON encoded hidden input by JavaScript:
$custom_fields_data = json_decode( param( 'custom_fields_data', 'string' ) );
set_param( 'custom_fields_data', $custom_fields_data );
$inputs = array(
'ID' => '/^[a-z0-9\-_]+$/',
'new' => array( 'integer', 0 ),
'label' => 'string',
'name' => '/^[a-z0-9\-_]+$/',
'schema_prop' => 'string',
'type' => 'string',
'order' => 'integer',
'note' => 'string',
'required' => array( 'integer', 0 ),
'meta' => array( 'integer', 0 ),
'public' => array( 'integer', 0 ),
'format' => 'string',
'formula' => 'string',
'disp_condition' => 'string',
'header_class' => 'string',
'cell_class' => 'string',
'link' => array( 'string', 'nolink' ),
'link_nofollow' => 'integer',
'link_class' => 'string',
'line_highlight' => array( 'string', 'never' ),
'green_highlight' => array( 'string', 'never' ),
'red_highlight' => array( 'string', 'never' ),
'description' => 'html',
'merge' => array( 'integer', 0 ),
);
// Flag to inform user once about changed formula:
$formula_was_changed = false;
for( $i = 1 ; $i <= $custom_field_count; $i++ )
{
$custom_field_data = array();
foreach( $inputs as $input_name => $input_data )
{
// Get input data:
$input_type = is_array( $input_data ) ? $input_data[0] : $input_data;
$input_default_value = is_array( $input_data ) ? $input_data[1] : NULL;
if( isset( $custom_fields_data->{$input_name.$i} ) )
{
if( $input_type == 'string' &&
$input_default_value !== NULL &&
$custom_fields_data->{$input_name.$i} === '' )
{ // Use default value for empty string:
$input_value = $input_default_value;
}
else
{ // Use submitted value:
$input_value = $custom_fields_data->{$input_name.$i};
}
}
else
{ // Use default value:
$input_value = $input_default_value;
}
if( $input_value !== $input_default_value )
{ // Format input value to requested type only when it is not default value:
if( substr( $input_type, 0, 1 ) == '/' )
{ // Check value by regexp:
if( ! empty( $input_value ) && ! preg_match( $input_type, $input_value ) )
{ // Don't allow wrong value:
bad_request_die( sprintf( T_('Illegal value received for parameter «%s»!'), $input_name ) );
}
$input_type = 'string';
}
$input_value = param_format( $input_value, $input_type );
}
switch( $input_name )
{
case 'ID':
$custom_field_ID = $input_value;
break;
case 'new':
$custom_field_is_new = $input_value;
break;
default:
$custom_field_data[ $input_name ] = $input_value;
break;
}
}
// Note: this param contains ID of existing custom field from DB
// or random value like d63d5d53-df3d-5299-8c85-35f69b77 for new creating field:
if( empty( $custom_field_ID ) || in_array( $custom_field_ID, $this->delete_custom_fields ) )
{ // This field was deleted, don't neeed to update
continue;
}
// Add each new/existing custom field in this array
// in order to see all them on the form when post type is not updated because some errors
$this->custom_fields[] = array(
'temp_i' => $i, // Used only on submit form to know the number of the field on the form
'ID' => $custom_field_ID,
'ityp_ID' => $this->ID,
) + $custom_field_data;
if( empty( $custom_field_data['label'] ) )
{ // Field title can't be emtpy
if( ! $empty_title_error )
{ // This message was not displayed yet
$Messages->add( T_('Custom field titles can\'t be empty!') );
$empty_title_error = true;
}
}
elseif( empty( $custom_field_data['name'] ) )
{ // Field identical name can't be emtpy
$Messages->add( sprintf( T_('Please enter name for custom field "%s"'), $custom_field_data['label'] ) );
}
elseif( in_array( $custom_field_data['name'], $field_names ) )
{ // Field name must be identical
$Messages->add( sprintf( T_('The field name "%s" is used more than once. Each field name must be unique.'), $custom_field_data['name'] ) );
}
else
{
$field_names[] = $custom_field_data['name'];
}
// Checks for computed custom fields:
if( $custom_field_data['type'] == 'computed' )
{
if( $custom_field_data['formula'] === '' )
{ // Formula must be not empty:
$Messages->add( sprintf( TB_('Please enter formula for computed custom field "%s".'), $custom_field_data['label'] ) );
}
if( ! $formula_was_changed &&
! $custom_field_is_new &&
isset( $old_computed_custom_fields[ $custom_field_data['name'] ] ) &&
$old_computed_custom_fields[ $custom_field_data['name'] ]['formula'] != $custom_field_data['formula'] )
{ // Inform once user about changed formula:
$Messages->add( TB_('You changed one or several formulas. All posts need to be re-saved to update the results of these formulas.'), 'warning' );
$formula_was_changed = true;
}
}
if( $custom_field_is_new )
{ // Insert custom field
$this->insert_custom_fields[ $custom_field_ID ] = $custom_field_data;
}
else
{ // Update custom field
$this->update_custom_fields[ $custom_field_ID ] = $custom_field_data;
}
}
// Check formulas of computed fields:
$custom_fields = $this->get_custom_fields();
foreach( $custom_fields as $custom_field )
{
if( $custom_field['type'] != 'computed' )
{ // Skip not computed field:
continue;
}
$formula_has_wrong_field = false;
if( preg_match_all( '#\$(.+?)\$#', $custom_field['formula'], $formula_fields ) )
{ // If formula has at least one field:
foreach( $formula_fields[1] as $formula_field )
{
if( ! isset( $custom_fields[ $formula_field ] ) )
{ // Not found field:
$Messages->add( sprintf( TB_('The field name %s is not recognized (in the formula %s of the field "%s".'),
'<code>'.$formula_field.'</code>',
'<code>'.$custom_field['formula'].'</code>',
$custom_field['label']
), 'warning' );
$formula_has_wrong_field = true;
}
elseif( ! in_array( $custom_fields[ $formula_field ]['type'], array( 'double', 'computed' ) ) )
{ // Field with wrong type is used in formula:
$Messages->add( sprintf( TB_('Only numeric or computed fields can be used in formulas. Please remove the field %s from the formula %s of the field "%s".'),
'<code>'.$formula_field.'</code>',
'<code>'.$custom_field['formula'].'</code>',
$custom_field['label']
), 'warning' );
$formula_has_wrong_field = true;
}
}
}
if( $formula_uses_function = preg_match( '#[a-z0-9_]+\s*\(.*?\)#i', $custom_field['formula'] ) )
{ // Don't allow to use functions in formula:
$Messages->add( sprintf( T_('Forbidden to use functions in formula, please fix %s of the field "%s".'),
'<code>'.$custom_field['formula'].'</code>',
$custom_field['label']
), 'warning' );
}
if( ! $formula_has_wrong_field &&
! $formula_uses_function &&
$custom_field['formula'] !== '' )
{ // Check for correct formula:
$test_formula = preg_replace( '#\$(.+?)\$#', '1', $custom_field['formula'] );
try
{ // Compute value:
ob_start();
$test_value = eval( "return $test_formula;" );
$formula_code_output = ob_get_clean();
if( ( $formula_code_output !== '' && $formula_code_output !== false ) ||
! is_numeric( $test_value ) )
{ // If output buffer contains some text it means there is some error;
// Don't allow to use not numeric value for the "computed" custom field:
$test_value = NULL;
}
}
catch( Error $e )
{ // Set NULL value for wrong formula:
$test_value = NULL;
}
catch( ParseError $e )
{ // Set NULL value for wrong formula:
$test_value = NULL;
}
if( $test_value === NULL )
{ // Display warning when formula cannot be executed properly:
$Messages->add( sprintf( TB_('Please check formula %s of the field "%s" because it cannot be evaluated properly.'),
'<code>'.$custom_field['formula'].'</code>',
$custom_field['label']
), 'warning' );
}
}
}
}
/**
* Get the name of the ItemType
* @return string
*/
function get_name()
{
return $this->name;
}
/**
* Insert object into DB based on previously recorded changes.
*/
function dbinsert()
{
global $DB;
$DB->begin();
if( parent::dbinsert() )
{
global $Collection, $Blog;
// Update/Insert/Delete custom fields:
$this->dbsave_custom_fields();
if( ! empty( $Blog ) )
{ // Enable this item type only for selected Blog:
$DB->query( 'INSERT INTO T_items__type_coll
( itc_ityp_ID, itc_coll_ID )
VALUES ( '.$this->ID.', '.$Blog->ID.' )' );
}
}
else
{
$DB->rollback();
return false;
}
$DB->commit();
return true;
}
/**
* Update the DB based on previously recorded changes
*/
function dbupdate()
{
global $DB;
$DB->begin();
parent::dbupdate();
// Update/Insert/Delete custom fields
$this->dbsave_custom_fields();
$DB->commit();
// BLOCK CACHE INVALIDATION:
BlockCache::invalidate_key( 'item_type_'.$this->ID, 1 ); // Item Type has changed (useful for compare widget which needs to check several item_IDs, including from different collections)
return true;
}
/**
* Update the DB based on previously recorded changes
*/
function dbdelete()
{
global $DB;
$DB->begin();
$item_ID = $this->ID;
if( parent::dbdelete() )
{
// Delete all custom fields of this post type
$DB->query( 'DELETE FROM T_items__type_custom_field
WHERE itcf_ityp_ID = '.$item_ID );
}
$DB->commit();
}
/**
* Update/Insert/Delete custom fields
*/
function dbsave_custom_fields()
{
global $DB;
if( ! empty( $this->delete_custom_fields ) )
{ // Delete custom fields:
$sql_data = array();
foreach( $this->delete_custom_fields as $itcf_ID )
{
$sql_data[] = '( itcf_ityp_ID = '.$DB->quote( $this->ID ).' AND itcf_ID = '.$DB->quote( $itcf_ID ).' )';
}
$DB->query( 'DELETE FROM T_items__type_custom_field
WHERE '.implode( ' OR ', $sql_data ) );
}
if( ! empty( $this->insert_custom_fields ) )
{ // Insert new custom fields:
$sql_data = array();
foreach( $this->insert_custom_fields as $itcf_ID => $custom_field )
{
$sql_data[] = '( '.$DB->quote( $this->ID ).', '
.$DB->quote( $custom_field['label'] ).', '
.$DB->quote( $custom_field['name'] ).', '
.$DB->quote( $custom_field['schema_prop'] ).', '
.$DB->quote( $custom_field['type'] ).', '
.( empty( $custom_field['order'] ) ? 'NULL' : $DB->quote( $custom_field['order'] ) ).', '
.( empty( $custom_field['note'] ) ? 'NULL' : $DB->quote( $custom_field['note'] ) ).', '
.$DB->quote( $custom_field['required'] ).', '
.$DB->quote( $custom_field['meta'] ).', '
.$DB->quote( $custom_field['public'] ).', '
.$DB->quote( $custom_field['format'] ).', '
.$DB->quote( $custom_field['formula'] ).', '
.$DB->quote( $custom_field['disp_condition'] ).', '
.$DB->quote( $custom_field['header_class'] ).', '
.$DB->quote( $custom_field['cell_class'] ).', '
.$DB->quote( $custom_field['link'] ).', '
.$DB->quote( $custom_field['link_nofollow'] ).', '
.$DB->quote( $custom_field['link_class'] ).', '
.$DB->quote( $custom_field['line_highlight'] ).', '
.$DB->quote( $custom_field['green_highlight'] ).', '
.$DB->quote( $custom_field['red_highlight'] ).', '
.( empty( $custom_field['description'] ) ? 'NULL' : $DB->quote( $custom_field['description'] ) ).', '
.$DB->quote( $custom_field['merge'] ).' )';
}
$DB->query( 'INSERT INTO T_items__type_custom_field ( itcf_ityp_ID, itcf_label, itcf_name, itcf_schema_prop, itcf_type, itcf_order, itcf_note, itcf_required, itcf_meta, itcf_public, itcf_format, itcf_formula, itcf_disp_condition, itcf_header_class, itcf_cell_class, itcf_link, itcf_link_nofollow, itcf_link_class, itcf_line_highlight, itcf_green_highlight, itcf_red_highlight, itcf_description, itcf_merge )
VALUES '.implode( ', ', $sql_data ) );
}
if( ! empty( $this->update_custom_fields ) )
{ // Update custom fields:
unset( $this->custom_fields );
$old_custom_fields = $this->get_custom_fields( 'all', 'ID' );
foreach( $this->update_custom_fields as $itcf_ID => $custom_field )
{
$DB->query( 'UPDATE T_items__type_custom_field
SET
itcf_label = '.$DB->quote( $custom_field['label'] ).',
itcf_name = '.$DB->quote( $custom_field['name'] ).',
itcf_schema_prop = '.$DB->quote( $custom_field['schema_prop'] ).',
itcf_order = '.( empty( $custom_field['order'] ) ? 'NULL' : $DB->quote( $custom_field['order'] ) ).',
itcf_note = '.( empty( $custom_field['note'] ) ? 'NULL' : $DB->quote( $custom_field['note'] ) ).',
itcf_required = '.$DB->quote( $custom_field['required'] ).',
itcf_meta = '.$DB->quote( $custom_field['meta'] ).',
itcf_public = '.$DB->quote( $custom_field['public'] ).',
itcf_format = '.$DB->quote( $custom_field['format'] ).',
itcf_formula = '.$DB->quote( $custom_field['formula'] ).',
itcf_cell_class = '.$DB->quote( $custom_field['cell_class'] ).',
itcf_disp_condition = '.$DB->quote( $custom_field['disp_condition'] ).',
itcf_header_class = '.$DB->quote( $custom_field['header_class'] ).',
itcf_link = '.$DB->quote( $custom_field['link'] ).',
itcf_link_nofollow = '.$DB->quote( $custom_field['link_nofollow'] ).',
itcf_link_class = '.$DB->quote( $custom_field['link_class'] ).',
itcf_line_highlight = '.$DB->quote( $custom_field['line_highlight'] ).',
itcf_green_highlight = '.$DB->quote( $custom_field['green_highlight'] ).',
itcf_red_highlight = '.$DB->quote( $custom_field['red_highlight'] ).',
itcf_description = '.( empty( $custom_field['description'] ) ? 'NULL' : $DB->quote( $custom_field['description'] ) ).',
itcf_merge = '.$DB->quote( $custom_field['merge'] ).'
WHERE itcf_ityp_ID = '.$DB->quote( $this->ID ).'
AND itcf_ID = '.$DB->quote( $itcf_ID ).'
AND itcf_type = '.$DB->quote( $custom_field['type'] ) );
if( isset( $old_custom_fields[ $itcf_ID ] ) &&
$this->ID > 0 &&
$custom_field['name'] != $old_custom_fields[ $itcf_ID ]['name'] )
{ // Update item setting names of custom field to use new field name:
$DB->query( 'UPDATE T_items__item_custom_field
INNER JOIN T_items__item ON post_ID = icfv_item_ID AND post_ityp_ID = '.$DB->quote( $this->ID ).'
SET icfv_itcf_name = '.$DB->quote( $custom_field['name'] ).'
WHERE icfv_itcf_name = '.$DB->quote( $old_custom_fields[ $itcf_ID ]['name'] ) );
}
}
}
}
/**
* Check if this post type is used for intro posts
*
* @return boolean
*/
function is_intro()
{
return in_array( $this->usage, array( 'intro-front', 'intro-main', 'intro-cat', 'intro-tag', 'intro-sub', 'intro-all' ) );
}
/**
* Returns array, which determinate what post types are defaults of the blogs
*
* @return array ( key => Blog ID, value => ItemType ID )
*/
static function get_default_ids()
{
global $DB;
// Get default value of blog setting "default_post_type"
load_class( 'collections/model/_collsettings.class.php', 'CollectionSettings' );
$CollectionSettings = new CollectionSettings();
$item_types['default'] = $CollectionSettings->get_default( 'default_post_type' );
// Get default post type of each blog
$SQL = new SQL();
$SQL->SELECT( 'cset_coll_ID, cset_value' );
$SQL->FROM( 'T_coll_settings' );
$SQL->WHERE( 'cset_name = "default_post_type"' );
$item_types += $DB->get_assoc( $SQL->get() );
return $item_types;
}
/**
* Get the custom fields
*
* @param string Type of custom field: 'all', 'varchar', 'double', 'text', 'html', 'url', 'image', 'computed', 'separator'. Use comma separator to get several types
* @param string Field name that is used as key of array: 'ID', 'ityp_ID', 'label', 'name', 'type', 'order', 'public'
* @return array Custom fields
*/
function get_custom_fields( $type = 'all', $array_key = 'name' )
{
if( ! isset( $this->custom_fields ) )
{ // Initialize an array only first time
if( empty( $this->ID ) )
{ // Set an empty array for new creating post type
$this->custom_fields = array();
}
else
{ // Get the custom fields from DB
global $DB;
$SQL = new SQL( 'Load all custom fields definitions of Item Type #'.$this->ID );
$SQL->SELECT( '*' );
$SQL->FROM( 'T_items__type_custom_field' );
$SQL->WHERE( 'itcf_ityp_ID = '.$DB->quote( $this->ID ) );
$SQL->ORDER_BY( 'itcf_order, itcf_ID' );
$custom_fields = $DB->get_results( $SQL, ARRAY_A );
$this->custom_fields = array();
foreach( $custom_fields as $c => $custom_field )
{
$this->custom_fields[ $c ] = array();
foreach( $custom_field as $custom_field_key => $custom_field_value )
{
$this->custom_fields[ $c ][ substr( $custom_field_key, 5 ) ] = $custom_field_value;
}
}
}
}
$custom_fields = array();
foreach( $this->custom_fields as $custom_field )
{
if( $type == 'all' || strpos( $type, $custom_field['type'] ) !== false )
{
switch( $array_key )
{
case 'name':
// Use field 'name' as key of array
if( empty( $custom_field['name'] ) )
{ // Name can be empty when we are saving it with empty name and page is displayed with error messages
$field_index = $custom_field['ID'];
}
else
{ // Get field index from name
$field_index = preg_replace( '/\s+/', '_', strtolower( trim( $custom_field['name'] ) ) );
}
break;
default:
// Set an array key from other field, or use 'ID' on invalid field name
$field_index = isset( $custom_field[ $array_key ] ) ? $custom_field[ $array_key ] : $custom_field['ID'];
break;
}
$custom_fields[ $field_index ] = $custom_field;
}
}
return $custom_fields;
}
/**
* Get associated post status
*
* @return array IDs of associated post status
*/
function get_applicable_post_status()
{
global $DB;
$sql = 'SELECT its_pst_ID FROM T_items__status_type WHERE its_ityp_ID = '.$this->ID;
$item_status_array = $DB->get_col( $sql );
$item_status_array = array_map( 'intval', $item_status_array );
return $item_status_array;
}
/**
* Get post status not associated with current item type
*
* @return array IDs of post status not valid for current item type
*/
function get_ignored_post_status( )
{
global $DB;
$sql = 'SELECT pst_ID FROM T_items__status WHERE pst_ID NOT IN ( SELECT its_pst_ID FROM T_items__status_type WHERE its_ityp_ID = '.$this->ID.' )';
/*
$sql = 'SELECT pst_ID
FROM T_items__status
JOIN T_items__type
LEFT JOIN T_items__status_type ON its_ityp_ID = ityp_ID AND its_pst_ID = pst_ID
WHERE ityp_ID = '.$this->ID.' AND its_pst_ID IS NULL';
*/
$item_status_array = $DB->get_col( $sql );
$item_status_array = array_map( 'intval', $item_status_array );
return $item_status_array;
}
/**
* Update item statuses associated with this item type
*/
function update_item_statuses_from_Request()
{
global $DB;
$allowed_values = array();
$remove_values = array();
// Item Types
$item_status_IDs = param( 'item_status_IDs', 'string', true );
$item_status_IDs = explode( ',', $item_status_IDs );
foreach( $item_status_IDs as $loop_status_ID )
{
$loop_status_ID = intval( $loop_status_ID );
$item_status = param( 'status_'.$loop_status_ID, 'integer', 0 );
if( $item_status )
{
$allowed_values[] = "( $this->ID, $loop_status_ID )";
}
else
{
$remove_values[] = $loop_status_ID;
}
}
if( $allowed_values )
{
$DB->query( 'REPLACE INTO T_items__status_type( its_ityp_ID, its_pst_ID )
VALUES '.implode( ', ', $allowed_values ) );
}
if( $remove_values )
{
$DB->query( 'DELETE FROM T_items__status_type
WHERE its_ityp_ID = '.$this->ID.'
AND its_pst_ID IN ('.implode( ',', $remove_values ).')' );
}
}
/**
* Check if this Item Type is enabled for requested collection
*
* @param integer Collection ID
* @return boolean
*/
function is_enabled( $coll_ID )
{
if( empty( $this->ID ) )
{ // Item Type is not inserted in DB yet:
return false;
}
if( ! isset( $this->enabled_colls ) )
{ // Load into cache where this Item Type is enabled for all collections:
global $DB;
$SQL = new SQL( 'Load all collections IDs where Item Type #'.$this->ID.' is enabled' );
$SQL->SELECT( 'itc_coll_ID' );
$SQL->FROM( 'T_items__type_coll' );
$SQL->WHERE( 'itc_ityp_ID = '.$this->ID );
$this->enabled_colls = $DB->get_col( $SQL );
}
return in_array( $coll_ID, $this->enabled_colls );
}
/**
* Get item denomination
*
* @param string Position where denomination will be used, can be one of the following: 'evobar_new', 'inskin_new_btn', 'title_new', 'title_update'
* @param string Default denomination, e.g. when no current collection
* @return string Item denomination
*/
function get_item_denomination( $position = 'evobar_new', $default_denomination = NULL )
{
switch( $position )
{
case 'evobar_new':
if( ! empty( $this->evobar_link_text ) )
{
return $this->evobar_link_text;
}
break;
case 'inskin_new_btn':
if( ! empty( $this->skin_btn_text ) )
{
return $this->skin_btn_text;
}
break;
}
global $Collection, $Blog;
if( ! empty( $Blog ) )
{
return $Blog->get_item_denomination( $position );
}
return $default_denomination;
}
}
?>