pepiscms/resources/module_template/_admin_controller.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');
/**
* {module_name} admin controller
*
* @author {author}
* @date {date}
* @see AdminCRUDController for the list of the methods you can use in your constructor
* @classTemplateVersion 20181105
*
* @property {model_class_name} ${model_class_name}
*/
class {module_class_name}Admin extends AdminCRUDController
{
/**
* Base path for file uploads
*
* @var String
*/
private $uploads_base_path = './application/cache/tmp/'; // Overwritten by constructor
/**
* Default constructor containing all necessary definitions
*/
public function __construct()
{
parent::__construct();
// Overwriting uploads base path
$this->uploads_base_path = $this->config->item('uploads_path') . '{module_name}/';
// Getting module and model name from class name
$module_name = $this->getModuleName();
$this->load->moduleLanguage($module_name, $module_name);
$this->load->moduleModel($module_name, '{model_class_name}');
$this->setFeedObject($this->{model_class_name})
->setPageTitle($this->lang->line($module_name . '_module_name'))
->setAddNewItemLabel($this->lang->line($module_name . '_add'));
// $this->addActionForIndex(array('link' => module_url() . 'export', 'name' => $this->lang->line($module_name . '_export'), 'icon' => 'pepiscms/theme/img/dialog/actions/action_16.png'));
// if ($this->input->getParam('id')) {
// $this->addActionForEdit(array('link' => module_url('attachments') . 'index/layout-popup/forced_filters-' . DataGrid::encodeFiltersString(array('entry_id' => $this->input->getParam('id'))), 'name' => $this->lang->line($module_name . '_manage_attachments'), 'icon' => 'pepiscms/theme/img/dialog/actions/action_16.png', 'class' => 'popup'));
// }
// $this->setBackToItemsLabel($this->lang->line($module_name . '_back'));
// $this->setTooltipTextForIndex($this->lang->line($module_name . '_index_tip'));
// $this->setTooltipTextForEdit($this->lang->line($module_name.'_edit_tip'));
// Setting crud properties, these are optional. Default true all
$this->setDeletable(true)
->setAddable(true)
->setEditable(true)
->setPreviewable(false)
->setPopupEnabled(false)
->setOrderable(false);
// $this->setExportable(true, function ($resulting_line) {
// // The callback is optional, it is used to filter individual rows before inserting them
// unset($resulting_line['afield_you_want_to_ignore']);
// return $resulting_line;
// });
// $this->setImportable(true, array('name', 'street'), function ($resulting_line, $original_line) {
// // The callback is optional, it is used to filter individual rows before inserting them
// // You can change existing values, add or unset fields
// $resulting_line['name'] = ucfirst($resulting_line['name']);
// $resulting_line['is_displayed_globally'] = 1;
// $resulting_line['is_published'] = 1;
// return $resulting_line;
// });
$this->setMetaOrderField('{label_field_name}', $this->lang->line($module_name . '_{label_field_name}'));
$this->setMetaTitlePattern('{{label_field_name}}'); // Use field names as {field_name}
{image_meta_code_element}
// $this->setMetaImageField('image_path', $this->uploads_base_path); // Using field name and basepath
// $this->setMetaImageField(array($this, '_datagrid_format_image_field')); // Using callback
{description_meta_code_element}
// $this->setMetaDescriptionPattern('{description}'); // Use field names as {field_name}
// $this->setMetaDescriptionPattern(array($this, '_fb_format_meta_description')); // Can use a callback as well
// $this->setMetaDescriptionPattern('{description}', array($this, '_fb_format_meta_description')); // Can use a pattern + callback as well
{order_meta_code_element}
// $this->setOrderable(true, 'item_order');
// $this->setOrderable(true, 'item_order', 'optional_constraint_field_name'); // optional_constraint_field_name is usually the foreign key field
// $this->setStarable(true, 'is_starable', $this->lang->line($module_name . '_is_starable')); // Basic toggle button accessible from grid
// $this->addMetaAction(array($this, '_crud_action_images'), $this->lang->line($module_name . '_images')); // Action link displayed in grid cell
// $this->addMetaAction(array($this, '_crud_action_images'), $this->lang->line($module_name . '_images'), 'heavy_operation'); // Action link displayed in grid cell that triggers heavy operation overlayer
// $this->addActionForIndex(array('title' => $this->lang->line($module_name.'_manage_banners'), 'name' => $this->lang->line($module_name.'_manage_banners'), 'icon' => 'pepiscms/theme/img/dialog/actions/action_16.png', 'link' => module_url().'manage_banners'));
// // Manually restrict access to selected items
// if (!$this->auth->isRoot()) {
// // Display rows that match the user_id parameter
// $this->manuallySetForcedFilters(array('user_id' => $this->auth->getUserId()));
// }
// // Datagrid row format callback
// $this->datagrid->setRowCssClassFormattingFunction(function ($line) {
// if ($line->is_active == 1) {
// return DataGrid::ROW_COLOR_GREEN;
// } else {
// return DataGrid::ROW_COLOR_RED;
// }
// });
// $this->datagrid->setItemsPerPage(300)
// ->datagrid->setDefaultOrder('id', 'DESC')
// ->datagrid->addFilter($this->lang->line($module_name.'_date_from'), 'date', DataGrid::FILTER_DATE, false,
// DataGrid::FILTER_CONDITION_GREATER_OR_EQUAL); // Can also be an associative array
{filters_element}
// If not set, then DefaultFormRenderer is used
// You can even use your own form templates, see views/templates
$this->formbuilder->setRenderer(new FloatingFormRenderer())
->setApplyButtonEnabled(true);
// Formbuilder callbacks
$callbacks = array(
'_fb_callback_after_save' => FormBuilder::CALLBACK_AFTER_SAVE,
'_fb_callback_before_render' => FormBuilder::CALLBACK_BEFORE_RENDER,
'_fb_callback_before_save' => FormBuilder::CALLBACK_BEFORE_SAVE,
'_fb_callback_on_save' => FormBuilder::CALLBACK_ON_SAVE,
'_fb_callback_on_save_failure' => FormBuilder::CALLBACK_ON_SAVE_FAILURE,
'_fb_callback_on_read' => FormBuilder::CALLBACK_ON_READ,
);
// Assigning every single callback
foreach ($callbacks as $callback_method_name => $callback_type) {
// Attaching only when are callable
if (is_callable(array($this, $callback_method_name))) {
$this->formbuilder->setCallback(array($this, $callback_method_name), $callback_type);
}
}
$definition = {definition_output}
// This method is only required when using $this->setTable()
// or the model has not accepted post fields defined
//
// Feel free to comment it out if post accepted fields are defined in model
// $this->getFeedObject()->setAcceptedPostFields(array_keys($definition));
// // Generating form fields for translations
// // Only if the feed object is translateable and the getLocales function exists
// if (($this->getFeedObject() instanceof TranslateableInterface) && is_callable(array($this, 'getLocales'))) {
// // Overwriting the default group
// foreach ($definition as &$field) {
// // Only when there is no group specified
// if (!isset($field['input_group']) || $field['input_group'] == 'default') {
// // Take the default action name
// $field['input_group'] = $module_name . '_add';
// }
// }
//
// // Getting language list
// $locales = $this->getLocales();
// // First language is the default one and is not taken into consideration
// unset($locales[0]);
//
// // Copying fields for each language
// foreach ($locales as $locale) {
// foreach ($this->getFeedObject()->getTranslateableFieldNames() as $translateable_field) {
// $definition[$translateable_field . '_' . $locale] = $definition[$translateable_field];
// $definition[$translateable_field . '_' . $locale]['input_group'] = $locale;
// }
// }
// }
// Here we go!
$this->setDefinition($definition);
}
/**
* Description format callback
*
* @param mixed $content Value of the element
* @param object $line Object representing database row
* @return string resulting text/html
*/
public function _fb_format_meta_description($content, $line)
{
$this->load->helper('text');
$content = strip_tags($content);
return word_limiter($content, 10, '...');
}
/**
* Called after validation, before saving
*
* @param array $data_array associative array made of filtered POST variables
*/
public function _fb_callback_before_save(&$data_array)
{
// // EXAMPLE: Transforming all values to lowercase
// foreach ($data_array as $key => $value) {
// $data_array[$key] = strtolower($data_array[$key]);
// }
{updated_at_code_element}
// Computing element slug if one of the slug fields are present
// List of the fields to be used, if no value is present for a given key
// then the key will be ignored. By default all values of the keys
// specified will be concatenated
$title_field_names = array('name', 'title');
// List of sluggable field names
$sluggable_field_names = array('slug', 'url_slug', 'url_name', 'uri_name');
// Getting form field names
$field_names = $this->formbuilder->getFieldNames();
$slug_field = false;
foreach ($field_names as $field_name) {
if (in_array($field_name, $sluggable_field_names)) {
$slug_field = $field_name;
break; // A single slug field is accepted
}
}
// Only if there is no slug or the slug value is empty
if ($slug_field) {
$this->load->helper('string');
if (!(isset($data_array[$slug_field]) && $data_array[$slug_field])) {
// Attempt to build a slug
$slug = '';
foreach ($title_field_names as $title_field_name) {
// Concatenating all the elements
if (isset($data_array[$title_field_name]) && $data_array[$title_field_name]) {
$slug .= '-' . $data_array[$title_field_name];
}
}
// Slugify
$slug = niceuri($slug);
// Generating pseudo random slug if there was no slug found
if (!$slug) {
$slug = md5(time() . '-some-random-string-34-' . rand(1000, 9999));
}
// Assigning the field
$data_array[$slug_field] = $slug;
} else {
// Slugify anyway
$data_array[$slug_field] = niceuri($data_array[$slug_field]);
}
// TODO check if slug is unique
}
}
/**
* Some logs or statistics maybe?
* @param array $data_array associative array made of filtered POST variables
*/
public function _fb_callback_after_save(&$data_array)
{
$title = $this->getCompiledTitle('', (object)$data_array);
Logger::info('Editing element id:' . $this->formbuilder->getId() . ' (' . $title . ')',
strtoupper(str_replace('Admin', '', __CLASS__)), $this->formbuilder->getId());
}
/**
* Callback function changing the name of the file to SEO friendly
*
* @version: 1.2.3
* @date: 2015-06-11
*
* @param $filename
* @param $base_path
* @param $data
* @param $current_image_field_name
* @return bool
*/
public function _fb_callback_make_filename_seo_friendly(&$filename, $base_path, &$data, $current_image_field_name)
{
// List of the fields to be used, if no value is present for a given key
// then the key will be ignored. By default all values of the keys
// specified will be concatenated
$title_field_names = array('name', 'title', 'label');
$this->load->helper('string');
$path = $base_path . $filename;
$path_parts = pathinfo($path);
// Attempt to build a name
$new_base_filename = '';
foreach ($title_field_names as $title_field_name) {
// Concatenating all the elements
if (isset($data[$title_field_name]) && $data[$title_field_name]) {
$new_base_filename .= '-' . $data[$title_field_name];
}
}
// Making it web safe
if ($new_base_filename) {
$new_base_filename = niceuri($new_base_filename);
}
// This should not be an else statement as niceuri can return empty string sometimes
if (!$new_base_filename) {
$new_base_filename = niceuri($path_parts['filename']);
}
// This should normally never happen, but who knows - this is bulletproof
if (!$new_base_filename) {
$new_base_filename = md5(time() + rand(1000, 9999));
}
$new_base_path = '';
// $new_base_path = date('Y-m-d') . '/'; // Will create directory based on date
// $new_base_path = $new_name_base . '/'; // Will create directory based on the niceuri value
// @mkdir($base_path . $new_base_path); // Do not forget!
// We don't like upper case extensions
$extension = strtolower($path_parts['extension']);
$new_name = $new_base_filename . '.' . $extension;
// Protection against existing files
$i = 2;
while (file_exists($base_path . $new_base_path . $new_name)) {
$new_name = $new_base_filename . '-' . $i . '.' . $extension;
if ($i++ > 50 || strlen($i) > 2) // strlen is a protection against the infinity loop for md5 checksums
{
// This is ridiculous but who knowss
$i = md5(time() + rand(1000, 9999));
}
}
// No need to change filename? Then we are fine
if ($filename == $new_name) {
return true;
}
// Finally here we go!
if (rename($path, $base_path . $new_base_path . $new_name)) {
$data[$current_image_field_name] = $new_base_path . $new_name;
$filename = $new_base_path . $new_name;
return true;
}
return false;
}
/**
* This function is called on delete
* You should remove any external resources such as images here
*
* @param mixed $id
* @param object $item
*/
public function _onDelete($id, $item)
{
// Get the file or image fields out of the definition
$file_fields = array();
$definition = $this->getDefinition();
// Attempt to find fields contain file paths
foreach ($definition as $key => $field) {
if ($field['input_type'] == FormBuilder::IMAGE || $field['input_type'] == FormBuilder::FILE) {
$file_fields[] = isset($field['field']) && $field['field'] ? $field['field'] : $key;
}
}
// Alternative, static, more safe version
//$file_fields = array('path', 'image_path', 'attachment_path', 'pdf_path', 'download_path', 'file_path', 'archive_path', 'banner_path', 'baner_path', 'image', 'pdf', 'download', 'file', 'archive', 'baner', 'baner');
$log_msgs = array();
foreach ($file_fields as $field) {
// Checking if the field is set and nonempty
if (!isset($item->$field) || !trim($item->$field)) {
continue;
}
// Checking whether the file exists
$path = $this->uploads_base_path . trim($item->$field);
if (file_exists($path) && is_file($path)) {
// Trying to delete file
if (@unlink($path)) {
$log_msgs[] = 'unlink ' . $path;
} else {
$log_msgs[] = 'ERROR unlink ' . $path;
}
}
}
// Deleting translations
// // Only if the feed object is translateable and the getLocales function exists
// if (($this->getFeedObject() instanceof Translateable) && is_callable(array($this, 'getLocales'))) {
// // Generating table name (by convention)
// $table_name = $this->getFeedObject()->getTable() . '_translations';
// $this->db->where('object_id', $id)->delete($table_name);
// }
// Logging action
$title = $this->getCompiledTitle('', $item);
Logger::info('Deleting element id:' . $id . ' (' . $title . ') ' . implode(' ', $log_msgs),
strtoupper(str_replace('Admin', '', __CLASS__)), $id);
}
// /**
// * Returns a list of locales
// *
// * This function should probably be moved out of the controller or should act as a proxy
// *
// * @return array
// */
// private function getLocales()
// {
// // First language is the default one and is not taken into consideration
// return array('pl_pl', 'en_us');
// }
//
// /**
// * Generic action with redirect
// */
// public function generic_redirect_action()
// {
// $success = $this->getFeedObject()->doAction();
//
// $this->load->library('User_agent');
// $this->load->library('SimpleSessionMessage');
// if ($success) {
// $this->simplesessionmessage->setFormattingFunction(SimpleSessionMessage::FUNCTION_SUCCESS);
// $this->simplesessionmessage->setMessage('global_header_success');
// }
//
// // Smart redirect
// $this->load->library('User_agent');
// if ($this->agent->referrer()) {
// redirect($this->agent->referrer());
// } else {
// redirect(module_url());
// }
// }
//
// /**
// * Handles import file upload and parsing
// *
// * @param array $data_array
// * @return boolean
// */
// public function _fb_callback_on_import($data_array)
// {
// // Overwrite, add own logic here
// return parent::_fb_callback_on_import($data_array);
// }
//
// /**
// * Link format callback
// *
// * @param mixed $content Value of the element
// * @param object $line Object representing database row
// * @return string resulting href
// */
// public function _crud_action_images($content, $line)
// {
// return module_url('images') . 'index' . ($this->input->getParam('layout') ? '/layout-' .
// $this->input->getParam('layout') : '') . '/forced_filters-' . DataGrid::encodeFiltersString(array('gallery_id' => $line->id));
// }
//
// /**
// * Must populate object
// *
// * @param object $object
// */
// public function _fb_callback_on_read(&$object)
// {
// // If you overwrite this action, you should probably call the model getById action
// // If you want to keep the original getById it is recommended to use before render callback
// $object = $this->formbuilder->getFeedObject()->getById($this->formbuilder->getId());
//
// // There is no object so do not apply translations
// if (!$object) {
// return;
// }
//
// // Only if the feed object is translateable and the getLocales function exists
// if (($this->getFeedObject() instanceof Translateable) && is_callable(array($this, 'getLocales'))) {
// // Getting language list
// $locales = $this->getLocales();
// // First language is the default one and is not taken into consideration
// unset($locales[0]);
//
// // Generating table name (by convention)
// $table_name = $this->getFeedObject()->getTable() . '_translations';
// // Builing an empty structure
// $translations = array();
// // Reading all related translations at once
// $translations_result = $this->db->select('*')->from($table_name)->where('object_id', $this->formbuilder->getId())->get()->result();
//
// // Walking through translations and building multidimentional structure
// foreach ($translations_result as $translation_row) {
// // Create language array if it does not exists
// if (!isset($translations[$translation_row->locale])) {
// $translations[$translation_row->locale] = array();
// }
//
// $translations[$translation_row->locale][$translation_row->field] = $translation_row->content;
// }
//
// // Assigning variables to flat object
// foreach ($locales as $locale) {
// // Walking through translateable fields
// foreach ($this->getFeedObject()->getTranslateableFieldNames() as $translateable_field) {
// $object->{$translateable_field . '_' . $locale} = isset($translations[$locale][$translateable_field]) ? $translations[$locale][$translateable_field] : NULL;
// }
// }
// }
// }
//
// /**
// * Can manipulate data after read, before rendering
// * @param object $object
// */
// public function _fb_callback_before_render(&$object)
// {
// // EXAMPLE: Transforming all values to uppercase
// $attribute_names = array_keys(get_object_vars($object));
// foreach ($attribute_names as $attribute_name) {
// $object->$attribute_name = strtoupper($object->$attribute_name);
// }
// }
//
// /**
// * Must overwrite the save procedure and return true or false
// * @param array $data_array associative array made of filtered POST variables
// * @return bool
// */
// public function _fb_callback_on_save(&$data_array)
// {
// // If you overwrite this action, you should probably call the model saveById action
// // If you want to keep the original saveById it is recommended to use before save callback along with the after save one
// $success = $this->formbuilder->getFeedObject()->saveById($this->formbuilder->getId(), $data_array);
//
// // Skip the rest when it failed to save
// if (!$success) {
// return false;
// }
//
// // Get last entry id
// $id = $this->formbuilder->getId();
// // Form builder assigns ID only after the save callback is executed with success so we need to apply a hack to get the ID out of DB API
// if (!$id) {
// $id = $this->db->insert_id();
// }
//
// // Only if the feed object is translateable and the getLocales function exists
// if (($this->getFeedObject() instanceof Translateable) && is_callable(array($this, 'getLocales'))) {
// // Getting language list
// $locales = $this->getLocales();
// // First language is the default one and is not taken into consideration
// unset($locales[0]);
//
// // Copying fields for each language
// $data_array_translated = array();
// foreach ($locales as $locale) {
// $data_array_translated[$locale] = array();
//
// foreach ($this->getFeedObject()->getTranslateableFieldNames() as $translateable_field) {
// $data_array_translated[$locale][$translateable_field] = isset($data_array[$translateable_field . '_' . $locale]) ? $data_array[$translateable_field . '_' . $locale] : NULL;
// }
// }
//
// // Generating table name (by convention)
// $table_name = $this->getFeedObject()->getTable() . '_translations';
// foreach ($locales as $locale) {
// foreach ($data_array_translated[$locale] as $field => $content) {
// // Check if the entry already exists in the database
// if ($this->db->where('object_id', $id)->where('locale', $locale)->where('field', $field)->count_all_results($table_name) > 0) {
// // Update existing row
// $this->db->where('object_id', $id)->where('locale', $locale)->where('field', $field)->set('content', $content)->update($table_name);
// } else {
// // Insert a new row
// $this->db->set('object_id', $id)->set('locale', $locale)->set('field', $field)->set('content', $content)->insert($table_name);
// }
// }
// }
// }
//
// return $success;
// }
//
// /**
// * Put here your rollback action
// *
// * @param array $data_array associative array made of filtered POST variables
// */
// public function _fb_callback_on_save_failure(&$data_array)
// {
// // Rollback
// }
//
//
// /**
// * Image format callback
// *
// * @param string $content
// * @param object $line
// * @return string
// */
// public function _datagrid_format_image_field($content, $line)
// {
// return $this->uploads_base_path . $line->image_path;
// }
}