I am trying to create an API using CakePHP that allows searching. For example:
http://localhost:8765/users/index/?username=admin
Which should return users with usernames equal to 'admin':
users: [
{
id: 3,
username: "admin",
image: "",
firstName: "Jeremy",
lastName: "Quick",
userTypeId: 1,
email: "jrquick#test.com",
groupId: 2
}
]
So far, I have been able to accomplish this with a custom get() in the AppController which checks the $_GET and $_POST array for fields on the model. But the function is getting more and more complicated and verging on hackiness as I add more functionality (range search, collection search, and child table filtering). Is there a better, more CakePHP friendly way of accomplishing this? Whether through pure cakephp or a plugin?
I think you want to use the Cakephp Search plugin. It has good documentation and uses a PRG method similar to what you are currently using. It will function just fine through an API. Here's a link to that plugin: github.com/FriendsOfCake/search
If You want to create API, You should create a MiddleWare at first, which will filter tokens, keys etc. to make Your API more protected.
Also, You should use Plugins and RESTful Routes, which will be very helpful.
To create plugin:
bin/cake bake plugin Api
Create Model:
bin/cake bake model Users
For example, You want to have UsersController in Api plugin:
<?php
namespace Api\Controller;
/* This controller will be extending like parent */
use Api\Controller\AppController;
use Api\Model\Table\UsersTable;
/**
* Class UsersController
* #package Api\Controller
* #property UsersTable $Users
*
*/
class UsersController extends AppController{
public function initialize(){
parent::initialize();
$this->loadModel('Api.Users');
}
public function getUser($field ='username', $username = false){
return $this->_jsonResponse(
[
'users' => $this->Users->findBy{ucfirst($field)}($username)
];
)
}
public function _jsonResponse($data, $code = 200){
$this->response->type('json');
$this->response->statusCode($code);
$this->response->body(
json_encode((array)$data)
);
return $this->response;
}
}
Route will be descripbed in plugins/config/routes.php. You need to create Route Map for API in /api path:
function (RouteBuilder $routes) {
$routes->resources('Users', [
'map' => [
'get-user' => [
'action' => 'getUser',
'method' => 'GET' /* Can be also as array ['GET', 'PUT', 'DELETE'] */
]
]
]);
$routes->fallbacks('DashedRoute');
}
If You have frequent calls, You should use Cache that calls and save them for some amount of time. For example - 10 minutes. Cache can be configured in config/app.php. You should create separate Cache prefix and use it in this way:
<?php
use Cake\Cache\Cache;
$data = [];
Cache::write('some_key', $data, 'prefix')
dump(Cache::read('some_key', 'prefix'));
It's just examples. If You will face some problems - just tell in comments :)
Also, use Migrations and Seeds instead dumping sql files
If You want to filter data from Middleware - You should have Event as argument, that will contain request data ($_POST) and request query($_GET) variables that You will be able to easily handle with.
From controllers You need to use $this->request->data to get POST data array or $this->request->query to get GET data array.
I haven't found an answer that seems to work exactly how I am wanting, so here is my current get command. It does allow searching by fields, join tables, greater/less than, in array, and like.
If anyone has recommendations to improve I will update my answer.
public function get() {
$response = new Response();
$model = $this->loadModel();
$fields = $this->getFields();
$joins = $this->getJoins();
$order = $this->getOrder();
$params = $this->getParams();
$limit = $this->getLimit();
$offset = $this->getOffset();
$query = $model->find('all', ['fields' => $fields]);
if (!is_null($joins)) {
$query->contain($joins);
}
if (sizeof($params['equals']) > 0) {
foreach ($params['equals'] as $equalsKey=>$equalsValue) {
$query->andWhere([$equalsKey => $equalsValue]);
}
}
if (sizeof($params['or']) > 0) {
foreach ($params['or'] as $orKey=>$orValue) {
$query->orWhere([$orKey => $orValue]);
}
}
if (!is_null($order)) {
$query->order([$order]);
}
if (!is_null($limit)) {
$query->limit($limit);
if (!is_null($offset)) {
$query->offset($offset);
}
}
$response->addMessage($model->table(), $query->toArray());
$response->respond($this);
}
private function getFields() {
$fields = [];
if (array_key_exists('fields', $_GET)) {
$fields = explode(',', $_GET['fields']);
}
return $fields;
}
private function getLimit() {
$limit = null;
if (array_key_exists('limit', $_GET)) {
$limit = $_GET['limit'];
}
return $limit;
}
private function getJoins() {
$joins = null;
if (array_key_exists('joins', $_GET)) {
$joins = explode(',', $_GET['joins']);
}
return $joins;
}
private function getOffset() {
$offset = null;
if (array_key_exists('offset', $_GET)) {
$offset = $_GET['limit'];
}
return $offset;
}
private function getOrder() {
$results = [];
if (array_key_exists('order', $_GET)) {
$orders = explode(',', $_GET['order']);
foreach ($orders as $order) {
$sign = substr($order, 0, 1);
$direction = 'ASC';
if (in_array($sign, ['+', '-'])) {
if ($sign === '-') {
$direction = 'DESC';
}
$order = substr($order, 1);
}
$result = $order;
if (strpos($result, '.') === false) {
$result = $this->loadModel()->alias() . '.' . $order;
}
$result = $result . ' ' . $direction;
$results[] = $result;
}
}
return (sizeof($results) == 0) ? null : implode(',', $results);
}
private function getParams() {
$params = [
'equals' => [],
'or' => []
];
$parentModel = $this->loadModel();
$array = array_merge($_GET, $_POST);
foreach ($array as $field=>$value) {
$comparisonType = 'equals';
$operator = substr($field, strlen($field) - 1);
if (in_array($operator, ['!', '>', '<'])) {
$field = substr($field, 0, strlen($field) - 1);
$operator .= '=';
} else if (in_array($operator, ['|'])) {
$field = substr($field, 0, strlen($field) - 1);
$comparisonType = 'or';
$operator = '=';
} else if (in_array($operator, ['%'])) {
$field = substr($field, 0, strlen($field) - 1);
$operator = 'LIKE';
$value = '%'.$value.'%';
} else {
$operator = '=';
}
if ($value == 'null') {
$operator = (strpos($operator, '!') === false) ? 'IS' : 'IS NOT';
$value = null;
}
$field = str_replace('_', '.', $field);
if (strpos($field, '.') === false) {
$alias = $parentModel->alias();
} else {
$fieldExplosion = explode('.', $field);
$alias = $fieldExplosion[0];
$field = $fieldExplosion[1];
}
$model = null;
if ($parentModel->alias() !== $alias) {
$association = $parentModel->associations()->get($alias);
if (!is_null($association)) {
$model = $this->loadModel($association->className());
}
} else {
$model = $parentModel;
}
if (!is_null($model)) {
if ($model->hasField(rtrim($field, 's')) && !$model->hasField($field)) {
$field = rtrim($field, 's');
$value = '(' . $value . ')';
$operator = ' IN';
}
if ($model->hasField($field)) {
$params[$comparisonType][$alias.'.'.$field . ' ' . $operator] = $value;
}
}
}
return $params;
}
Related
So i try to make a hooking API like wordpress add_filter and apply_filters,
So this is my implementation
My problem is that apply_filters does not filter the hook
$hook = new Hook();
$hook->add_filter('filter',function($test) {
return ' stackoverflow';
});
$hook->add_filter('filter',function($test) {
return $test .' world';
},1);
echo $hook->apply_filters('filter','hello');
// Result is hello world
What's wrong with my code, I want to result like this
hello world stackoverflow
For adding filters
public function add_filter(string $tag,mixed $object,int $priority = 10,int $args_limit = 1): void
{
$hooks = static::$hooks;
if(isset($hooks[$tag])) {
static::$hooks[$tag]['sorted'] = false;
static::$hooks[$tag]['priority'][] = $priority;
static::$hooks[$tag]['object'][] = $object;
static::$hooks[$tag]['args_limit'][] = $args_limit;
} else {
static::$hooks[$tag] = [
'sorted' => true,
'priority' => [$priority],
'object' => [$object],
'args_limit' => [$args_limit]
];
}
}
and for applying the filters
public function apply_filters(string $tag,mixed $value,mixed ...$args): mixed
{
$hooks = static::$hooks;
// Shift value to args
array_unshift($args,$value);
$num_args = count($args);
if(isset($hooks[$tag])) {
$hooks = $hooks[$tag];
if(!$hooks['sorted']) {
// Sort filter by priority
array_multisort(
$hooks['priority'],
SORT_NUMERIC,
$hooks['object'],
$hooks['args_limit']
);
$hooks['sorted'] = true;
}
foreach($hooks['object'] as $key => $object) {
$args_limit = $hooks['args_limit'][$key];
if(0 === $args_limit) {
$value = call_user_func($object);
} elseif($args_limit >= $num_args) {
$value = call_user_func_array($object,$args);
} else {
// Slice arguments if not meet from the second statement
$value = call_user_func_array($object,array_slice($args,0,$args_limit));
}
}
}
return $value;
}
So I try to look wordpress core code but the too complicated.
Thanks
Finally solved it! , I just forgot that $value doesn't pass to the callbacks
Here's the fix, for future references
public function apply_filters(string $tag,mixed $value,mixed ...$args): mixed
{
$hooks = static::$hooks;
// +1 for $value parameter
$num_args = count($args) + 1;
if(isset($hooks[$tag])) {
$hooks = $hooks[$tag];
if(!$hooks['sorted']) {
// Sort filter by priority
array_multisort(
$hooks['priority'],
SORT_NUMERIC,
$hooks['object'],
$hooks['args_limit']
);
$hooks['sorted'] = true;
}
foreach($hooks['object'] as $key => $object) {
$args_limit = $hooks['args_limit'][$key];
if(0 === $args_limit) {
$value = call_user_func($object);
} elseif($args_limit >= $num_args) {
$value = call_user_func($object,$value,...$args);
} else {
// Slice arguments if not meet from the second statement
$slice = array_slice($args,0,$args_limit);
$value = call_user_func($object,$value,...$slice);
}
}
}
return $value;
}
I have to make filtering by date in reqest. I know about existing yii\data\DataFilter class, so I used it to solve the issue.
Actual request URL(example): https://api.site.com/module/post?filter[from_date][>=]=100
Don't worry about value 100, we use UNIX in our policy.
I use yii\rest\ActiveController to perform actions, so I defined dataFilter property in [[actions()]]:
public function actions()
{
$actions = parent::actions();
$actions['index']['dataFilter'] = [
'class' => DataFilter::class,
'attributeMap' => [
'from_date' => 'date_success',
'to_date' => 'date_success',
],
'searchModel' => function () {
return (new DynamicModel(['from_date', 'to_date']))
->addRule(['from_date', 'to_date'], 'integer', ['min' => 0]);
},
];
return $actions;
}
After the query is completed, an empty array is returned []. I traced SQL queries:
As you can see there is "EQUALS" operand instead ">", which defined in query-string ?filter[from_date][>]=100.
By default in yii\rest\IndexAction variable $query calls method where($filter):
/*
After successful filter build $filter variable becomes:
$filter = [
'date_success' => [
'>' => 100,
],
]
*/
$query = $modelClass::find();
if (!empty($filter)) {
$query->andWhere($filter);
}
Why it's happens? I debugged the code, and I find one interesting feature! In yii\db\conditions\HashConditionBuilder:
public function build(ExpressionInterface $expression, array &$params = [])
{
$hash = $expression->getHash();
$parts = [];
foreach ($hash as $column => $value) {
if (ArrayHelper::isTraversable($value) || $value instanceof Query) {
// IN condition
// Executing will be here.
// Yii2 thinks thats 'IN' condition, and builds as 'IN'.
$parts[] = $this->queryBuilder->buildCondition(new InCondition($column, 'IN', $value), $params);
} else {
if (strpos($column, '(') === false) {
$column = $this->queryBuilder->db->quoteColumnName($column);
}
if ($value === null) {
$parts[] = "$column IS NULL";
} elseif ($value instanceof ExpressionInterface) {
$parts[] = "$column=" . $this->queryBuilder->buildExpression($value, $params);
} else {
$phName = $this->queryBuilder->bindParam($value, $params);
$parts[] = "$column=$phName";
}
}
}
return count($parts) === 1 ? $parts[0] : '(' . implode(') AND (', $parts) . ')';
}
This problem repeats with different 'conditionOperators', the result absolutely same.
filter[from_date][=]=100
filter[from_date][<]=100
filter[from_date][gt]=100
filter[from_date][gte]=100
There were one sticky difference between ActiveDataFilter and DataFilter. It concluse in method [[buildInternal()]].
DataFilter method:
protected function buildInternal()
{
return $this->normalize(false);
}
ActiveDataFilter method:
protected function buildInternal()
{
$filter = $this->normalize(false);
if (empty($filter)) {
return [];
}
return $this->buildCondition($filter);
}
By calling $this->buildCondition($filter) ActiveDataFilter passes $filter variable and then applyes QueryBilders, so $filter variable becomes:
$filter = ['>', 'date_success', 100];
Here is the scenario, and let me start off saying any help would be a god-send, I have cloned the Article Category module inside Joomla! Basically changed all the articles_category to breed_articles (for my purpose). This worked fine, where I am stuck at is where in the module code can I define a specific category to pull articles from.
I know I can do this in the backend but I am working on a dynamic way to pull articles by categories and need to define the category in the module code. That being said, I will also need to pull the categoies by the slug not id.
Where I have been looking is the helper.php file in the module and I believe that I am on the right path there. I have tried replacing a few things and tracing the code but I am not very familiar with Joomla!
helper.php
$com_path = JPATH_SITE.'/components/com_content/';
require_once $com_path.'router.php';
require_once $com_path.'helpers/route.php';
JModelLegacy::addIncludePath($com_path . '/models', 'ContentModel');
abstract class modBreedArticlesHelper
{
public static function getList(&$params)
{
// Get an instance of the generic articles model
$articles = JModelLegacy::getInstance('Articles', 'ContentModel', array('ignore_request' => true));
// Set application parameters in model
$app = JFactory::getApplication();
$appParams = $app->getParams();
$articles->setState('params', $appParams);
// Set the filters based on the module params
$articles->setState('list.start', 0);
$articles->setState('list.limit', (int) $params->get('count', 0));
$articles->setState('filter.published', 1);
// Access filter
$access = !JComponentHelper::getParams('com_content')->get('show_noauth');
$authorised = JAccess::getAuthorisedViewLevels(JFactory::getUser()->get('id'));
$articles->setState('filter.access', $access);
// Prep for Normal or Dynamic Modes
$mode = $params->get('mode', 'normal');
switch ($mode)
{
case 'dynamic':
$option = $app->input->get('option');
$view = $app->input->get('view');
if ($option === 'com_content') {
switch($view)
{
case 'category':
$catids = array($app->input->getInt('id'));
break;
case 'categories':
$catids = array($app->input->getInt('id'));
break;
case 'article':
if ($params->get('show_on_article_page', 1)) {
$article_id = $app->input->getInt('id');
$catid = $app->input->getInt('catid');
if (!$catid) {
// Get an instance of the generic article model
$article = JModelLegacy::getInstance('Article', 'ContentModel', array('ignore_request' => true));
$article->setState('params', $appParams);
$article->setState('filter.published', 1);
$article->setState('article.id', (int) $article_id);
$item = $article->getItem();
$catids = array($item->catid);
}
else {
$catids = array($catid);
}
}
else {
// Return right away if show_on_article_page option is off
return;
}
break;
case 'featured':
default:
// Return right away if not on the category or article views
return;
}
}
else {
// Return right away if not on a com_content page
return;
}
break;
case 'normal':
default:
$catids = $params->get('catid');
$articles->setState('filter.category_id.include', (bool) $params->get('category_filtering_type', 1));
break;
}
// Category filter
if ($catids) {
if ($params->get('show_child_category_articles', 0) && (int) $params->get('levels', 0) > 0) {
// Get an instance of the generic categories model
$categories = JModelLegacy::getInstance('Categories', 'ContentModel', array('ignore_request' => true));
$categories->setState('params', $appParams);
$levels = $params->get('levels', 1) ? $params->get('levels', 1) : 9999;
$categories->setState('filter.get_children', $levels);
$categories->setState('filter.published', 1);
$categories->setState('filter.access', $access);
$additional_catids = array();
foreach($catids as $catid)
{
$categories->setState('filter.parentId', $catid);
$recursive = true;
$items = $categories->getItems($recursive);
if ($items)
{
foreach($items as $category)
{
$condition = (($category->level - $categories->getParent()->level) <= $levels);
if ($condition) {
$additional_catids[] = $category->id;
}
}
}
}
$catids = array_unique(array_merge($catids, $additional_catids));
}
$articles->setState('filter.category_id', $catids);
}
// Ordering
$articles->setState('list.ordering', $params->get('article_ordering', 'a.ordering'));
$articles->setState('list.direction', $params->get('article_ordering_direction', 'ASC'));
// New Parameters
$articles->setState('filter.featured', $params->get('show_front', 'show'));
$articles->setState('filter.author_id', $params->get('created_by', ""));
$articles->setState('filter.author_id.include', $params->get('author_filtering_type', 1));
$articles->setState('filter.author_alias', $params->get('created_by_alias', ""));
$articles->setState('filter.author_alias.include', $params->get('author_alias_filtering_type', 1));
$excluded_articles = $params->get('excluded_articles', '');
if ($excluded_articles) {
$excluded_articles = explode("\r\n", $excluded_articles);
$articles->setState('filter.article_id', $excluded_articles);
$articles->setState('filter.article_id.include', false); // Exclude
}
$date_filtering = $params->get('date_filtering', 'off');
if ($date_filtering !== 'off') {
$articles->setState('filter.date_filtering', $date_filtering);
$articles->setState('filter.date_field', $params->get('date_field', 'a.created'));
$articles->setState('filter.start_date_range', $params->get('start_date_range', '1000-01-01 00:00:00'));
$articles->setState('filter.end_date_range', $params->get('end_date_range', '9999-12-31 23:59:59'));
$articles->setState('filter.relative_date', $params->get('relative_date', 30));
}
// Filter by language
$articles->setState('filter.language', $app->getLanguageFilter());
$items = $articles->getItems();
// Display options
$show_date = $params->get('show_date', 0);
$show_date_field = $params->get('show_date_field', 'created');
$show_date_format = $params->get('show_date_format', 'Y-m-d H:i:s');
$show_category = $params->get('show_category', 0);
$show_hits = $params->get('show_hits', 0);
$show_author = $params->get('show_author', 0);
$show_introtext = $params->get('show_introtext', 0);
$introtext_limit = $params->get('introtext_limit', 100);
// Find current Article ID if on an article page
$option = $app->input->get('option');
$view = $app->input->get('view');
if ($option === 'com_content' && $view === 'article') {
$active_article_id = $app->input->getInt('id');
}
else {
$active_article_id = 0;
}
// Prepare data for display using display options
foreach ($items as &$item)
{
$item->slug = $item->id.':'.$item->alias;
$item->catslug = $item->catid ? $item->catid .':'.$item->category_alias : $item->catid;
if ($access || in_array($item->access, $authorised))
{
// We know that user has the privilege to view the article
$item->link = JRoute::_(ContentHelperRoute::getArticleRoute($item->slug, $item->catslug));
}
else
{
$app = JFactory::getApplication();
$menu = $app->getMenu();
$menuitems = $menu->getItems('link', 'index.php?option=com_users&view=login');
if (isset($menuitems[0]))
{
$Itemid = $menuitems[0]->id;
}
elseif ($app->input->getInt('Itemid') > 0)
{
// Use Itemid from requesting page only if there is no existing menu
$Itemid = $app->input->getInt('Itemid');
}
$item->link = JRoute::_('index.php?option=com_users&view=login&Itemid='.$Itemid);
}
// Used for styling the active article
$item->active = $item->id == $active_article_id ? 'active' : '';
$item->displayDate = '';
if ($show_date) {
$item->displayDate = JHTML::_('date', $item->$show_date_field, $show_date_format);
}
if ($item->catid) {
$item->displayCategoryLink = JRoute::_(ContentHelperRoute::getCategoryRoute($item->catid));
$item->displayCategoryTitle = $show_category ? ''.$item->category_title.'' : '';
}
else {
$item->displayCategoryTitle = $show_category ? $item->category_title : '';
}
$item->displayHits = $show_hits ? $item->hits : '';
$item->displayAuthorName = $show_author ? $item->author : '';
if ($show_introtext) {
$item->introtext = JHtml::_('content.prepare', $item->introtext, '', 'mod_articles_category.content');
$item->introtext = self::_cleanIntrotext($item->introtext);
}
$item->displayIntrotext = $show_introtext ? self::truncate($item->introtext, $introtext_limit) : '';
$item->displayReadmore = $item->alternative_readmore;
}
return $items;
}
public static function _cleanIntrotext($introtext)
{
$introtext = str_replace('<p>', ' ', $introtext);
$introtext = str_replace('</p>', ' ', $introtext);
$introtext = strip_tags($introtext, '<a><em><strong>');
$introtext = trim($introtext);
return $introtext;
}
/**
* Method to truncate introtext
*
* The goal is to get the proper length plain text string with as much of
* the html intact as possible with all tags properly closed.
*
* #param string $html The content of the introtext to be truncated
* #param integer $maxLength The maximum number of charactes to render
*
* #return string The truncated string
*/
public static function truncate($html, $maxLength = 0)
{
$baseLength = strlen($html);
$diffLength = 0;
// First get the plain text string. This is the rendered text we want to end up with.
$ptString = JHtml::_('string.truncate', $html, $maxLength, $noSplit = true, $allowHtml = false);
for ($maxLength; $maxLength < $baseLength;)
{
// Now get the string if we allow html.
$htmlString = JHtml::_('string.truncate', $html, $maxLength, $noSplit = true, $allowHtml = true);
// Now get the plain text from the html string.
$htmlStringToPtString = JHtml::_('string.truncate', $htmlString, $maxLength, $noSplit = true, $allowHtml = false);
// If the new plain text string matches the original plain text string we are done.
if ($ptString == $htmlStringToPtString)
{
return $htmlString;
}
// Get the number of html tag characters in the first $maxlength characters
$diffLength = strlen($ptString) - strlen($htmlStringToPtString);
// Set new $maxlength that adjusts for the html tags
$maxLength += $diffLength;
if ($baseLength <= $maxLength || $diffLength <= 0)
{
return $htmlString;
}
}
return $html;
}
public static function groupBy($list, $fieldName, $article_grouping_direction, $fieldNameToKeep = null)
{
$grouped = array();
if (!is_array($list)) {
if ($list == '') {
return $grouped;
}
$list = array($list);
}
foreach($list as $key => $item)
{
if (!isset($grouped[$item->$fieldName])) {
$grouped[$item->$fieldName] = array();
}
if (is_null($fieldNameToKeep)) {
$grouped[$item->$fieldName][$key] = $item;
}
else {
$grouped[$item->$fieldName][$key] = $item->$fieldNameToKeep;
}
unset($list[$key]);
}
$article_grouping_direction($grouped);
return $grouped;
}
public static function groupByDate($list, $type = 'year', $article_grouping_direction, $month_year_format = 'F Y')
{
$grouped = array();
if (!is_array($list)) {
if ($list == '') {
return $grouped;
}
$list = array($list);
}
foreach($list as $key => $item)
{
switch($type)
{
case 'month_year':
$month_year = JString::substr($item->created, 0, 7);
if (!isset($grouped[$month_year])) {
$grouped[$month_year] = array();
}
$grouped[$month_year][$key] = $item;
break;
case 'year':
default:
$year = JString::substr($item->created, 0, 4);
if (!isset($grouped[$year])) {
$grouped[$year] = array();
}
$grouped[$year][$key] = $item;
break;
}
unset($list[$key]);
}
$article_grouping_direction($grouped);
if ($type === 'month_year') {
foreach($grouped as $group => $items)
{
$date = new JDate($group);
$formatted_group = $date->format($month_year_format);
$grouped[$formatted_group] = $items;
unset($grouped[$group]);
}
}
return $grouped;
}
}
It looks like my issue was really specific to the project I am working on. If anyone happens to find this or wants to accomplish something similar, read on.
Decided to accomplish what I was doing using a JDatabase query. To retrieve the articles using the category alias, I queried the DB to match the alias I was giving the query to the category ID. Then joined the content table to get the article information.
All the information you need to make a proper JDatabase query can be found here: http://docs.joomla.org/Accessing_the_database_using_JDatabase
Codeigniter when i submit more than one option of form_multiselect(), Only just the last one that saved on database.
in my view :
<label>Trimestres :</label>
<div class="controls" >
<?php $options = array(
'trim1' => ' Premier trimestre (Janv,Fév,Mars)',
'trim2' => ' Deuxiéme trimestre (Avril,Mai,Juin)',
'trim3' => ' Troisiéme trimestre (Juill,Aout,Sept)',
'trim4' => ' Quatriéme trimestre (Oct,Nov,Déc)',
);
echo form_multiselect('trimestres', $options , $this->input->post('trimestres') ? $this->input->post('trimestres') : $participant_sport->trimestres, 'id="trim"'); ?>
</div>
</div>
in my controller :
public function inscriresport ($id = NULL)
{
// Fetch a participant or set a new one
if ($id) {
$this->data['participant_sport'] = $this->participantsport_m->get($id);
count($this->data['participant_sport']) || $this->data['errors'][] = 'participant non trouvé';
}
else {
$this->data['participant_sport'] = $this->participantsport_m->get_new();
}
// Process the form
$this->participantsport_m->array_from_post(array('matricule', 'nom', 'prenom', 'beneficiaire', 'sexe', 'telephone', 'date_naissance', 'date_inscription_sport', 'trimestres' ,'sport_montant_paye', 'sport_debut_periode', 'sport_fin_periode'));
$this->participantsport_m->save($data, $id);
redirect('admin/agent/profile/3608');
}
// Load the view
$this->data['subview'] = 'admin/agent/inscriresport';
$this->load->view('admin/_layout_main', $this->data);
}
The function array_from_post() is defined on application\core\MY_Model.php :
public function array_from_post($fields){
$data = array();
foreach ($fields as $field) {
$data[$field] = $this->input->post($field);
}
return $data;
}
in my model :
public function get_new()
{
$participant_sport = new stdClass();
$participant_sport->matricule = '';
$participant_sport->nom = '';
$participant_sport->prenom = '';
$participant_sport->beneficiaire = '';
$participant_sport->sexe = '';
$participant_sport->telephone = '';
$participant_sport->date_naissance = '';
$participant_sport->date_inscription_sport = '';
$participant_sport->trimestres = '';
$participant_sport->sport_montant_paye = '';
$participant_sport->sport_debut_periode = '';
$participant_sport->sport_fin_periode = '';
return $participant_sport;
}
Any help Please? i think that must be an array but i don't know how to do it?
i thing that i must do something like that :
foreach($_POST["strategylist[]"] as $s) {
# do the insert here, but use $s instead of $_POST["strategylist[]"]
$result=mysql_query("INSERT INTO sslink (study_id, strategyname) " .
"VALUES ('$id','" . join(",",$s) . "')")
or die("Insert Error: ".mysql_error());
}
to insert more than one option selected in one row but i don't know how to do it in codeigniter
the get() function :
public function get($id = NULL, $single = FALSE){
if ($id != NULL) {
$filter = $this->_primary_filter;
$id = $filter($id);
$this->db->where($this->_primary_key, $id);
$method = 'row';
}
elseif($single == TRUE) {
$method = 'row';
}
else {
$method = 'result';
}
if (!count($this->db->ar_orderby)) {
$this->db->order_by($this->_order_by);
}
return $this->db->get($this->_table_name)->$method();
}
If select name (in HTML tag) is trimestres it will always remember last selection. Use trimestres[] as a name to get array with all selected values`
<select name="trimestres[]" multiple …
By the way:
I don't know how array_from_post() works but it has to change trimestres[] values to one string to save all of them in one column. It is hard to search/add/delete one value if all values are in one string. It is "SQL Antipattern". You could do another table in database for trimestres - one value in one row.
Edit:
It will change all arrays into string with elements connected by ,. Not tested.
public function array_from_post($fields){
$data = array();
foreach ($fields as $field) {
// print_r($this->input->post($field));
if( is_array( $this->input->post($field) ) ) {
$data[$field] = join(",", $this->input->post($field));
} else {
$data[$field] = $this->input->post($field);
}
// print_r($data[$field]);
}
return $data;
}
Edit:
Not tested.
public function inscriresport ($id = NULL)
{
// Fetch a participant or set a new one
if ($id) {
$this->data['participant_sport'] = $this->participantsport_m->get($id);
count($this->data['participant_sport']) || $this->data['errors'][] = 'participant non trouvé';
// explode to array
// print_r($this->data['participant_sport']->trimestres); // test before explode
// $this->data['participant_sport']['trimestres'] = explode(",", $this->data['participant_sport']['trimestres']);
$this->data['participant_sport']->trimestres = explode(",", $this->data['participant_sport']->trimestres);
// print_r($this->data['participant_sport']->trimestres); // test after explode
} else {
$this->data['participant_sport'] = $this->participantsport_m->get_new();
}
// rest of code
}
There is a easy way to solve this problem that I found today.
you have to serialize the $_POST['trimestres'] array just after array_form_post .
the this array will save to database as a serialize string.
public function inscriresport ($id = NULL)
{
// Fetch a participant or set a new one
if ($id) {
$this->data['participant_sport'] = $this->participantsport_m->get($id);
count($this->data['participant_sport']) || $this->data['errors'][] = 'participant non trouvé';
}
else {
$this->data['participant_sport'] = $this->participantsport_m->get_new();
}
// Process the form
$this->participantsport_m->array_from_post(array('matricule', 'nom', 'prenom', 'beneficiaire', 'sexe', 'telephone', 'date_naissance', 'date_inscription_sport', 'trimestres' ,'sport_montant_paye', 'sport_debut_periode', 'sport_fin_periode'));
$data['trimestres'] = serialize($_POST['trimestres']);
$this->participantsport_m->save($data, $id);
redirect('admin/agent/profile/3608');
}
// Load the view
$this->data['subview'] = 'admin/agent/inscriresport';
$this->load->view('admin/_layout_main', $this->data);
}
When you just need this data back form database just use php unserialize() function .
Hope it will help to do this easily ....
-thanks
It seems I've hit a wall here and could use some help
Would like to pass a MySql variable to a Joomla Module
Im using Yootheme's Widget-kit to display tweets from a search term. Works great and all but you need to enter the twitter search term in the Module back end.
Instead I would like to use a variable ( already used on the page) and pass that variable to the Twitter module so it can display the tweets I want
Here are some lines of PHP with the variable I'd like to use
$document->setTitle(JText::sprintf('COVERAGE_DATA_PLACE', $this->country->country_name, $this->city->city_name));
$text = JString::str_ireplace('%city_name%',$this->city->city_name,$text);
$this->setBreadcrumbs(array('country','city'));
Is there any way to take the "City" variable and send it to the 'word" field found in the twitter module?
Here is the Code for the twitter module
<?php
Class: TwitterWidgetkitHelper
Twitter helper class
*/
class TwitterWidgetkitHelper extends WidgetkitHelper {
/* type */
public $type;
/* options */
public $options;
/*
Function: Constructor
Class Constructor.
*/
public function __construct($widgetkit) {
parent::__construct($widgetkit);
// init vars
$this->type = strtolower(str_replace('WidgetkitHelper', '', get_class($this)));
$this->options = $this['system']->options;
// create cache
$cache = $this['path']->path('cache:');
if ($cache && !file_exists($cache.'/twitter')) {
mkdir($cache.'/twitter', 0777, true);
}
// register path
$this['path']->register(dirname(__FILE__), $this->type);
}
/*
Function: site
Site init actions
Returns:
Void
*/
public function site() {
// add translations
foreach (array('LESS_THAN_A_MINUTE_AGO', 'ABOUT_A_MINUTE_AGO', 'X_MINUTES_AGO', 'ABOUT_AN_HOUR_AGO', 'X_HOURS_AGO', 'ONE_DAY_AGO', 'X_DAYS_AGO') as $key) {
$translations[$key] = $this['system']->__($key);
}
// add stylesheets/javascripts
$this['asset']->addFile('css', 'twitter:styles/style.css');
$this['asset']->addFile('js', 'twitter:twitter.js');
$this['asset']->addString('js', sprintf('jQuery.trans.addDic(%s);', json_encode($translations)));
// rtl
if ($this['system']->options->get('direction') == 'rtl') {
$this['asset']->addFile('css', 'twitter:styles/rtl.css');
}
}
/*
Function: render
Render widget on site
Returns:
String
*/
public function render($options) {
if ($tweets = $this->_getTweets($options)) {
// get options
extract($options);
return $this['template']->render("twitter:styles/$style/template", compact('tweets', 'show_image', 'show_author', 'show_date', 'image_size'));
}
return 'No tweets found.';
}
/*
Function: _getURL
Create Twitter Query URL
Returns:
String
*/
protected function _getURL($options) {
// get options
extract($options);
// clean options
foreach (array('from_user', 'to_user', 'ref_user', 'word', 'nots', 'hashtag') as $var) {
$$var = preg_replace('/[##]/', '', preg_replace('/\s+/', ' ', trim($$var)));
}
// build query
$query = array();
if ($from_user) {
$query[] = 'from:'.str_replace(' ', ' OR from:', $from_user);
}
if ($to_user) {
$query[] = 'to:'.str_replace(' ', ' OR to:', $to_user);
}
if ($ref_user) {
$query[] = '#'.str_replace(' ', ' #', $ref_user);
}
if ($word) {
$query[] = $word;
}
if ($nots) {
$query[] = '-'.str_replace(' ', ' -', $nots);
}
if ($hashtag) {
$query[] = '#'.str_replace(' ', ' #', $hashtag);
}
$limit = min($limit ? intval($limit) : 5, 100);
// build timeline url
if ($from_user && !strpos($from_user, ' ') && count($query) == 1) {
$url = 'http://twitter.com/statuses/user_timeline/'.strtolower($from_user).'.json';
if ($limit > 15) {
$url .= '?count='.$limit;
}
return $url;
}
// build search url
if (count($query)) {
$url = 'http://search.twitter.com/search.json?q='.urlencode(implode(' ', $query));
if ($limit > 15) {
$url .= '&rpp='.$limit;
}
return $url;
}
return null;
}
/*
Function: _getTweets
Get Tweet Object Array
Returns:
Array
*/
protected function _getTweets($options) {
// init vars
$tweets = array();
// query twitter
if ($url = $this->_getURL($options)) {
if ($path = $this['path']->path('cache:twitter')) {
$file = rtrim($path, '/').sprintf('/twitter-%s.php', md5($url));
// is cached ?
if (file_exists($file)) {
$response = file_get_contents($file);
}
// refresh cache ?
if (!file_exists($file) || (time() - filemtime($file)) > 300) {
// send query
$request = $this['http']->get($url);
if (isset($request['status']['code']) && $request['status']['code'] == 200) {
$response = $request['body'];
file_put_contents($file, $response);
}
}
}
}
// create tweets
if (isset($response)) {
$response = json_decode($response, true);
if (is_array($response)) {
if (isset($response['results'])) {
foreach ($response['results'] as $res) {
$tweet = new WidgetkitTweet();
$tweet->user = $res['from_user'];
$tweet->name = $res['from_user'];
$tweet->image = $res['profile_image_url'];
$tweet->text = $res['text'];
$tweet->created_at = $res['created_at'];
$tweets[] = $tweet;
}
} else {
foreach ($response as $res) {
$tweet = new WidgetkitTweet();
$tweet->user = $res['user']['screen_name'];
$tweet->name = $res['user']['name'];
$tweet->image = $res['user']['profile_image_url'];
$tweet->text = $res['text'];
$tweet->created_at = $res['created_at'];
$tweets[] = $tweet;
}
}
}
}
return array_slice($tweets, 0, $options['limit'] ? intval($options['limit']) : 5);
}
}
class WidgetkitTweet {
public $user;
public $name;
public $image;
public $text;
public $created_at;
public function getLink() {
return 'http://twitter.com/'.$this->user;
}
public function getText() {
// format text
$text = preg_replace('#(https?://([-\w\.]+)+(/([\w/_\.]*(\?\S+)?(#\S+)?)?)?)#', '$1', $this->text);
$text = preg_replace('/#(\w+)/', '#$1', $text);
$text = preg_replace('/\s+#(\w+)/', ' #$1', $text);
return $text;
}
}
// bind events
$widgetkit = Widgetkit::getInstance();
$widgetkit['event']->bind('site', array($widgetkit['twitter'], 'site'));
I believe you can do what you want with this:
http://www.j-plant.com/joomla-extensions/free-extensions/26-module-plant.html
This plugin supports module parameters overriding. Use the next code
for overriding parameters:
[moduleplant id="77" <param_name_1>="<param_value_1>" <param_name_N>="<param_value_N>"]
replace and with the necessary parameter name and value.
You can override as many parameters as you want.
Available module parameters can be found in module XML manifest
file. A manifest file is usually located in the next path:
modules/<module_type>/<module_type>.xml