/** * formats the posted data for insertion into the database * @param mixed thie elements posted form data * @param array posted form data */ function storeDatabaseFormat($val, $data) { if ($this->getGroup()->canRepeat()) { $str = ''; foreach ($val as $v) { $str .= $v[0] . GROUPSPLITTER; } $str = FabrikString::rtrimword($str, GROUPSPLITTER); return $str; } else { //if sent via inline edit val is string already return is_array($val) ? $val[0] : $val; } }
/** * Fabrik Search method * * The sql must return the following fields that are * used in a common display routine: href, title, section, created, text, * browsernav * @param string Target search string * @param string mathcing option, exact|any|all * @param string ordering option, newest|oldest|popular|alpha|category * @param mixed An array if restricted to areas, null if search all */ function onDoContentSearch($text, $phrase = '', $ordering = '', $areas = null) { if (defined('COM_FABRIK_SEARCH_RUN')) { return; } define('COM_FABRIK_SEARCH_RUN', true); JModel::addIncludePath(COM_FABRIK_FRONTEND . DS . 'models', 'FabrikFEModel'); $user = JFactory::getUser(); $db = FabrikWorker::getDbo(true); require_once JPATH_SITE . DS . 'components' . DS . 'com_content' . DS . 'helpers' . DS . 'route.php'; // load plugin params info $limit = $this->params->def('search_limit', 50); $text = trim($text); if ($text == '') { return array(); } switch ($ordering) { case 'oldest': $order = 'a.created ASC'; break; case 'popular': $order = 'a.hits DESC'; break; case 'alpha': $order = 'a.title ASC'; break; case 'category': $order = 'b.title ASC, a.title ASC'; $morder = 'a.title ASC'; break; case 'newest': default: $order = 'a.created DESC'; break; } //get all tables with search on $query = $db->getQuery(true); $query->select('id')->from('#__{package}_lists')->where('published = 1'); $db->setQuery($query); $list = array(); $ids = $db->loadColumn(); if ($db->getErrorNum() != 0) { jexit('search:' . $db->getErrorMsg()); } $section = $this->params->get('search_section_heading'); $urls = array(); //$$$ rob remove previous search results? JRequest::setVar('resetfilters', 1); //ensure search doesnt go over memory limits $memory = (int) FabrikString::rtrimword(ini_get('memory_limit'), 'M') * 1000000; $usage = array(); $memSafety = 0; $listModel = JModel::getInstance('list', 'FabrikFEModel'); $app = JFactory::getApplication(); foreach ($ids as $id) { // unset enough stuff in the table model to allow for correct query to be run $listModel->reset(); /// $$$ geros - http://fabrikar.com/forums/showthread.php?t=21134&page=2 $key = 'com_fabrik.list' . $id . '.filter.searchall'; $app->setUserState($key, null); unset($table); unset($elementModel); unset($params); unset($query); unset($allrows); $used = memory_get_usage(); $usage[] = memory_get_usage(); if (count($usage) > 2) { $diff = $usage[count($usage) - 1] - $usage[count($usage) - 2]; if ($diff + $usage[count($usage) - 1] > $memory - $memSafety) { JError::raiseNotice(500, 'Some records were not searched due to memory limitations'); break; } } // $$$rob set this to current table //otherwise the fabrik_list_filter_all var is not used JRequest::setVar('listid', $id); $listModel->setId($id); $filterModel = $listModel->getFilterModel(); $requestKey = $filterModel->getSearchAllRequestKey(); //set the request variable that fabrik uses to search all records JRequest::setVar($requestKey, $text, 'post'); $table = $listModel->getTable(true); $fabrikDb = $listModel->getDb(); $params = $listModel->getParams(); //test for swap too boolean mode $mode = JRequest::getVar('searchphraseall', 'all'); //$params->set('search-mode-advanced', true); $params->set('search-mode-advanced', $mode); //the table shouldn't be included in the search results //or we have reached the max number of records to show. if (!$params->get('search_use') || $limit <= 0) { continue; } //set the table search mode to OR - this will search ALL fields with the search term $params->set('search-mode', 'OR'); $allrows = $listModel->getData(); // $$$ rob -moved inside loop as dup records from joined data aren't all added to search results //$limit = $limit - count( $allrows ); $elementModel = $listModel->getFormModel()->getElement($params->get('search_description', $table->label), true); $descname = is_object($elementModel) ? $elementModel->getFullName(false, true) : ''; $elementModel = $listModel->getFormModel()->getElement($params->get('search_title', 0), true); $title = is_object($elementModel) ? $elementModel->getFullName(false, true) : ''; $aAllowedList = array(); $pk = $table->db_primary_key; foreach ($allrows as $group) { foreach ($group as $oData) { $pkval = $oData->__pk_val; if ($app->isAdmin()) { $href = $oData->fabrik_edit_url; } else { $href = $oData->fabrik_view_url; } if (!in_array($href, $urls)) { $limit--; $urls[] = $href; $o = new stdClass(); if (isset($oData->{$title})) { $o->title = $table->label . ' : ' . $oData->{$title}; } else { $o->title = $table->label; } $o->_pkey = $table->db_primary_key; $o->section = $section; $o->href = $href; $o->created = ''; $o->browsernav = 2; if (isset($oData->{$descname})) { $o->text = $oData->{$descname}; } else { $o->text = ''; } $o->title = strip_tags($o->title); $aAllowedList[] = $o; } } $list[] = $aAllowedList; } } $allList = array(); foreach ($list as $li) { if (is_array($li) && !empty($li)) { $allList = array_merge($allList, $li); } } return $allList; }
/** * draws the form element * @param int repeat group counter * @return string returns element html */ function render($data, $repeatCounter = 0) { $name = $this->getHTMLName($repeatCounter); $id = $this->getHTMLId($repeatCounter); $element = $this->getElement(); $params =& $this->getParams(); $str = "<div class=\"fabrikSubElementContainer\" id=\"{$id}\">"; $arVals = $this->getSubOptionValues(); $arTxt = $this->getSubOptionLabels(); $options_per_row = intval($params->get('ck_options_per_row', 0)); // 0 for one line $selected = $this->getValue($data, $repeatCounter); $aRoValues = array(); if ($options_per_row > 0) { $percentageWidth = floor(floatval(100) / $options_per_row) - 2; $div = "<div class=\"fabrik_subelement\" style=\"float:left;width:" . $percentageWidth . "%\">\n"; } for ($ii = 0; $ii < count($arVals); $ii++) { if ($options_per_row > 0) { $str .= $div; } $thisname = FabrikString::rtrimword($name, '[]') . "[{$ii}]"; $label = "<span>" . $arTxt[$ii] . "</span>"; $value = htmlspecialchars($arVals[$ii], ENT_QUOTES); //for values like '1"' $chx = "<input type=\"checkbox\" class=\"fabrikinput checkbox\" name=\"{$thisname}\" value=\"" . $value . "\" "; if (is_array($selected) and in_array($arVals[$ii], $selected)) { if ($params->get('icon_folder') != -1 && $params->get('icon_folder') != '') { $aRoValues[] = $this->_replaceWithIcons($arVals[$ii]); } else { $aRoValues[] = $arTxt[$ii]; } $chx .= " checked=\"checked\" />\n"; } else { $chx .= " />\n"; } $str .= $params->get('element_before_label') == '1' ? "<label>" . $chx . $label . "</label>\n" : "<label>" . $label . $chx . "</label>\n"; if ($options_per_row > 0) { $str .= "</div> <!-- end row div -->\n"; } } if (!$this->_editable) { $splitter = $params->get('icon_folder') != -1 && $params->get('icon_folder') != '' ? ' ' : ', '; return implode($splitter, $aRoValues); } if ($options_per_row > 0) { $str .= "<br />"; } $str .= "</div>"; if ($params->get('allow_frontend_addtocheckbox', false)) { $onlylabel = $params->get('chk-allowadd-onlylabel'); $str .= $this->getAddOptionFields($onlylabel, $repeatCounter); } return $str; }
private function getCordsFromData($d) { $v = trim($d); $v = FabrikString::ltrimword($v, "("); if (strstr($v, ",")) { if (strstr($v, ":")) { $ar = explode(":", $v); array_pop($ar); $v = explode(",", $ar[0]); } else { $v = explode(",", $v); } $v[1] = FabrikString::rtrimword($v[1], ")"); } else { $v = array(0, 0); } return $v; }
/** * Build the filter query for the given element. * Can be overwritten in plugin - e.g. see checkbox element which checks for partial matches * * @param string $key Element name in format `tablename`.`elementname` * @param string $condition =/like etc. * @param string $value Search string - already quoted if specified in filter array options * @param string $originalValue Original filter value without quotes or %'s applied * @param string $type Filter type advanced/normal/prefilter/search/querystring/searchall * * @return string sql query part e,g, "key = value" */ public function getFilterQuery($key, $condition, $value, $originalValue, $type = 'normal') { $element = $this->getElement(); $db = JFactory::getDbo(); $condition = JString::strtoupper($condition); $this->encryptFieldName($key); $glue = 'OR'; if ($element->filter_type == 'checkbox' || $element->filter_type == 'multiselect') { $str = array(); if ($condition === 'NOT IN') { $partialComparison = ' NOT LIKE '; $comparison = ' <> '; $glue = ' AND '; } else { $partialComparison = ' LIKE '; $comparison = ' = '; $glue = ' OR '; } switch ($condition) { case 'IN': case 'NOT IN': /** * Split out 1,2,3 into an array to iterate over. * It's a string if pre-filter, array if element filter */ if (!is_array($originalValue)) { $originalValue = explode(',', $originalValue); } foreach ($originalValue as &$v) { $v = trim($v); $v = FabrikString::ltrimword($v, '"'); $v = FabrikString::ltrimword($v, "'"); $v = FabrikString::rtrimword($v, '"'); $v = FabrikString::rtrimword($v, "'"); } break; default: $originalValue = (array) $originalValue; break; } foreach ($originalValue as $v2) { $v2 = str_replace("/", "\\\\/", $v2); $str[] = '(' . $key . $partialComparison . $db->quote('%"' . $v2 . '"%') . $glue . $key . $comparison . $db->quote($v2) . ') '; } $str = '(' . implode($glue, $str) . ')'; } else { $originalValue = trim($value, "'"); /* * JSON stored values will back slash "/". So we need to add "\\\\" * before it to escape it for the query. */ $originalValue = str_replace("/", "\\\\/", $originalValue); if (strtoupper($condition) === 'IS NULL') { $value = ''; } switch ($condition) { case '=': case '<>': $condition2 = $condition == '=' ? 'LIKE' : 'NOT LIKE'; $glue = $condition == '=' ? 'OR' : 'AND'; $db = FabrikWorker::getDbo(); $str = "({$key} {$condition} {$value} " . " {$glue} {$key} {$condition2} " . $db->quote('["' . $originalValue . '"%') . " {$glue} {$key} {$condition2} " . $db->quote('%"' . $originalValue . '"%') . " {$glue} {$key} {$condition2} " . $db->quote('%"' . $originalValue . '"]') . ")"; break; default: $str = " {$key} {$condition} {$value} "; break; } } return $str; }
/** * create the SQL install file * * @param object $row package * * @return string path */ protected function makeInstallSQL($row) { $sql = ''; $config = JFactory::getConfig(); $db = FabrikWorker::getDbo(true); // Create the sql for the cloned fabrik meta data tables foreach ($this->tables as $table) { $db->setQuery('SHOW CREATE TABLE ' . $table); $tbl = $db->loadRow(); $tbl = str_replace('_fabrik_', '_' . $row->component_name . '_', $tbl[1]); $tbl = str_replace($config->get('dbprefix'), '#__', $tbl); $sql .= str_replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS', $tbl) . ";\n\n"; $table = str_replace(array('_fabrik_', '{package}'), array('_' . $row->component_name . '_', $row->component_name), $table); $sql .= 'TRUNCATE TABLE ' . $table . ";\n\n"; } foreach ($row->blocks as $block => $ids) { $key = FabrikString::rtrimword($block, 's'); } // Create the sql to build the db tables that store the data. $formModel = JModelLegacy::getInstance('form', 'FabrikFEModel'); $lookups = $this->getInstallItems($row); $lids = $lookups->list; JArrayHelper::toInteger($lids); $plugins = array(); foreach ($lids as $lid) { $listModel = JModelLegacy::getInstance('list', 'FabrikFEModel'); $listModel->setId($lid); $sql .= "\n\n" . $listModel->getCreateTableSQL(true); } foreach ($lookups->form as $fid) { $formModel->setId($fid); if (!in_array($fid, $lookups->list)) { $lookups->list[] = $fid; } // @FIXME get sql to create tables for dbjoin/cdd elements (need to do if not exists) $dbs = $formModel->getElementOptions(false, 'name', true, true, array()); } $sql .= "\n\n"; if (isset($lookups->visualization)) { $vrow = FabTable::getInstance('Visualization', 'FabrikTable'); $vrow->load($vid); $visModel = JModelLegacy::getInstance($vrow->plugin, 'fabrikModel'); $visModel->setId($vid); $listModels = $visModel->getlistModels(); foreach ($listModels as $lmodel) { $vrow = FabTable::getInstance('Visualization', 'FabrikTable'); $vrow->load($vid); $visModel = JModel::getInstance($vrow->plugin, 'fabrikModel'); $visModel->setId($vid); $listModels = $visModel->getlistModels(); foreach ($listModels as $lmodel) { $sql .= $lmodel->getCreateTableSQL(true); // Add the table ids to the $lookups->list if (!in_array($lmodel->getId(), $lookups->list)) { $lookups->list[] = $lmodel->getId(); } } } } $path = $this->outputPath . 'admin/sql/install.mysql.uft8.sql'; JFile::write($path, $sql); return $path; }
/** * save the pacakge * @param array data * @return bol */ public function save($data) { $canvas = $data['params']['canvas']; $canvas = json_decode($canvas); $o = new stdClass(); if (is_null($canvas)) { JError::raiseError(E_ERROR, 'malformed json package object'); } $o->canvas = $canvas; $data['params'] = json_encode($o); $return = parent::save($data); $data['id'] = $this->getState($this->getName() . '.id'); $packageId = $this->getState($this->getName() . '.id'); $blocks = is_object($o->canvas) ? $o->canvas->blocks : array(); foreach ($blocks as $fullkey => $ids) { $key = FabrikString::rtrimword($fullkey, 's'); $tbl = JString::ucfirst($key); foreach ($ids as $id) { $item = $this->getTable($tbl); $item->load($id); if ($key == 'list') { //also assign the form to the package $form = $this->getTable('Form'); $form->load($item->form_id); if (!in_array($form->id, $blocks->form)) { $o->canvas->blocks->form[] = $item->id; } } } } // resave the data to update blocks $data['params'] = json_encode($o); $return = parent::save($data); return $return; }
/** * Build the sums() sql statement * * @return string */ private function sums() { $params = $this->getParams(); $sums = explode(',', $params->get('pivot_sum')); $db = $this->model->getDb(); $fn = (int) $params->get('pivot_count', '0') == 1 ? 'COUNT' : 'SUM'; foreach ($sums as &$sum) { $sum = trim($sum); $sum = FabrikString::rtrimword($sum, '_raw'); $as = FabrikString::safeColNameToArrayKey($sum); $statement = $fn . '(' . FabrikString::safeColName($sum) . ')'; $statement .= ' AS ' . $db->quoteName($as); $statement .= ', ' . $fn . '(' . FabrikString::safeColName($sum) . ')'; $statement .= ' AS ' . $db->quoteName($as . '_raw'); $sum = $statement; } $sum = implode(', ', $sums); return $sum; }
/** * Strip out any element names from url qs vars * * @param string $url URL * * @return string */ protected function stripElementsFromUrl($url) { $url = explode('?', $url); if (count($url) == 1) { return $url; } $filtered = array(); $bits = explode('&', $url[1]); foreach ($bits as $bit) { $parts = explode('=', $bit); $key = $parts[0]; $key = FabrikString::rtrimword($key, '_raw'); if (!$this->hasElement($key)) { $filtered[] = implode('=', $parts); } } $url = $url[0] . '?' . implode('&', $filtered); return $url; }
/** * Draws the html form element * * @param array $data to pre-populate element with * @param int $repeatCounter repeat group counter * * @return string elements html */ public function render($data, $repeatCounter = 0) { $name = $this->getHTMLName($repeatCounter); $id = $this->getHTMLId($repeatCounter); $params = $this->getParams(); $bits = $this->inputProperties($repeatCounter); $value = $this->getValue($data, $repeatCounter); $opts = array(); if ($value == '') { $value = array('label' => '', 'link' => ''); } else { if (!is_array($value)) { $value = FabrikWorker::JSONtoData($value, true); /** * In some legacy case, data is like ... * [{"label":"foo","link":"bar"}] * ... I think if it came from 2.1. So lets check to see if we need * to massage that into the right format */ if (array_key_exists(0, $value) && is_object($value[0])) { $value = JArrayHelper::fromObject($value[0]); } elseif (array_key_exists(0, $value)) { $value['label'] = $value[0]; } } } if (count($value) == 0) { $value = array('label' => '', 'link' => ''); } if (FabrikWorker::getMenuOrRequestVar('rowid') == 0 && FArrayHelper::getValue($value, 'link', '') === '') { $value['link'] = $params->get('link_default_url'); } if (!$this->isEditable()) { $lbl = trim(FArrayHelper::getValue($value, 'label')); $href = trim(FArrayHelper::getValue($value, 'link')); $w = new FabrikWorker(); $href = is_array($data) ? $w->parseMessageForPlaceHolder($href, $data) : $w->parseMessageForPlaceHolder($href); $opts['target'] = trim($params->get('link_target', '')); $opts['smart_link'] = $params->get('link_smart_link', false); $opts['rel'] = $params->get('rel', ''); $title = $params->get('link_title', ''); if ($title !== '') { $opts['title'] = strip_tags($w->parseMessageForPlaceHolder($title, $data)); } return FabrikHelperHTML::a($href, $lbl, $opts); } $labelname = FabrikString::rtrimword($name, '[]') . '[label]'; $linkname = FabrikString::rtrimword($name, '[]') . '[link]'; $bits['name'] = $labelname; $bits['placeholder'] = FText::_('PLG_ELEMENT_LINK_LABEL'); $bits['value'] = $value['label']; $bits['class'] .= ' fabrikSubElement'; unset($bits['id']); $layout = $this->getLayout('form'); $layoutData = new stdClass(); $layoutData->id = $id; $layoutData->name = $name; $layoutData->linkAttributes = $bits; $bits['placeholder'] = FText::_('PLG_ELEMENT_LINK_URL'); $bits['name'] = $linkname; $bits['value'] = FArrayHelper::getValue($value, 'link'); if (is_a($bits['value'], 'stdClass')) { $bits['value'] = $bits['value']->{0}; } $layoutData->labelAttributes = $bits; return $layout->render($layoutData); }
/** * resize an image to a specific width/height using standard php gd graphics lib * @param int maximum image Width (px) * @param int maximum image Height (px) * @param string current images folder pathe (must have trailing end slash) * @param string destination folder path for resized image (must have trailing end slash) * @param string file name of the image to resize * @param bol save the resized image * @return object? image * */ function resize($maxWidth, $maxHeight, $origFile, $destFile) { /* check if the file exists*/ if (!$this->storage->exists($origFile)) { return JError::raiseError(500, "no file found for {$origFile}"); } /* Load image*/ $img = null; $ext = $this->GetImgType($origFile); if (!$ext) { return; } ini_set('display_errors', true); $memory = ini_get('memory_limit'); $intmemory = FabrikString::rtrimword($memory, 'M'); if ($intmemory < 50) { ini_set('memory_limit', '50M'); } if ($ext == 'jpg' || $ext == 'jpeg') { $img = imagecreatefromjpeg($origFile); $header = "image/jpeg"; } else { if ($ext == 'png') { $img = imagecreatefrompng($origFile); $header = "image/png"; /* Only if your version of GD includes GIF support*/ } else { if ($ext == 'gif') { if (function_exists(imagecreatefromgif)) { $img = imagecreatefromgif($origFile); $header = "image/gif"; } else { JError::raiseWarning(21, "imagecreate from gif not available"); } } } } /* If an image was successfully loaded, test the image for size*/ if ($img) { /* Get image size and scale ratio*/ $width = imagesx($img); $height = imagesy($img); $scale = min($maxWidth / $width, $maxHeight / $height); /* If the image is larger than the max shrink it*/ if ($scale < 1) { $new_width = floor($scale * $width); $new_height = floor($scale * $height); /* Create a new temporary image*/ $tmp_img = imagecreatetruecolor($new_width, $new_height); /* Copy and resize old image into new image*/ imagecopyresampled($tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height); imagedestroy($img); $img = $tmp_img; } } if (!$img) { JError::raiseWarning(21, "no image created for {$origFile}, extension = {$ext} , destination = {$destFile} "); } /* save the file * wite them out to output buffer first so that we can use JFile to write them to the server (potential using J ftp layer) */ if ($header == "image/jpeg") { ob_start(); imagejpeg($img, "", 100); $image = ob_get_contents(); ob_end_clean(); $this->storage->write($destFile, $image); } else { if ($header == "image/png") { ob_start(); imagepng($img, "", 0); $image = ob_get_contents(); ob_end_clean(); $this->storage->write($destFile, $image); } else { if (function_exists("imagegif")) { ob_start(); imagegif($img, "", 100); $image = ob_get_contents(); ob_end_clean(); $this->storage->write($destFile, $image); } else { /* try using imagemagick to convert gif to png:*/ $image_file = imgkConvertImage($image_file, $baseDir, $destDir, ".png"); } } } $this->_thumbPath = $destFile; ini_set('memory_limit', $memory); }
/** * Collapses 'repeated joined' rows into a single row. * If a group is not repeating we just use the first row's data (as subsequent rows will contain the same data * Otherwise if the group is repeating we append each repeated record's data into the first row's data * All rows execpt the first row for each group are then unset (as unique subsequent row's data will be contained within * the first row) * @param array $data */ function formatForJoins(&$data) { $merge = $this->mergeJoinedData(); if (empty($merge)) { return; } $listid = $this->getTable()->id; $dbprimaryKey = FabrikString::safeColNameToArrayKey($this->getTable()->db_primary_key); $formModel =& $this->getFormModel(); foreach ($data as $groupk => $group) { $last_pk = ''; $last_i = 0; $count = count($group); $can_repeats = array(); for ($i = 0; $i < $count; $i++) { // $$$rob if rendering J article in PDF format __pk_val not in pdf table view //$next_pk = isset($data[$groupk][$i]->__pk_val) ? $data[$groupk][$i]->__pk_val : $data[$groupk][$i]->id; $next_pk = isset($data[$groupk][$i]->__pk_val) ? $data[$groupk][$i]->__pk_val : $data[$groupk][$i]->{$dbprimaryKey}; if (!empty($last_pk) && $last_pk == $next_pk) { foreach ($data[$groupk][$i] as $key => $val) { $origKey = $key; $tmpkey = FabrikString::rtrimword($key, '_raw'); // $$$ hugh - had to cache this stuff, because if you have a lot of rows and a lot of elements, // doing this many hundreds of times causes huge slowdown, exceeding max script execution time! // And we really only need to do it once for the first row. if (!isset($can_repeats[$tmpkey])) { $elementModel =& $formModel->getElement($tmpkey); $can_repeats[$tmpkey] = $elementModel ? $elementModel->getGroup()->canRepeat() : 0; } if (isset($data[$groupk][$last_i]->{$key}) && $can_repeats[$tmpkey]) { // $$$ rob - what about data like yes/no where each viewable option needs to be shown? // $$$ rob - yeah commenting this out, not a good idea - as other cols for this record may have // different data so you end up with this col having 3 entries and the next col having four and you can't // see the correlation between the two sets of data. //if ($data[$groupk][$last_i]->$key != $val) { // $$$ rob meant that only one link to details was shown in admin - dont see the point in that //if (preg_match("#\W+fabrik___rowlink.*\W+listid=$listid\W#",$val)) { //continue; //} if ($origKey == $tmpkey) { $data[$groupk][$last_i]->{$key} .= "<br >\n" . $val; } else { $json = json_decode($data[$groupk][$last_i]->{$origKey}); $json = $val; $data[$groupk][$last_i]->{$origKey} = json_encode($json); //$data[$groupk][$last_i]->$origKey .= GROUPSPLITTER.$val; } } } unset($data[$groupk][$i]); continue; } else { $last_i = $i; // $$$rob if rendering J article in PDF format __pk_val not in pdf table view $last_pk = $next_pk; } } // $$$ rob ensure that we have a sequental set of keys otherwise ajax json will turn array into object $data[$groupk] = array_values($data[$groupk]); } }
/** * Build array of items for use in grid() * * @param array $values Option values * @param array $labels Option labels * @param array $selected Selected options * @param string $name Input name * @param string $type Checkbox/radio etc * @param bool $elementBeforeLabel Element before or after the label - deprecated - not used in Joomla 3 * @param array $classes Label classes * @param bool $buttonGroup Should it be rendered as a bootstrap button group (radio only) * * @return array Grid items */ public static function gridItems($values, $labels, $selected, $name, $type = 'checkbox', $elementBeforeLabel = true, $classes = array(), $buttonGroup = false) { $j3 = FabrikWorker::j3(); $version = new JVersion(); for ($i = 0; $i < count($values); $i++) { $item = array(); $thisname = $type === 'checkbox' ? FabrikString::rtrimword($name, '[]') . '[' . $i . ']' : $name; $label = '<span>' . $labels[$i] . '</span>'; // For values like '1"' $value = htmlspecialchars($values[$i], ENT_QUOTES); $inputClass = FabrikWorker::j3() ? '' : $type; if (array_key_exists('input', $classes)) { $inputClass .= ' ' . implode(' ', $classes['input']); } $chx = '<input type="' . $type . '" class="fabrikinput ' . $inputClass . '" name="' . $thisname . '" value="' . $value . '" '; $sel = in_array($values[$i], $selected); $chx .= $sel ? ' checked="checked" />' : ' />'; $labelClass = FabrikWorker::j3() && !$buttonGroup ? $type : ''; $item[] = '<label class="fabrikgrid_' . $value . ' ' . $labelClass . '">'; $item[] = $elementBeforeLabel == '1' ? $chx . $label : $label . $chx; $item[] = '</label>'; $items[] = implode("\n", $item); } return $items; }
/** * Draws the html form element * * @param array $data To pre-populate element with * @param int $repeatCounter Repeat group counter * * @return string Elements html */ public function render($data, $repeatCounter = 0) { $this->_repeatGroupCounter = $repeatCounter; $id = $this->getHTMLId($repeatCounter); $name = $this->getHTMLName($repeatCounter); $groupModel = $this->getGroup(); $element = $this->getElement(); $params = $this->getParams(); $use_wip = $params->get('upload_use_wip', '0') == '1'; $device_capture = $params->get('ul_device_capture', '0'); if ($element->hidden == '1') { return $this->getHiddenField($name, $data[$name], $id); } $str = array(); $value = $this->getValue($data, $repeatCounter); $value = is_array($value) ? $value : FabrikWorker::JSONtoData($value, true); $value = $this->checkForSingleCropValue($value); if ($params->get('ajax_upload')) { if (isset($value->file)) { $value = $value->file; } } $storage = $this->getStorage(); $use_download_script = $params->get('fu_use_download_script', '0'); // $$$ rob - explode as it may be grouped data (if element is a repeating upload) $values = is_array($value) ? $value : FabrikWorker::JSONtoData($value, true); if (!$this->isEditable() && ($use_download_script == FU_DOWNLOAD_SCRIPT_DETAIL || $use_download_script == FU_DOWNLOAD_SCRIPT_BOTH)) { $links = array(); if (!is_array($value)) { $value = (array) $value; } foreach ($value as $v) { $links[] = $this->downloadLink($v, $data, $repeatCounter); } return count($links) < 2 ? implode("\n", $links) : '<ul class="fabrikRepeatData"><li>' . implode('</li><li>', $links) . '</li></ul>'; } $render = new stdClass(); $render->output = ''; $allRenders = array(); /* * $$$ hugh testing slide-show display */ if ($params->get('fu_show_image') === '3' && !$this->isEditable()) { // Failed validations - format different! if (array_key_exists('id', $values)) { $values = array_keys($values['id']); } $rendered = $this->buildCarousel($id, $values, $params, $data); return $rendered; } if ($params->get('fu_show_image') !== '0' && !$params->get('ajax_upload') || !$this->isEditable()) { // Failed validations - format different! if (array_key_exists('id', $values)) { $values = array_keys($values['id']); } // End failed validations foreach ($values as $value) { if (is_object($value)) { $value = $value->file; } $render = $this->loadElement($value); if ($use_wip && $this->isEditable() || $value != '' && ($storage->exists(COM_FABRIK_BASE . $value) || JString::substr($value, 0, 4) == 'http')) { $render->render($this, $params, $value); } if ($render->output != '') { if ($this->isEditable()) { // $$$ hugh - TESTING - using HTML5 to show a selected image, so if no file, still need the span, hidden, but not the actual delete button if ($use_wip && empty($value)) { $render->output = '<span class="fabrikUploadDelete fabrikHide" id="' . $id . '_delete_span">' . $render->output . '</span>'; } else { $render->output = '<span class="fabrikUploadDelete" id="' . $id . '_delete_span">' . $this->deleteButton($value, $repeatCounter) . $render->output . '</span>'; } /* if ($use_wip) { $render->output .= '<video id="' . $id . '_video_preview" controls></video>'; } */ } $allRenders[] = $render->output; } } } if (!$this->isEditable()) { if ($render->output == '' && $params->get('default_image') != '') { $render->output = '<img src="' . $params->get('default_image') . '" alt="image" />'; $allRenders[] = $render->output; } $str[] = '<div class="fabrikSubElementContainer">'; $ul = '<ul class="fabrikRepeatData"><li>' . implode('</li><li>', $allRenders) . '</li></ul>'; $str[] = count($allRenders) < 2 ? implode("\n", $allRenders) : $ul; $str[] = '</div>'; return implode("\n", $str); } $allRenders = implode('<br/>', $allRenders); $allRenders .= $allRenders == '' ? '' : '<br/>'; $capture = ''; switch ($device_capture) { case 1: $capture = ' capture="camera"'; case 2: $capture = ' accept="image/*"' . $capture; break; case 3: $capture = ' capture="microphone"'; case 4: $capture = ' accept="audio/*"' . $capture; break; case 5: $capture = ' capture="camcorder"'; case 6: $capture = ' accept="video/*"' . $capture; break; default: $capture = implode(",.", $this->_getAllowedExtension()); $capture = $capture ? ' accept=".' . $capture . '"' : ''; break; } $str[] = $allRenders . '<input class="fabrikinput" name="' . $name . '" type="file" id="' . $id . '"' . $capture . ' />' . "\n"; if ($params->get('fileupload_storage_type', 'filesystemstorage') == 'filesystemstorage' && $params->get('upload_allow_folderselect') == '1') { $rDir = JPATH_SITE . '/' . $params->get('ul_directory'); $folders = JFolder::folders($rDir); $str[] = FabrikHelperHTML::folderAjaxSelect($folders); if ($groupModel->canRepeat()) { $uploadName = FabrikString::rtrimword($name, "[{$repeatCounter}]") . "[ul_end_dir][{$repeatCounter}]"; } else { $uploadName = $name . '[ul_end_dir]'; } $str[] = '<input name="' . $uploadName . '" type="hidden" class="folderpath"/>'; } if ($params->get('ajax_upload')) { $str = array(); $str[] = $allRenders; $str = $this->plupload($str, $repeatCounter, $values); } array_unshift($str, '<div class="fabrikSubElementContainer">'); $str[] = '</div>'; return implode("\n", $str); }
/** * Render checkbox list in form * * @param array $data Form data * @param int $repeatCounter Repeat group counter * @param array &$html HTML to assign output to * @param array $tmp List of value/label objects * @param array $default Default values - the lookup table's primary key values * * @since 3.0.7 * * @return void */ protected function renderCheckBoxList($data, $repeatCounter, &$html, $tmp, $default) { $id = $this->getHTMLId($repeatCounter); $name = $this->getHTMLName($repeatCounter); $params = $this->getParams(); $optsPerRow = (int) $params->get('dbjoin_options_per_row', 0); $html[] = '<div class="fabrikSubElementContainer" id="' . $id . '">'; $editable = $this->isEditable(); $attribs = 'class="fabrikinput inputbox" id="' . $id . '"'; $name = FabrikString::rtrimword($name, '[]'); $targetIds = $this->multiOptionTargetIds($data, $repeatCounter); if ($targetIds !== false) { $default = $targetIds; } $html[] = FabrikHelperHTML::aList('checkbox', $tmp, $name, $attribs, $default, 'value', 'text', $optsPerRow, $editable); if (empty($tmp)) { $tmpids = array(); $o = new stdClass(); $o->text = 'dummy'; $o->value = 'dummy'; $tmpids[] = $o; $tmp = $tmpids; $dummy = FabrikHelperHTML::aList('checkbox', $tmp, $name, $attribs, $default, 'value', 'text', 1, true); $html[] = '<div class="chxTmplNode">' . $dummy . '</div>'; } $html[] = '</div>'; }
/** * Encrypt view only elements * * @param array &$aHiddenFields Hidden fields * * @return void */ protected function _cryptViewOnlyElements(&$aHiddenFields) { /** @var FabrikFEModelForm $model */ $model = $this->getModel(); $crypt = FabrikWorker::getCrypt(); $fields = array(); $ro = $model->getReadOnlyVals(); foreach ($ro as $key => $pair) { $repeatGroup = $pair['repeatgroup']; $isJoin = $pair['join']; $input = $pair['data']; // $$$ rob not sure this is correct now as I modified the readOnlyVals structure to contain info about if its in a group // and it now contains the repeated group data $input = is_array($input) && array_key_exists('value', $input) ? $input['value'] : $input; if ($repeatGroup) { $ar = array(); $input = (array) $input; foreach ($input as $i) { if (is_array($i)) { // Elements with sub options in repeat group $i = json_encode($i); } $ar[] = $i; } $input = $isJoin ? $ar : json_encode($ar); } else { if (is_array($input)) { // Elements with sub options not in repeat group $input = json_encode($input); } } if (is_array($input)) { for ($x = 0; $x < count($input); $x++) { if (trim($input[$x]) !== '') { $input[$x] = $crypt->encrypt($input[$x]); } } } else { if (trim($input) !== '') { $input = $crypt->encrypt($input); } } $safeKey = FabrikString::rtrimword($key, '[]'); // $$$ rob - no don't do below as it will strip out join names join[x][fullname] => join // $key = preg_replace("/\[(.*)\]/", '', $key); if (!array_key_exists($safeKey, $fields)) { $fields[$safeKey] = $input; } else { $fields[$safeKey] = (array) $fields[$safeKey]; $fields[$safeKey][] = $input; } } foreach ($fields as $key => $input) { if (is_array($input)) { for ($c = 0; $c < count($input); $c++) { $i = $input[$c]; $fields[] = '<input type="hidden" name="fabrik_vars[querystring][' . $key . '][' . $c . ']" value="' . $i . '" />'; } unset($fields[$key]); } else { $fields[$key] = '<input type="hidden" name="fabrik_vars[querystring][' . $key . ']" value="' . $input . '" />'; } } $aHiddenFields = array_merge($aHiddenFields, array_values($fields)); }
/** * @param $key * @param $condition * @param $originalValue * @param $evalFilter * * @return string */ protected function filterQueryMultiValues($key, $condition, $originalValue, $evalFilter) { $str = array(); if ($evalFilter) { $originalValue = stripslashes(htmlspecialchars_decode($originalValue, ENT_QUOTES)); $originalValue = @eval($originalValue); FabrikWorker::logEval($originalValue, 'Caught exception on eval of elementList::filterQueryMultiValues() ' . $key . ': %s'); } if ($condition === 'NOT IN') { $partialComparison = ' NOT LIKE '; $comparison = ' <> '; $glue = ' AND '; } else { $partialComparison = ' LIKE '; $comparison = ' = '; $glue = ' OR '; } switch ($condition) { case 'IN': case 'NOT IN': /** * Split out 1,2,3 into an array to iterate over. * It's a string if pre-filter, array if element filter */ if (!is_array($originalValue)) { $originalValue = explode(',', $originalValue); } foreach ($originalValue as &$v) { $v = trim($v); $v = FabrikString::ltrimword($v, '"'); $v = FabrikString::ltrimword($v, "'"); $v = FabrikString::rtrimword($v, '"'); $v = FabrikString::rtrimword($v, "'"); } break; default: $originalValue = (array) $originalValue; break; } foreach ($originalValue as $v2) { $v2 = str_replace("/", "\\\\/", $v2); $str[] = '(' . $key . $partialComparison . $this->_db->q('%"' . $v2 . '"%') . $glue . $key . $comparison . $this->_db->q($v2) . ') '; } return '(' . implode($glue, $str) . ')'; }
/** * @return string */ protected function defaultMessage() { $formModel = $this->getModel(); $data = $formModel->formData; $arDontEmailThesKeys = array(); // Remove raw file upload data from the email foreach ($_FILES as $key => $file) { $arDontEmailThesKeys[] = $key; } $message = ''; $groups = $formModel->getGroupsHiarachy(); foreach ($groups as $groupModel) { $elementModels = $groupModel->getPublishedElements(); foreach ($elementModels as $elementModel) { $element = $elementModel->getElement(); $element->label = strip_tags($element->label); if (!array_key_exists($element->name, $data)) { $elName = $element->getFullName(); } else { $elName = $element->name; } $key = $elName; if (!in_array($key, $arDontEmailThesKeys)) { if (array_key_exists($elName, $data)) { $val = stripslashes($data[$elName]); $params = $elementModel->getParams(); if (method_exists($elementModel, 'getEmailValue')) { $val = $elementModel->getEmailValue($val); } else { if (is_array($val)) { $val = implode("\n", $val); } } $val = FabrikString::rtrimword($val, '<br />'); $message .= $element->label . ': ' . $val . "\r\n"; } } } } $message = FText::_('PLG_FORM_SMS_FROM') . $this->config->get('sitename') . "\r \n \r \nMessage:\r \n" . stripslashes($message); return $message; }
/** * used to format the data when shown in the form's email * @param mixed element's data * @param array form records data * @param int repeat group counter * @return string formatted value */ function getEmailValue($value, $data, $c) { $params =& $this->getParams(); $element =& $this->getElement(); $labels = explode(GROUPSPLITTER2, $element->sub_labels); $values = explode(GROUPSPLITTER2, $element->sub_values); $sLabels = ''; if (is_string($value)) { $value = array($value); } foreach ($value as $tmpVal) { $key = array_search($tmpVal, $values); $sLabels .= $labels[$key] . "\n"; } $val = FabrikString::rtrimword($sLabels, "\n"); return $val; }
/** * Resize an image to a specific width/height * * @param int $maxWidth maximum image Width (px) * @param int $maxHeight maximum image Height (px) * @param string $origFile current images folder path (must have trailing end slash) * @param string $destFile destination folder path for resized image (must have trailing end slash) * @param int $quality Percentage image save quality 100 = no compression, 0 = max compression * * @return object image */ public function resize($maxWidth, $maxHeight, $origFile, $destFile, $quality = 100) { $app = JFactory::getApplication(); // Check if the file exists if (!$this->storage->exists($origFile)) { throw new RuntimeException("no file found for {$origFile}"); } // Load image $img = null; $ext = $this->getImgType($origFile); if (!$ext) { return; } ini_set('display_errors', true); $memory = ini_get('memory_limit'); $intMemory = FabrikString::rtrimword($memory, 'M'); if ($intMemory < 50) { ini_set('memory_limit', '50M'); } if ($ext == 'jpg' || $ext == 'jpeg') { $img = imagecreatefromjpeg($origFile); $header = "image/jpeg"; } elseif ($ext == 'png') { $img = imagecreatefrompng($origFile); $header = "image/png"; // Only if your version of GD includes GIF support } elseif ($ext == 'gif') { if (function_exists('imagecreatefromgif')) { $img = imagecreatefromgif($origFile); $header = "image/gif"; } else { $app->enqueueMessage("imagecreate from gif not available"); } } // If an image was successfully loaded, test the image for size if ($img) { // Handle image transparency for original image if (function_exists('imagealphablending')) { imagealphablending($img, false); imagesavealpha($img, true); } // Get image size and scale ratio $width = imagesx($img); $height = imagesy($img); $scale = min($maxWidth / $width, $maxHeight / $height); // If the image is larger than the max shrink it if ($scale < 1) { $new_width = floor($scale * $width); $new_height = floor($scale * $height); // Create a new temporary image $tmp_img = imagecreatetruecolor($new_width, $new_height); // handle transparency for tmp image if (function_exists('imagealphablending')) { imagealphablending($tmp_img, false); imagesavealpha($tmp_img, true); } // Copy and resize old image into new image imagecopyresampled($tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height); imagedestroy($img); $img = $tmp_img; } } if (!$img) { $app->enqueueMessage("no image created for {$origFile}, extension = {$ext} , destination = {$destFile} "); } /* save the file * write them out to output buffer first so that we can use JFile to write them to the server (potential using J ftp layer) */ if ($header == "image/jpeg") { ob_start(); imagejpeg($img, null, $quality); $image = ob_get_contents(); ob_end_clean(); $this->storage->write($destFile, $image); } else { if ($header == "image/png") { ob_start(); $quality = round((100 - $quality) * 9 / 100); imagepng($img, null, $quality); $image = ob_get_contents(); ob_end_clean(); $this->storage->write($destFile, $image); } else { if (function_exists("imagegif")) { ob_start(); imagegif($img, null, $quality); $image = ob_get_contents(); ob_end_clean(); $this->storage->write($destFile, $image); } else { $app->enqueueMessage("GD gif support not available: could not resize image"); } } } $this->thumbPath = $destFile; ini_set('memory_limit', $memory); }
/** * THIS SEEMS GOOFY TO HAVE TO OVERRIDE DEFAULT FUNCTION - BUT! * THE ORIGINAL SETS THE PAGE TO EMPTY IF ITS 0 - APPARENTLY TO DO WITH * ROUTING - THIS HAS BEEN REMOVED HERE * * PERHAPS THE FABRIK ROUTING ISN'T RIGHT? * * OCCURS EVEN WITHOUT SEF URLS ON THOUGH? :s * * Create and return the pagination data object * * @return object Pagination data object */ protected function _buildDataObject() { $app = JFactory::getApplication(); // Initialize variables $data = new stdClass(); $this->url = preg_replace("/limitstart{$this->id}=(.*)?(&|)/", '', $this->url); $this->url = FabrikString::rtrimword($this->url, "&"); // $$$ hugh - need to work out if we need & or ? $sepchar = strstr($this->url, '?') ? '&' : '?'; $data->all = new JPaginationObject(JText::_('COM_FABRIK_VIEW_ALL')); if (!$this->viewAll) { $data->all->base = '0'; $data->all->link = JRoute::_("{$sepchar}limitstart="); } // Set the start and previous data objects $data->start = new JPaginationObject(JText::_('COM_FABRIK_START')); $data->previous = new JPaginationObject(JText::_('COM_FABRIK_PREV')); if ($this->get('pages.current') > 1) { $page = ($this->get('pages.current') - 2) * $this->limit; $data->start->base = '0'; $data->start->link = JRoute::_($this->url . "{$sepchar}limitstart{$this->id}=0"); $data->previous->base = $page; $data->previous->link = JRoute::_($this->url . "{$sepchar}limitstart{$this->id}=" . $page); $data->start->link = str_replace('resetfilters=1', '', $data->start->link); $data->previous->link = str_replace('resetfilters=1', '', $data->previous->link); $data->start->link = str_replace('clearordering=1', '', $data->start->link); $data->previous->link = str_replace('clearordering=1', '', $data->previous->link); } // Set the next and end data objects $data->next = new JPaginationObject(JText::_('COM_FABRIK_NEXT')); $data->end = new JPaginationObject(JText::_('COM_FABRIK_END')); if ($this->get('pages.current') < $this->get('pages.total')) { $next = $this->get('pages.current') * $this->limit; $end = ($this->get('pages.total') - 1) * $this->limit; $data->next->base = $next; $data->next->link = JRoute::_($this->url . "{$sepchar}limitstart{$this->id}=" . $next); $data->end->base = $end; $data->end->link = JRoute::_($this->url . "{$sepchar}limitstart{$this->id}=" . $end); $data->next->link = str_replace('resetfilters=1', '', $data->next->link); $data->end->link = str_replace('resetfilters=1', '', $data->end->link); $data->next->link = str_replace('clearordering=1', '', $data->next->link); $data->end->link = str_replace('clearordering=1', '', $data->end->link); } $data->pages = array(); $stop = $this->get('pages.stop'); for ($i = $this->get('pages.start'); $i <= $stop; $i++) { $offset = ($i - 1) * $this->limit; $data->pages[$i] = new JPaginationObject($i); if ($i != $this->get('pages.current') || $this->viewAll) { $data->pages[$i]->base = $offset; $data->pages[$i]->link = JRoute::_($this->url . "{$sepchar}limitstart{$this->id}=" . $offset); $data->pages[$i]->link = str_replace('resetfilters=1', '', $data->pages[$i]->link); $data->pages[$i]->link = str_replace('clearordering=1', '', $data->pages[$i]->link); } } return $data; }
/** * $$$ rob 19/10/2011 now called before formatData() from getData() as otherwise element tips (created in element->renderListData()) * only contained first merged records data and not all merged records * * Collapses 'repeated joined' rows into a single row. * If a group is not repeating we just use the first row's data (as subsequent rows will contain the same data * Otherwise if the group is repeating we append each repeated record's data into the first row's data * All rows except the first row for each group are then unset (as unique subsequent row's data will be contained within * the first row) * * @param array &$data list data * * @return void */ protected function formatForJoins(&$data) { $merge = $this->mergeJoinedData(); if (empty($merge)) { return; } $dbPrimaryKey = $this->getPrimaryKey(true); $formModel = $this->getFormModel(); $db = $this->getDb(); FabrikHelperHTML::debug($data, 'render:before formatForJoins'); $last_pk = ''; $last_i = 0; $count = count($data); $canRepeats = array(); $canRepeatsTables = array(); $canRepeatsKeys = array(); $canRepeatsPkValues = array(); $remove = array(); $first_pk_i = array(); if (empty($data)) { return; } /* First, go round first row of data, and prep some stuff. * Basically, if doing a "reduce data" merge (merge == 2), we need to know what the * PK element is for each joined group (well, for each element, really) */ foreach ($data[0] as $key => $val) { $shortKey = FabrikString::rtrimword($key, '_raw'); /* $$$ hugh - had to cache this stuff, because if you have a lot of rows and a lot of elements, * doing this many hundreds of times causes huge slowdown, exceeding max script execution time! * And we really only need to do it once for the first row. */ if (!isset($canRepeats[$shortKey])) { $elementModel = $formModel->getElement($shortKey); // $$$ rob - testing for linking join which is repeat but linked join which is not - still need separate info from linked to join // $canRepeats[$shortKey] = $elementModel ? ($elementModel->getGroup()->canRepeat()) : 0; if ($merge == 2 && $elementModel) { if ($elementModel->getGroup()->canRepeat() || $elementModel->getGroup()->isJoin()) { // We need to work out the PK of the joined table. // So first, get the table name. $group = $elementModel->getGroup(); $join = $group->getJoinModel()->getJoin(); $join_table_name = $join->table_join; // We have the table name, so see if we already have it cached ... if (!isset($canRepeatsTables[$join_table_name])) { // We don't have it yet, so grab the PK $keys = $this->getPrimaryKeyAndExtra($join_table_name); if (!empty($keys) && array_key_exists('key', $keys[0])) { // OK, now we have the PK for the table $canRepeatsTables[$join_table_name] = $keys[0]; } else { // $$$ hugh - might be a view, so Hail Mary attempt to get PK $query = $db->getQuery(true); $query->select('db_primary_key')->from('#__{package}_lists')->where('db_table_name = ' . $db->q($join_table_name)); $db->setQuery($query); $joinPk = $db->loadResult(); if (!empty($joinPk)) { $canRepeatsTables[$join_table_name] = array('colname' => FabrikString::shortColName($joinPk)); } } } // Hopefully we now have the PK if (isset($canRepeatsTables[$join_table_name])) { $canRepeatsKeys[$shortKey] = $join_table_name . '___' . $canRepeatsTables[$join_table_name]['colname']; } $crk_sk = $canRepeatsKeys[$shortKey]; // Create the array if it doesn't exist if (!isset($canRepeatsPkValues[$crk_sk])) { $canRepeatsPkValues[$crk_sk] = array(); } // Now store the if (!isset($canRepeatsPkValues[$crk_sk][0]) and isset($data[0]->{$crk_sk})) { $canRepeatsPkValues[$crk_sk][0] = $data[0]->{$crk_sk}; } } } $canRepeats[$shortKey] = $elementModel ? $elementModel->getGroup()->canRepeat() || $elementModel->getGroup()->isJoin() : 0; } } for ($i = 0; $i < $count; $i++) { // $$$rob if rendering J article in PDF format __pk_val not in pdf table view $next_pk = isset($data[$i]->__pk_val) ? $data[$i]->__pk_val : $data[$i]->{$dbPrimaryKey}; //if (!empty($last_pk) && ($last_pk == $next_pk)) if (array_key_exists($next_pk, $first_pk_i)) { foreach ($data[$i] as $key => $val) { $origKey = $key; $shortKey = FabrikString::rtrimword($key, '_raw'); if ($canRepeats[$shortKey]) { if ($merge == 2 && !isset($canRepeatsPkValues[$canRepeatsKeys[$shortKey]][$i]) && isset($data[$i]->{$canRepeatsKeys[$shortKey]})) { $canRepeatsPkValues[$canRepeatsKeys[$shortKey]][$i] = $data[$i]->{$canRepeatsKeys[$shortKey]}; } if ($origKey == $shortKey) { /* $$$ rob - this was just appending data with a <br> but as we do thie before the data is formatted * it was causing all sorts of issues for list rendering of links, dates etc. So now turn the data into * an array and at the end of this method loop over the data to encode the array into a json object. */ $do_merge = true; if ($merge == 2) { $pk_vals = array_count_values(array_filter($canRepeatsPkValues[$canRepeatsKeys[$shortKey]])); if (isset($data[$i]->{$canRepeatsKeys[$shortKey]})) { if ($pk_vals[$data[$i]->{$canRepeatsKeys[$shortKey]}] > 1) { $do_merge = false; } } } if ($do_merge) { /* The raw data is not altererd at the moment - not sure that that seems correct but can't see any issues * with it currently * $$$ hugh - added processing of raw data, needed for _raw placeholders * in things like custom links */ /* $data[$last_i]->$key = (array) $data[$last_i]->$key; array_push($data[$last_i]->$key, $val); */ $data[$first_pk_i[$next_pk]]->{$key} = (array) $data[$first_pk_i[$next_pk]]->{$key}; // if first occurrence is null, casting to array will give empty array if (count($data[$first_pk_i[$next_pk]]->{$key}) === 0) { array_push($data[$first_pk_i[$next_pk]]->{$key}, null); } array_push($data[$first_pk_i[$next_pk]]->{$key}, $val); $rawKey = $key . '_raw'; if (isset($data[$i]->{$rawKey})) { $rawval = $data[$i]->{$rawKey}; /* $data[$last_i]->$rawKey = (array) $data[$last_i]->$rawKey; array_push($data[$last_i]->$rawKey, $rawval); */ $data[$first_pk_i[$next_pk]]->{$rawKey} = (array) $data[$first_pk_i[$next_pk]]->{$rawKey}; array_push($data[$first_pk_i[$next_pk]]->{$rawKey}, $rawval); } } } else { /* $$$ hugh - don't think we need this, now we're processing _raw data? if (!is_array($data[$last_i]->$origKey)) { $json= $val; $data[$last_i]->$origKey = json_encode($json); } */ } } } $remove[] = $i; continue; } else { $first_pk_i[$next_pk] = $i; if ($merge == 2) { foreach ($data[$i] as $key => $val) { $origKey = $key; $shortKey = FabrikString::rtrimword($key, '_raw'); if ($canRepeats[$shortKey] && !isset($canRepeatsPkValues[$canRepeatsKeys[$shortKey]][$i]) && isset($data[$i]->{$canRepeatsKeys[$shortKey]})) { $canRepeatsPkValues[$canRepeatsKeys[$shortKey]][$i] = $data[$i]->{$canRepeatsKeys[$shortKey]}; } } } $last_i = $i; // $$$rob if rendering J article in PDF format __pk_val not in pdf table view $last_pk = $next_pk; } // $$$ rob ensure that we have a sequential set of keys otherwise ajax json will turn array into object $data = array_values($data); } for ($c = count($remove) - 1; $c >= 0; $c--) { unset($data[$remove[$c]]); } // $$$ rob loop over any data that was merged into an array and turn that into a json object foreach ($data as $gKey => $d) { foreach ($d as $k => $v) { if (is_array($v)) { foreach ($v as &$v2) { $v2 = FabrikWorker::JSONtoData($v2); } $v = json_encode($v); $data[$gKey]->{$k} = $v; } } } $data = array_values($data); }
/** * Set the url for the filter form's action * * @return string action url */ public function getFilterFormURL() { if (isset($this->getFilterFormURL)) { return $this->getFilterFormURL; } $app = JFactory::getApplication(); $package = $app->getUserState('com_fabrik.package', 'fabrik'); $input = $app->input; $option = $input->get('option'); // Get the router $router = $app->getRouter(); $uri = clone JURI::getInstance(); /** * $$$ rob force these to be 0 once the menu item has been loaded for the first time * subsequent loads of the link should have this set to 0. When the menu item is re-clicked * rest filters is set to 1 again */ $router->setVar('resetfilters', 0); if ($option !== 'com_' . $package) { // $$$ rob these can't be set by the menu item, but can be set in {fabrik....} $router->setVar('clearordering', 0); $router->setVar('clearfilters', 0); } $queryvars = $router->getVars(); $page = 'index.php?'; foreach ($queryvars as $k => $v) { $qs[] = $k . '=' . $v; } $action = $page . implode("&", $qs); // Limitstart gets added in the pagination model $action = preg_replace("/limitstart" . $this->getState('id') . "}=(.*)?(&|)/", '', $action); $action = FabrikString::rtrimword($action, "&"); $this->getFilterFormURL = JRoute::_($action); return $this->getFilterFormURL; }
/** * used from getIntro as preg_replace_callback function to strip * undeisred text from form label intro * @param array $match * @return string intro text */ private function _getIntro($match) { $m = explode(":", $match[0]); array_shift($m); return FabrikString::rtrimword(implode(":", $m), "}"); }
/** * default email handling routine, called if no email template specified * @return string email message */ function _getMessage() { $config =& JFactory::getConfig(); $data = $this->formModel->_formData; $arDontEmailThesKeys = array(); /*remove raw file upload data from the email*/ foreach ($_FILES as $key => $file) { $arDontEmailThesKeys[] = $key; } $message = ""; $pluginManager = $this->formModel->getPluginManager(); $groups =& $this->formModel->getGroupsHiarachy(); foreach ($groups as $groupModel) { $elementModels =& $groupModel->getPublishedElements(); foreach ($elementModels as $elementModel) { $element =& $elementModel->getElement(); $element->label = strip_tags($element->label); if (!array_key_exists($element->name, $data)) { $elName = $element->getFullName(); } else { $elName = $element->name; } $key = $elName; if (!in_array($key, $arDontEmailThesKeys)) { if (array_key_exists($elName, $data)) { $val = stripslashes($data[$elName]); $params =& $elementModel->getParams(); if (method_exists($elementModel, 'getEmailValue')) { $val = $elementModel->getEmailValue($val); } else { if (is_array($val)) { $val = implode("\n", $val); } } $val = FabrikString::rtrimword($val, "<br />"); $message .= $element->label . ": " . $val . "\r\n"; } } } } $message = JText::_('PLG_FORM_SMS_FROM') . $config->getValue('sitename') . "\r \n \r \nMessage:\r \n" . stripslashes($message); return $message; }
/** * set the url for the filter form's action * @return string action url */ public function getFilterFormURL() { if (isset($this->getFilterFormURL)) { return $this->getFilterFormURL; } $option = JRequest::getCmd('option'); // Get the router $app =& JFactory::getApplication(); $router =& $app->getRouter(); $uri = clone JURI::getInstance(); // $$$ rob force these to be 0 once the menu item has been loaded for the first time //subsequent loads of the link should have this set to 0. When the menu item is re-clicked //rest filters is set to 1 again $router->setVar('resetfilters', 0); if ($option !== 'com_fabrik') { // $$$ rob these can't be set by the menu item, but can be set in {fabrik....} $router->setVar('clearordering', 0); $router->setVar('clearfilters', 0); } $queryvars = $router->getVars(); $page = "index.php?"; foreach ($queryvars as $k => $v) { $qs[] = "{$k}={$v}"; } $action = $page . implode("&", $qs); //limitstart gets added in the pageination model $action = preg_replace("/limitstart{$this->_id}=(.*)?(&|)/", "", $action); $action = FabrikString::rtrimword($action, "&"); $this->getFilterFormURL = JRoute::_($action); return $this->getFilterFormURL; }
/** * default email handling routine, called if no email template specified * @return string email message */ protected function _getTextEmail() { $data = $this->getEmailData(); $config = JFactory::getConfig(); $ignore = $this->getDontEmailKeys(); $message = ""; $pluginManager = FabrikWorker::getPluginManager(); $groupModels = $this->formModel->getGroupsHiarachy(); foreach ($groupModels as &$groupModel) { $elementModels = $groupModel->getPublishedElements(); foreach ($elementModels as &$elementModel) { $element = $elementModel->getElement(); // @TODO - how about adding a 'renderEmail()' method to element model, so specific element types // can render themselves? $key = !array_key_exists($element->name, $data) ? $elementModel->getFullName(false, true, false) : $element->name; if (!in_array($key, $ignore)) { $val = ''; if (is_array($data[$key])) { //repeat group data foreach ($data[$key] as $k => $v) { if (is_array($v)) { $val = implode(", ", $v); } $val .= count($data[$key]) == 1 ? ": {$v}<br />" : $k++ . ": {$v}<br />"; } } else { $val = $data[$key]; } $val = FabrikString::rtrimword($val, "<br />"); $val = stripslashes($val); // set $val to default value if empty if ($val == '') { $val = " - "; } // don't add a second ":" $label = trim(strip_tags($element->label)); $message .= $label; if (strlen($label) != 0 && JString::strpos($label, ':', JString::strlen($label) - 1) === false) { $message .= ':'; } $message .= "<br />" . $val . "<br /><br />"; } } } $message = JText::_('Email from') . ' ' . $config->getValue('sitename') . '<br />' . JText::_('Message') . ':' . "<br />===================================<br />" . "<br />" . stripslashes($message); return $message; }
/** * Fabrik Search method * * The sql must return the following fields that are * used in a common display routine: href, title, section, created, text, * browsernav * * @param string $text Target search string * @param JRegistry $params Search plugin params * @param string $phrase Matching option, exact|any|all * @param string $ordering Option, newest|oldest|popular|alpha|category * * @return array */ public static function onDoContentSearch($text, $params, $phrase = '', $ordering = '') { $app = JFactory::getApplication(); $fbConfig = JComponentHelper::getParams('com_fabrik'); $package = $app->getUserState('com_fabrik.package', 'fabrik'); if (defined('COM_FABRIK_SEARCH_RUN')) { return; } $input = $app->input; define('COM_FABRIK_SEARCH_RUN', true); JModelLegacy::addIncludePath(COM_FABRIK_FRONTEND . '/models', 'FabrikFEModel'); $user = JFactory::getUser(); $db = FabrikWorker::getDbo(true); require_once JPATH_SITE . '/components/com_content/helpers/route.php'; // Load plugin params info $limit = $params->def('search_limit', 50); $text = trim($text); if ($text == '') { return array(); } switch ($ordering) { case 'oldest': $order = 'a.created ASC'; break; case 'popular': $order = 'a.hits DESC'; break; case 'alpha': $order = 'a.title ASC'; break; case 'category': $order = 'b.title ASC, a.title ASC'; $morder = 'a.title ASC'; break; case 'newest': default: $order = 'a.created DESC'; break; } // Set heading prefix $headingPrefix = $params->get('include_list_title', true); // Get all tables with search on $query = $db->getQuery(true); $query->select('id')->from('#__{package}_lists')->where('published = 1'); $db->setQuery($query); $list = array(); $ids = $db->loadColumn(); $section = $params->get('search_section_heading'); $urls = array(); // $$$ rob remove previous search results? $input->set('resetfilters', 1); // Ensure search doesn't go over memory limits $memory = ini_get('memory_limit'); $memory = (int) FabrikString::rtrimword($memory, 'M') * 1000000; $usage = array(); $memSafety = 0; $listModel = JModelLegacy::getInstance('list', 'FabrikFEModel'); $app = JFactory::getApplication(); foreach ($ids as $id) { // Re-ini the list model (was using reset() but that was flaky) $listModel = JModelLegacy::getInstance('list', 'FabrikFEModel'); // $$$ geros - http://fabrikar.com/forums/showthread.php?t=21134&page=2 $key = 'com_' . $package . '.list' . $id . '.filter.searchall'; $app->setUserState($key, null); $used = memory_get_usage(); $usage[] = memory_get_usage(); if (count($usage) > 2) { $diff = $usage[count($usage) - 1] - $usage[count($usage) - 2]; if ($diff + $usage[count($usage) - 1] > $memory - $memSafety) { $app->enqueueMessage('Some records were not searched due to memory limitations'); break; } } // $$$rob set this to current table // Otherwise the fabrik_list_filter_all var is not used $input->set('listid', $id); $listModel->setId($id); $searchFields = $listModel->getSearchAllFields(); if (empty($searchFields)) { continue; } $filterModel = $listModel->getFilterModel(); $requestKey = $filterModel->getSearchAllRequestKey(); // Set the request variable that fabrik uses to search all records $input->set($requestKey, $text, 'post'); $table = $listModel->getTable(); $fabrikDb = $listModel->getDb(); $params = $listModel->getParams(); // Test for swap too boolean mode $mode = $input->get('searchphrase', '') === 'all' ? 0 : 1; // $params->set('search-mode-advanced', true); $params->set('search-mode-advanced', $mode); // The table shouldn't be included in the search results or we have reached the max number of records to show. if (!$params->get('search_use') || $limit <= 0) { continue; } // Set the table search mode to OR - this will search ALL fields with the search term $params->set('search-mode', 'OR'); $allrows = $listModel->getData(); $elementModel = $listModel->getFormModel()->getElement($params->get('search_description', $table->label), true); $descname = is_object($elementModel) ? $elementModel->getFullName() : ''; $elementModel = $listModel->getFormModel()->getElement($params->get('search_title', 0), true); $title = is_object($elementModel) ? $elementModel->getFullName() : ''; /** * $$$ hugh - added date element ... always use raw, as anything that isn't in * standard MySQL format will cause a fatal error in J!'s search code when it does the JDate create */ $elementModel = $listModel->getFormModel()->getElement($params->get('search_date', 0), true); $date_element = is_object($elementModel) ? $elementModel->getFullName() : ''; if (!empty($date_element)) { $date_element .= '_raw'; } $aAllowedList = array(); $pk = $table->db_primary_key; foreach ($allrows as $group) { foreach ($group as $oData) { $pkval = $oData->__pk_val; if ($app->isAdmin() || $params->get('search_link_type') === 'form') { $href = $oData->fabrik_edit_url; } else { $href = $oData->fabrik_view_url; } if (!in_array($href, $urls)) { $limit--; $urls[] = $href; $o = new stdClass(); if (isset($oData->{$title})) { $o->title = $headingPrefix ? $table->label . ' : ' . $oData->{$title} : $oData->{$title}; } else { $o->title = $table->label; } $o->_pkey = $table->db_primary_key; $o->section = $section; $o->href = $href; // Need to make sure it's a valid date in MySQL format, otherwise J!'s code will pitch a fatal error if (isset($oData->{$date_element}) && FabrikString::isMySQLDate($oData->{$date_element})) { $o->created = $oData->{$date_element}; } else { $o->created = ''; } $o->browsernav = 2; if (isset($oData->{$descname})) { $o->text = $oData->{$descname}; } else { $o->text = ''; } $o->title = strip_tags($o->title); $aAllowedList[] = $o; } } $list[] = $aAllowedList; } } $allList = array(); foreach ($list as $li) { if (is_array($li) && !empty($li)) { $allList = array_merge($allList, $li); } } return $allList; }
/** * Run Joomla content plugins over text * * @param string &$text Content * * @return void * * @since 3.0.7 */ public static function runContentPlugins(&$text) { $app = JFactory::getApplication(); $input = $app->input; $opt = $input->get('option'); $view = $input->get('view'); $format = $input->get('format'); $input->set('option', 'com_content'); $input->set('view', 'article'); $input->set('format', 'html'); jimport('joomla.html.html.content'); /** * J!'s email cloaking will cloak email addresses in form inputs, which is a Bad Thing<tm>. * What we really need to do is work out a way to prevent ONLY cloaking of emails in form inputs, * but that's not going to be trivial. So band-aid is to turn it off in form and list views, so * addresses only get cloaked in details view. * In addition, if we are in a details PDF view we should not run the email cloak plugin. */ if ($view !== 'details' || $input->get('format') === 'pdf') { $text .= '{emailcloak=off}'; } $text = JHTML::_('content.prepare', $text); if ($view !== 'details' || $input->get('format') === 'pdf') { $text = FabrikString::rtrimword($text, '{emailcloak=off}'); } $input->set('option', $opt); $input->set('view', $view); $input->set('format', $format); }
/** * $$$ rob 19/10/2011 now called before formatData() from getData() as otherwise element tips (created in element->renderListData()) * only contained first merged records data and not all merged records * * Collapses 'repeated joined' rows into a single row. * If a group is not repeating we just use the first row's data (as subsequent rows will contain the same data * Otherwise if the group is repeating we append each repeated record's data into the first row's data * All rows execpt the first row for each group are then unset (as unique subsequent row's data will be contained within * the first row) * @param array $data */ function formatForJoins(&$data) { $merge = $this->mergeJoinedData(); if (empty($merge)) { return; } $listid = $this->getTable()->id; $dbprimaryKey = FabrikString::safeColNameToArrayKey($this->getTable()->db_primary_key); $formModel = $this->getFormModel(); FabrikHelperHTML::debug($data, 'render:before formatForJoins'); $count = count($data); $last_pk = ''; $last_i = 0; $count = count($data); $can_repeats = array(); $remove = array(); for ($i = 0; $i < $count; $i++) { // $$$rob if rendering J article in PDF format __pk_val not in pdf table view //$next_pk = isset($data[$groupk][$i]->__pk_val) ? $data[$groupk][$i]->__pk_val : $data[$groupk][$i]->id; $next_pk = isset($data[$i]->__pk_val) ? $data[$i]->__pk_val : $data[$i]->{$dbprimaryKey}; if (!empty($last_pk) && $last_pk == $next_pk) { foreach ($data[$i] as $key => $val) { $origKey = $key; $tmpkey = FabrikString::rtrimword($key, '_raw'); // $$$ hugh - had to cache this stuff, because if you have a lot of rows and a lot of elements, // doing this many hundreds of times causes huge slowdown, exceeding max script execution time! // And we really only need to do it once for the first row. if (!isset($can_repeats[$tmpkey])) { $elementModel = $formModel->getElement($tmpkey); // $$$ rob - testing for linking join which is repeat but linked join which is not - still need separate info from linked to join //$can_repeats[$tmpkey] = $elementModel ? ($elementModel->getGroup()->canRepeat()) : 0; $can_repeats[$tmpkey] = $elementModel ? $elementModel->getGroup()->canRepeat() || $elementModel->getGroup()->isJoin() : 0; //$can_repeats[$tmpkey] = 0; } if (isset($data[$last_i]->{$key}) && $can_repeats[$tmpkey]) { // $$$ rob - what about data like yes/no where each viewable option needs to be shown? // $$$ rob - yeah commenting this out, not a good idea - as other cols for this record may have // different data so you end up with this col having 3 entries and the next col having four and you can't // see the correlation between the two sets of data. //if ($data[$groupk][$last_i]->$key != $val) { // $$$ rob meant that only one link to details was shown in admin - dont see the point in that //if (preg_match("#\W+fabrik___rowlink.*\W+listid=$listid\W#",$val)) { //continue; //} if ($origKey == $tmpkey) { // $$$ rob - this was just appending data with a <br> but as we do thie before the data is formatted // it was causing all sorts of issues for list rendering of links, dates etc. So now turn the data into // an array and at the end of this method loop over the data to encode the array into a json object. // The raw data is not altererd at the moment - not sure that that seems correct but can't see any issues // with it currently $data[$last_i]->{$key} = (array) $data[$last_i]->{$key}; array_push($data[$last_i]->{$key}, $val); } else { $json = $val; $data[$last_i]->{$origKey} = json_encode($json); } } } $remove[] = $i; continue; } else { $last_i = $i; // $$$rob if rendering J article in PDF format __pk_val not in pdf table view $last_pk = $next_pk; } // $$$ rob ensure that we have a sequental set of keys otherwise ajax json will turn array into object $data = array_values($data); } for ($c = count($remove) - 1; $c >= 0; $c--) { unset($data[$remove[$c]]); } // $$$ rob loop over any data that was merged into an array and turn that into a json object foreach ($data as $gkey => $d) { foreach ($d as $k => $v) { if (is_array($v)) { foreach ($v as &$v2) { $v2 = FabrikWorker::JSONtoData($v2); } $v = json_encode($v); $data[$gkey]->{$k} = $v; } } } $data = array_values($data); }