Zendframework 2. ID parameter in SQL query - php

I kind of understand what is needed but I am new to ZF2 so just need pushing in the right direction.
I currently have a route set up, for example, viewsystem/1, which has the form [action][id].
When a person clicks on a link, they change their id, for example, viewsystem/5.
In the model where I run the SQL, I wish the id to change for the SQL statement:
->where('system.Id = "'.$id.'" ')
Can anyone explain where I can "get" the parameter and use this as a variable in the SQL?
Do I need to do something in the controller? Can I not just use a $_GET or something?
I have updated this, as it is quite clear to see what is happening. The route for viewsystemAction() is different to the route of ajaxviewsystemAction().
When I use $id = (int) $this->params()->fromRoute('id', 0); inside the viewsystemAction(), it echoes back the page link id route, for example viewsystem/220
When I use $id = (int) $this->params()->fromRoute('id', 0); inside the ajaxviewsystemAction(), it echoes back the 0 as the route id.
I need the route to be passed through this function
private function getSourceViewAllSystems($id)
{
return $this->getSystemsTable()->fetchViewAllSystems($id);
}
public function viewsystemAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
echo $id; //i see the correct id for example 220 from the route in the browser
}
public function ajaxviewsystemAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
echo $id; //to see the id of the route with the ajax page
//displays 0 and not the route id from the viewsystemAction
$table = new TableExample\Advance();
$table->setAdapter($this->getDbAdapter())
->setSource($this->getSourceViewAllSystems($id))
->setParamAdapter($this->getRequest()->getPost());
return $this->htmlResponse($table->render('custom' , 'custom-b2'));
}
To try explain a bit better here is my issue.
As you can see i am passing a param as you suggested into fetchViewAllSystems($id = 1);
fetchViewAllSystems is in my model and works perfectly, with the 1 there, it displays the system1.
however, the 1 needs to be the url id.
$id = (int) $this->params()->fromRoute('id', 0);
This gets the ID in the viewaction, but viewaction does not control the fetchViewAllSystems so it is quite tricky to pass this value from the url.
private function getSourceViewAllSystems()
{
return $this->getSystemsTable()->fetchViewAllSystems($id = 1);
}
public function viewsystemAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
/*if (!$id) {
return $this->redirect()->toRoute('systems', array(
'action' => 'activesystems'
));
}*/
echo $id;
}
public function ajaxviewsystemAction()
{
/*$table = new TableExample\Base();
$table->setAdapter($this->getDbAdapter())
->setSource($this->getSourceViewAllSystems())
->setParamAdapter($this->getRequest()->getPost())
;
return $this->htmlResponse($table->render());*/
$table = new TableExample\Advance();
$table->setAdapter($this->getDbAdapter())
->setSource($this->getSourceViewAllSystems())
->setParamAdapter($this->getRequest()->getPost())
;
return $this->htmlResponse($table->render('custom' , 'custom-b2'));
echo $id;
}

To get a $_GET params in your controller, do like this:
// your IndexController.php
public function indexAction(){
$viewmodel = new ViewModel();
// get the ID
$id = $this->params('id', null); // null is my default value
// ...
return $viewmodel;
}
I highly recommend you to check this great example : https://github.com/akrabat/zf2-tutorial - http://zf2.readthedocs.org/en/latest/ref/overview.html
Check this line https://github.com/akrabat/zf2-tutorial/blob/master/module/Album/src/Album/Controller/AlbumController.php#L43
Get params
$id = $this->params('id', null); // null is my default value
or
$id = $request->query()->get('foo', 'default value');
Ref: http://zend-framework-community.634137.n4.nabble.com/ZF2-How-to-set-get-params-in-url-td4076050.html
controller.php
I don't know what getSystemsTable() returns and also fetchViewAllSystems but it should be like this
private function getSourceViewAllSystems($id = 1)
{
return $this->getSystemsTable()->fetchViewAllSystems($id);
}
public function viewsystemAction()
{
$id = $this->params()->fromRoute('id', null);
if (!$id) {
return $this->redirect()->toRoute('systems', array(
'action' => 'activesystems'
));
}
echo $id;
}
public function ajaxviewsystemAction()
{
$id = $this->params()->fromRoute('id', null);
$id = $this->params()->fromQuery()['id']; // if from ajax GET param
$table = new TableExample\Advance();
$table->setAdapter($this->getDbAdapter())
->setSource($this->getSourceViewAllSystems($id)) // send the current id
->setParamAdapter($this->getRequest()->getPost())
;
return $this->htmlResponse($table->render('custom' , 'custom-b2'));
}

Related

yii2 mongodb - add comments to existing field how to

I have a collection called work-monitor where-in I have two fields namely
assignor_remarks and assignee_remarks.
so when a comment is submitted by either assignor or assignee, I want to add those comments in the respective comment filed.
I am able to save the comments in the collection, but new comments is overriding the existing one.
my code is like this:
public function actionWorkUpdate($id)
{
\Yii::$app->request->enableCsrfValidation = false;
$work = $this->modelClass::find()->where(['_id'=>$id])->one();
$work->load(Yii::$app->getRequest()->getBodyParams(), '');
$work->assignee_remarks = ["timestamp"=>date('d-m-Y h:i'),"comments"=>$work->assignee_remarks];
$work->update();
return "success";
}
how I can achieve this.
update like in the example below:
"assignee_remarks":{"comment":"test comment","commentTime":2020-04-29 12.41},
{"comment":"test comment2","commentTime":2020-04-29 12.45},
{"comment":"test comment3","commentTime":2020-04-29 12.50}
Try something like that, if I have understood you correctly.
// In Work Model
public $assignee_remarks;
public function rules()
{
return [
//...
['assignee_remarks', 'safe'] // for free load
];
}
// In controller
/**
* In bodyParams you have new comment like assignee_remarks: 'some text'
* #param $id
* #return mixed
*/
public function actionWorkUpdate($id)
{
\Yii::$app->request->enableCsrfValidation = false;
$work = $this->modelClass::find()->where(['_id' => $id])->one();
$currentComments = $work->assignee_remarks ?? [];
$work->load(Yii::$app->getRequest()->getBodyParams(), '');
$currentComments[] = ["commentTime" => date('d-m-Y h:i'), "comment" => $work->assignee_remarks];
$work->assignee_remarks = $currentComments;
$result = $work->update();
if ($result === false) {
// validation error
} else {
return $result > 0 ? 'success' : 'fail';
}
}

Laravel: "override" request object?

I have a function where I save a group. I want to "access" it from the page (when the user makes a new group with a form) and from a controller, too (when a process makes a new group, for example when I create a new tenant)
My code is so far:
.
.
.
$this->saveGroup($tenantId, 'Default group');
.
.
.
public function saveGroup(Request $request, $tenantId = 0, $nameFromFunction = ''){
if(!empty($request)){
$name = $request -> name;
} elseif($nameFromFunction != ''){
$name = $nameFromFunction;
} else {
$name = '';
}
if($tenantId > 0 && $name != ''){
$group = new ConversationGroup;
$group -> group_name = $name;
$group -> tenant_id = $tenantId;
$group->save();
}
if($nameFromFunction != ''){
return $group -> id; //if a function calls it
} else {
return redirect("/{$tenantId}/groups"); //if the new group was made from the page
}
}
If I test it with the page's group creation form it works fine, but when I run it from the controller I got the following error:
GroupController::saveGroup() must be an instance of Illuminate\Http\Request, integer given
What I must change if I want to earn this logic?
you could use global request() helper and completely avoid passing Request object to your function, like:
public function saveGroup($tenantId = 0, $nameFromFunction = ''){
//get input named 'name' or default to $nameFromFunction
$name = request('name', $nameFromFunction);
...
The reason this is happening, is because in your function definition, first parameter is not $tenantId, but the object of class request.
So you have to pass an object of request class as a first parameter to get this working.
You should try this way,
public function otherFunction()
{
$this->saveGroup(new Request(['name' => 'Default Group']), $tenantID);
OR
$this->saveGroup(new Request(), $tenantID, "Default Group");
}
public function saveGroup(Request $request, $id = 0, $nameFromFunction = '')
{
echo 'here-your-code';
}

Exception information: Message: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound

I have a code here that, has to search and post back information selected in a table above the add button, the search works but im having a problem with the post back to the table function. These are the lines it shows to have errors.
C:\xampp\htdocs\portal-gep-2\application\models\ServiceProviders.php(68): Zend_Db_Table_Abstract->fetchRow(Object(Zend_Db_Table_Select))
public function getName($id)
{
$select = $this->select();
$select->where('service_provider_id = ?', $id);
$result = $this->fetchRow($select); //this line
return $result['service_provider_name'];
}
#6 C:\xampp\htdocs\portal-gep-2\application\modules\admin\controllers\AjaxController.php(1104): Model_ServiceProviders->getName(NULL)
public function postserviceproviderAction()
{
$form = new Form_IndustrialTable();
$this->view->form = $form;
if(!$form->isValid($_POST))
{
$values=$form->getValues();
}
$sp = $this->getRequest()->getPost('serviceprovider', null);
$mdlserviceprovider = new Model_ServiceProviders();
$serviceprovider = $mdlserviceprovider ->getName($id); //this line
$rtn_array= array( 'sp' => $sp,
'serviceprovider ' => $serviceprovider);
$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender();
echo Zend_Json::encode($rtn_array);
}
You don't put any initial value to $id so it's null which causes error.
You want SQL query to look something like SELECT * FROM service_providers WHERE service_provider_id = 50, but for this you have to provide id which you want to find (50 in this example). You need to add some value to variable $id before using in $select->where('service_provider_id = ?', $id);, but your code you never put any value to variable $id.
If I'm guessing your idea then you need to change line:
$serviceprovider = $mdlserviceprovider ->getName($id);
to:
$serviceprovider = $mdlserviceprovider ->getName($sp);
Also this part of your code probably unnecessary as it does nothing:
$form = new Form_IndustrialTable();
$this->view->form = $form;
if(!$form->isValid($_POST))
{
$values=$form->getValues(); //you never use $values
}

joomla 2.5 pagination always set start limit to 20

I developed my own joomla 2.5 custom component for displaying data table in front-end.It contain filtering,paging and sorting.When navigate via paging it always shows only first 20.
Is there any way to override limit of a query which generate on function getListQuery().
My populateState method is
protected function populateState($ordering = null, $direction = null) {
// Initialise variables.
$app = JFactory::getApplication();
$search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
$filter_order = $this->getUserStateFromRequest($this->context . '.filter_order', 'filter_order');
//$filter_order = JRequest::getCmd('filter_order');
$filter_order_Dir = $this->getUserStateFromRequest($this->context . '.filter_order_Dir', 'filter_order_Dir');
//$filter_order_Dir = JRequest::getCmd('filter_order_Dir');
'filter_region', '');
$this->setState('filter_order', $filter_order);
$this->setState('filter_order_Dir', $filter_order_Dir);
// List state information
$limit = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->getCfg('list_limit'));
$this->setState('list.limit', $limit);
$limitstart = JRequest::getVar('limitstart', 0, '', 'int');
$this->setState('list.start', $limitstart);
parent::populateState();
}
Constructor method is
function __construct() {
parent::__construct();
//Get configuration
$app = JFactory::getApplication();
$config = JFactory::getConfig();
// Get the pagination request variables
$this->setState('limit', $app->getUserStateFromRequest('com_jointcm.limit', 'limit', $config->getValue('config.list_limit'), 'int'));
$this->setState('limitstart', JRequest::getVar('limitstart', 0, '', 'int'));
}
List query method is
protected function getListQuery() {
// Create a new query object.
$db = JFactory::getDBO();
$query = $db->getQuery(true);
//code goes here...
..............
return $query;
}
After some digging around and taking a look at the source code of the JModelList class, I realized that problem is with
\libraries\joomla\application\component\modellist.php file ,method name public function getItems(),line number 115.
I changed it to
public function getItems()
{
// Get a storage key.
$store = $this->getStoreId();
// Try to load the data from internal storage.
if (isset($this->cache[$store]))
{
return $this->cache[$store];
}
// Load the list items.
$query = $this->_getListQuery();
//$items = $this->_getList($query, $this->getStart(), $this->getState('list.limit'));
$items = $this->_getList($query, $this->getState('limitstart'), $this->getState('list.limit'));
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
// Add the items to the internal cache.
$this->cache[$store] = $items;
return $this->cache[$store];
}
Change was
$items = $this->_getList($query, $this->getStart(), $this->getState('list.limit'));
to
$items = $this->_getList($query, $this->getState('limitstart'), $this->getState('list.limit'));
It works fine.
In JModelList's getItems() the default method uses getStart() which in turn uses your models getQuery() to get a count of the number of items returned by your query, via _getListCount($query) which in turn calls the particular database adaptors version of getNumRows()). That value is used in the calculation in getStart(), if you have a large complicated query and don't really need to use the fancy getStart() implementation you can just override it in your model (i.e. your version of the JModelList class)
e.g. for our components model's for the front end which have rather complicated $query's returned by getListQuery, in their most basic implementation they do something similar to this:
public function getStart()
{
return $this->getState('list.start');
}
If you don't override it the default JModelList getStart() is invoked which looks like this:
/**
* Method to get the starting number of items for the data set.
*
* #return integer The starting number of items available in the data set.
*
* #since 11.1
*/
public function getStart()
{
$store = $this->getStoreId('getstart');
// Try to load the data from internal storage.
if (isset($this->cache[$store]))
{
return $this->cache[$store];
}
$start = $this->getState('list.start');
$limit = $this->getState('list.limit');
$total = $this->getTotal();
if ($start > $total - $limit)
{
$start = max(0, (int) (ceil($total / $limit) - 1) * $limit);
}
// Add the total to the internal cache.
$this->cache[$store] = $start;
return $this->cache[$store];
}
But, this probably isn't the problem area, it's more likely in your populateState(). At the end of populateState() you call parent::populateState() (if was called at the beginning it wouldn't be overwriting results of your method).
You seem to be duplicating the work done by the parent::populateState() which is probably redundant, looking at JModelList's implementation you will see this:
protected function populateState($ordering = null, $direction = null)
{
// If the context is set, assume that stateful lists are used.
if ($this->context)
{
$app = JFactory::getApplication();
$value = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->getCfg('list_limit'), 'uint');
$limit = $value;
$this->setState('list.limit', $limit);
$value = $app->getUserStateFromRequest($this->context . '.limitstart', 'limitstart', 0);
$limitstart = ($limit != 0 ? (floor($value / $limit) * $limit) : 0);
$this->setState('list.start', $limitstart);
// Check if the ordering field is in the white list, otherwise use the incoming value.
$value = $app->getUserStateFromRequest($this->context . '.ordercol', 'filter_order', $ordering);
if (!in_array($value, $this->filter_fields))
{
$value = $ordering;
$app->setUserState($this->context . '.ordercol', $value);
}
$this->setState('list.ordering', $value);
// Check if the ordering direction is valid, otherwise use the incoming value.
$value = $app->getUserStateFromRequest($this->context . '.orderdirn', 'filter_order_Dir', $direction);
if (!in_array(strtoupper($value), array('ASC', 'DESC', '')))
{
$value = $direction;
$app->setUserState($this->context . '.orderdirn', $value);
}
$this->setState('list.direction', $value);
}
else
{
$this->setState('list.start', 0);
$this->state->set('list.limit', 0);
}
}
The most obvious condition in the parent::populateState() that causes list.start to be set to 0 is the very first line, which checks your object context value, it may be that something is going wrong there and your objects context value is equating to false. (I can't see context defined anywhere... so, it will try an guess/build a context value for you in __construct()).
However, it may also be in the way in which getUserSateFromRequest() is processing the values returned from your request, it's hard to tell with the code available.
You can add limit like this $query->limit('0,40'); in getListQuery() function
Do you have list_limit defined in your component options? If not, then add a new parameter to your component options and call it list_limit. This will allow you to set your pagination limit to what ever you want in the component options.

How to Make Zend_Controller_Router resets un-wanted parameter by default

I'm using Zend-Framework 1.9.5 to make a web-application, But it's Url_Helper was quite tricky to me in the matter of parameter reset!, I know it's a good feature (parameter preserving) but in most cases I don't need it!.
So I'm thinking of overriding the default Router to force it loosing parameters Unless I ask for it or maybe specifying a certain parameters that it keeps like (lang, or something like that).
Also I want to make it the default router so I don't have to edit my Controllers, Views to get that done!
Any suggestions?
Update:
I spent the whole morning trying to write my url helper Admin_View_Helper_Xurl, But I couldn't do anything that solves the problem:
<?php
class Admin_View_Helper_Xurl extends Zend_View_Helper_Abstract
{
public function xurl(array $urlOptions = array(), $name = 'default', $reset = false, $encode = true)
{
$router = Zend_Controller_Front::getInstance()->getRouter();
$wanted_params = array('module', 'controller', 'action', 'lang', 'page', 'search');
$route = $router->getCurrentRoute();
$something = anyWayToGetThatObjectOrClass();
$params = $something->getParams();
foreach($params as $key => $val) {
if (!in_array($key, $wanted_params)) {
$params[$key] = null; // OR uset($params[$key]);
}
}
$something->clearParams();
$something->setParams($params);
return $router->assemble($urlOptions, $name, $reset, $encode);
}
}
I tried to get current URL parameters and filter them and clear the current parameters and pass my filtered ones but I couldn't do anything that does it without hard-code editing one Zend_Framework code :(.
Thanks
When generating a link a view, you can ask the helper to get rid of all aparamters with a simple boolean :
<?php echo $this->url(array('controller' => 'index', action => 'action'), 'default', true); ?>
The last parameter tells whether to reset parameters or not.
I came up with this solution. It took 7 hours to be functional.
class Zend_View_Helper_Xurl extends Zend_View_Helper_Abstract
{
const RESET_ALL = 'all';
const RESET_CUSTOM = 'normal';
const RESET_NON_MVC = 'mvc';
const RESET_NONE = 'none';
protected $_wantedParams = array('module', 'controller', 'action', 'lang', 'page', 'search');
protected $_router;
/**
* Generates an url given the name of a route.
*
* #access public
*
* #param array $urlOptions Options passed to the assemble method of the Route object.
* #param mixed $name The name of a Route to use. If null it will use the current Route
* #param bool $reset Whether or not to reset the route defaults with those provided
* #return string Url for the link href attribute.
*/
public function __construct()
{
$router = Zend_Controller_Front::getInstance()->getRouter();
$this->_router = clone $router;
}
public function xurl(array $urlOptions = array(), $reset = 'mvc', $encode = true)
{
$urlOptions = $this->_getFilteredParams($urlOptions, $reset);
return $this->_router->assemble($urlOptions, $name, true, $encode);
}
protected function _getFilteredParams($data = array(), $level)
{
// $filteredValues = array();
$request = Zend_Controller_Front::getInstance()->getRequest();
$filteredValues = $request->getUserParams();
$$filteredValues['module'] = $request->getModuleName();
$$filteredValues['controller'] = $request->getControllerName();
$$filteredValues['action'] = $request->getActionName();
switch ($level) {
case self::RESET_ALL:
$filteredValues['module'] = null;
$filteredValues['controller'] = null;
$filteredValues['action'] = null;
// break omitted intentionally
case self::RESET_NON_MVC:
$filteredValues['page'] = null;
$filteredValues['lang'] = null;
$filteredValues['search'] = null;
// break omitted intentionally
case self::RESET_CUSTOM:
foreach ($filteredValues as $key=>$val) {
if (!in_array($key, $this->_wantedParams)) {
$filteredValues[$key] = null;
}
}
break;
case self::RESET_NONE:
break;
default:
throw new RuntimeException('Unsuppoted Xurl URL helper reset level.');
break;
}
foreach ($filteredValues as $key => $val) {
if (!array_key_exists($key, $data)) {
$data[$key] = $val;
}
}
return $data;
}
}
Clearly it's a View Helper class, may be not the best solution but it works fine with me for now.

Categories