I've got a simple index action:
$reminders = $this->reminderTable->fetchAll();
foreach ($reminders as $reminder) {
$reminder->receivers = $this->reminderTable->getReceivers($reminder->id);
}
return new ViewModel(array(
'reminders' => $reminders
));
The get receivers (sub items of the main table) looks like this:
public function getReceivers($id)
{
$adapter = $this->tableGateway->getAdapter();
$receiversTable = new TableGateway('ga_reminders_receivers', $adapter);
$resultSet = $receiversTable->select(function (Select $select) use ($id) {
$select->join('ga_users', 'ga_reminders_receivers.receiver_uid = ga_users.uid', array('uid', 'firstname', 'lastname', 'email', 'telephone'), 'left');
$select->where('ga_reminders_receivers.rid = ' . $id);
});
return $resultSet;
}
This gives me the fancy error
This result is a forward only result set, calling rewind() after
moving forward is not supported.
So, I guess my question is this: When I do a fetch of a resultset it fils in the model class thanks to exchangearray(). But how am I suppose to fill a model property with a list of sub models?
In this case the model is Reminder:
class Reminder { // from the reminders table
public function exchangeArray($data)
{
$this->id = (!empty($data['rid'])) ? str_pad($data['rid'], 5, '0', STR_PAD_LEFT) : null;
$this->label = (!empty($data['label'])) ? $data['label'] : null;
// etc.
$this->receivers = array(
new Receiver(1),
new Receiver(2),
// list of objects from the reminders_receivers table
)
}
Second question: Is the separate getReceivers() method needed? Maybe it can be integrated in 1 query. As long as the model classes Reminder and Receiver are used it is OK.
In this cases you have to use buffer.
public function getReceivers($id)
{
$adapter = $this->tableGateway->getAdapter();
$receiversTable = new TableGateway('ga_reminders_receivers', $adapter);
$resultSet = $receiversTable->select(function (Select $select) use ($id) {
$select->join('ga_users', 'ga_reminders_receivers.receiver_uid = ga_users.uid', array('uid', 'firstname', 'lastname', 'email', 'telephone'), 'left');
$select->where('ga_reminders_receivers.rid = ' . $id);
});
$resultSet->buffer();
return $resultSet;
}
Related
I'm currently stuck with the built-in pagination of CI4.
I try to paginate the results of a function in my model, which does not work:
My model:
<?php
namespace App\Models;
use CodeIgniter\Model;
class CategoriesModel extends Model
{
protected $table = 'categories';
protected $allowedFields = [];
protected $beforeInsert = ['beforeInsert'];
protected $beforeUpdate = ['beforeUpdate'];
//Kategorie(n) laden
public function getCategories($categoryID = null)
{
$db = \Config\Database::connect();
if (!$categoryID) {
$builder = $db->table('categories');
$query = $builder->get();
$results = $query->getResultArray();
} else {
$builder = $db->table('categories');
$query = $builder->where('categoryID', $categoryID);
$query = $builder->get();
$results = $query->getRow();
}
return $results;
}
}
In my controller, i try to paginate the results of the "getCategories"-function from the model:
<?php
namespace App\Controllers;
use App\Models\CategoriesModel;
use App\Models\PodcastsModel;
class Categories extends BaseController
{
public function index($page = 1)
{
$this->request->setLocale(session()->get('locale'));
//Helper laden
helper(['form', 'template', 'userrights']);
$data['template'] = getTemplate();
$model = new CategoriesModel;
$data['categories'] = $model->getCategories()->paginate(5, 'test', $page, 2);
$data['pager'] = $model->pager;
//Recht "13" (Benutzergruppen) prüfen
if ($data['userrights'][13] == 0) {
return redirect()->to('/admin');
}
//Views aufbauen
echo view($data['template'] . '/templates/header', $data);
echo view($data['template'] . '/backend/navigation');
echo view($data['template'] . '/templates/sidebar');
echo view($data['template'] . '/backend/categories');
echo view($data['template'] . '/templates/footer');
}
}
So the line
$data['categories'] = $model->getCategories()->paginate(5, 'test', $page, 2);
will cause the following error:
Error
Call to a member function paginate() on array
When i use
$data['categories'] = $model->paginate(5, 'test', $page, 2);
it works just fine. But it paginates ALL results from the categories table, as declared in the model.
But as i want to paginate the results from the function, depending on variables i pass to the model,
Is there a way to use the pagination class for model-functions?
You're not using the paginate library correctly. It must be used at the end of your query builder instead of a get() for example.
Your model could return the paginate object.
public function getCategories($nb_paginate, $categoryID = null)
{
$db = \Config\Database::connect();
if (!$categoryID) {
$results = $this->paginate($nb_paginate);
} else {
$results = $this->where('categoryID', $categoryID)->paginate($nb_paginate);
}
return $results;
}
And then catch it with your controller
$data['categories'] = $model->getCategories(5);
$data['pager'] = $model->pager;
You might want to give a look at the doc aswell : https://codeigniter.com/user_guide/libraries/pagination.html
No idea if this is "valid code" (i'm new to this formal CI4 models namespaces etc). But this works fine for me. Just make sure to filter your "search" in production properly for security
Controller:
$filter['search'] = $this->request->getGet('search');
$this->template->data['customers'] = $customer_model->get_customers_index($filter)->paginate(50);
$this->template->data['pager'] = $customer_model->pager;
Model:
function get_customers_index($filter)
{
if (isset($filter['search']) and $filter['search'])
{
$this->like('id_number', $filter['search']);
}
return $this;
}
I can't seem to update my user and school table anymore but was able to update hobby table now.
Keep getting error: implode(): Invalid arguments passed when updating data --> linking back to the question before
Controller:
//update for user
public function edit($id){
$object = user::find($id);
return view('edit', compact('object'));
}
public function update(Request $request, $id){
$object = user::find($id);
$object->Name = $request->input('Name');
$object->update();
return redirect('/home');
}
//update for Schools table
public function edit1($id){
$object2 = school::find($id);
return view('edit1', compact('object2'));
}
public function update1(Request $request, $id){
$object2 = school::find($id);
$test = array();
$test['School'] = implode(' , ', $request->School);
$test['SDate'] = implode(' , ', $request->SDate);
$test['EDate'] = implode(' , ', $request->EDate);
$object2->update($test);
return redirect('/home');
}
// The error starts here after putting this whole thing in.
// (I tried putting it into another separate controller but the error
// still continues)
public function edit2($id) {
$object3 = hobby::find($id);
return view('edit2', compact('object3'));
}
public function update2(Request $request, $id){
$object3 = hobby::find($id);
$test2 = array();
$reading_book = (array)$request->reading_book;
$test2['reading_book'] = implode(' , ',$reading_book );
$computer_game = (array)$request->computer_game;
$test2['computer_game'] = implode(' , ',$computer_game );
$object3->update($test2);
return redirect('/home');
}
Hobby model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Eloquent;
class hobby extends Eloquent
{
protected $fillable = array('reading_book','computer_game','user_id');
public function users() {
return $this->belongsTo('App\user, 'user_id', 'id');
}
}
Route: (currently using these for updating)
Route::get('/user/show/{id}/edit', 'HomeController#edit');
Route::put('/user/show/{id}','HomeController#update');
Route::get('/user/show/{id}/edit1', 'HomeController#edit1');
Route::put('/user/show/{id}','HomeController#update1');
Route::get('/user/show/{id}/edit2', 'HomeController#edit2');
Route::put('/user/show/{id}','HomeController#update2');
The problem is in your routes :
Route::put('/user/show/{id}','HomeController#update');
Route::put('/user/show/{id}','HomeController#update1');
Route::put('/user/show/{id}','HomeController#update2');
It's the same route for three methods.
Just for testing you can do that :
Route::put('/user/show/{id}','HomeController#update');
Route::put('/user/showupdate1/{id}','HomeController#update1');
Route::put('/user/showupdate2/{id}','HomeController#update2');
And change in the view this will work perfectly :)
I want to write a dynamic update query in Laravel which accepts arguments and can be used in whole project.
Following is my Controller function:
public function editquery(Request $request)
{
$city_id = $request->input('city_id');
$city_name = $request->input('city_name');
$tbl = 'city';
$data = ['city_name'=>$city_name];
$wher = ('city_id',1);
General_model::editrecord($data,$wher,$tbl);
return redirect()->action('Admin_controller#cities_page')->with('status','Record Updated Successfully!');;
}
Below is my Model function:
public static function editrecord($data,$wher,$tbl)
{
return DB::table($tbl)->where($wher)->update($data);
}
The only problem here is that I cannot store the value ('city_id',1) in the $wher variable. This is the screenshot of the error:
link to the image file
Is there any other way to do this. Please Help.
The where method accepts an array of conditions.
$table = 'city';
$conditions = [
['city_id', '=', '1']
];
$data = ['city_name' => $city_name];
General_model::editRecord($table, $conditions, $data);
// In your model
public static function editRecord($table, $conditions, $data)
{
return DB::table($table)->where($conditions)->update($data);
}
You can also set multiple conditions.
$conditions = [
['city_id', '=', '1'],
['test', '=', 'test'],
];
Edit
This is the default where method
where($column, $operator = null, $value = null, $boolean = 'and')
Setting the fourth parameter to or will make the condition orWhere.
Example
$conditions = [
['city_id', '=', '1'],
['test', '=', 'test', 'or'],
];
You can't do this
public static function editrecord($data,$wher,$tbl)
{
return DB::table($tbl)->where($wher)->update($data);
}
Since, where is a function; it expects 2 or 3 arguments and not just 1 argument.
You will have to pass both the arguments like so
public static function editrecord($data, $where_column, $where_val, $tbl)
{
return DB::table($tbl)->where($where_column, $where_val)
->update($data);
}
Then, in your controller function
$where_column = 'city_id';
$where_val = 1;
General_model::editrecord($data,$where_column,$where_val,$tbl);
Your code is not exactly in the style of Laravel, why would you want to create a separate static function, if such tasks are easily solved by the standard features of Eloquent / Query Builder?
Eloquent example:
app/City.php
<?php
class City extends Model {
protected $table = 'city';
protected $primaryKey = 'city_id';
protected $fillable = ['city_name'];
}
In your controller:
City::findOrFail($city_id)->update([
'city_name' => $city_name
]);
Query Builder example:
DB::table('city')->where(['city_id' => $city_id])->update([
'city_name' => $city_name
]);
This is much easier to read, understand and support than functions that do similar things in an incomprehensible way.
I want to list on a view something like
Number Commands | Date of commands | Description (text from table article)
All I have is
Number Commands | Date of commands | Description (id from table Bc)
I have two tables: BC (as commands) which have columns: id_commands, id_article, id_user, number_commands, date_commands, ...
and table Article which have columns : id_article, name_article, description_article, ...
According to this tutorial, How to extend the ZF2 skeleton application - entities with foreign keys
There are my codes:
On Bc\Model\Bc.php
class Bc implements BcInterface
{
...
public function setArticle(ArticleInterface $bc_article)
{
$this->article = $bc_article;
}
public function getArticle()
{
return $this->bc_article;
}
}
On Bc\Mapper\BcHydrator.php
namespace Bc\Mapper;
class BcHydrator // extends Zend\Stdlib\Hydrator\ClassMethods
{
public function extract($object)
{
return array(
'bc_id' => $object->getBc_id(),
'article_designation' => $object->getA_designation(),
'article_reference' => $object->getA_reference()
);
}
}
On Bc\Mapper\ZendDbSqlMapper.php
...
public function findAllWithArticle()
{
$sql = new Sql($this->dbAdapter);
$select = $sql -> select()
-> from( array('a'=>'s_article'))
-> join( array('bc' => 's_bc'),
'bc.bc_id_article = a.a_id');
$stmt = $sql->prepareStatementForSqlObject($select);
$result = $stmt->execute();
if ($result instanceof ResultInterface && $result->isQueryResult()) {
$resultSet = new HydratingResultSet($this->hydrator, $this->bcPrototype);
\Zend\Debug\Debug::dump($result);die();
//return $resultSet->initialize($result);
}
return array();
}
On my Controller
...
public function detailAction()
{
$id = $this->params()->fromRoute('id');
try {
//$bc = $this->bcService->findBc($id);
$bc = $this->bcService->findAllBcsWithArticle($id);
$articleDesignation = $bc->getArticle()->getA_designation();
} catch (\InvalidArgumentException $ex) {
return $this->redirect()->toRoute('bc');
}
return new ViewModel(array(
'bc' => $bc,
'article' => $articleDesignation
));
}
I have this error, when I have access to my view:
Fatal error: Call to undefined method
Zend\Db\ResultSet\HydratingResultSet::getArticle()
Did someone have an idea of what I did wrong?
Finally i found a solution for those who want to know.
I didn't use hydrator, but i have the result i want.
Add on my class Bc (Bc\Model\Bc.php) a protected variable $description and set setter and getter.
On my Mapper (Bc\Mapper\ZendDbSqlMapper.php), i added a function findContent ($id), and use as sql request:
$sql = new Sql($this->dbAdapter); $select = $sql -> select()
-> from( array('bc'=>'bc'))
-> join( array('a' => 'article'),
'bc.bc_id_article = a.id',
array(
'description' => 'description',
));
$select->where(array('bc_id = ?' => $id));
On my service (Bc\Service\BcService.php)
public function findBcsContent($id)
{
return $this->bcMapper->findContent($id);
}
And on my controller
public function indexAction()
{
return new ViewModel(array(
'bcs'=> $this->bcService->findAllBcsContent()
));
}
On my view, i could use
$this->escapeHtml($bc->getDesignation());
That's all
Following Models:
class User extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn ( 'iron', 'integer', 4 );
}
public function setUp() {
$this->hasMany ('Field as Fields', array(
'local' => 'id',
'foreign' => 'owner_id'
));
}
}
class Field extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn('owner_id','integer',4);
$this->hasColumn('ressource_id','integer',4);
$this->hasColumn('ressource_amount','integer','2');
}
public function setUp() {
$this->hasOne('User as Owner',array(
'local' => 'owner_id',
'foreign' => 'id'
));
}
}
And I try following DQL:
$sqlRessourceUpdate = Doctrine_Query::create()
->update('Field f')
->set('f.Owner.iron','f.Owner.iron + f.ressource_amount')
->where('f.ressource_id = ?',1);
Result:
'Doctrine_Query_Exception' with message 'Unknown component alias f.Owner'
Basicly I just want to update the "iron" attribute from the Field-Owner according to the fields' value
I am guessing you can't reference other tables like that in your query.
This may not be the best way but, here is what I do
$q = Doctrine_Query::create()
->select('*')
->from('Field')
->where('ressource_id = ?',1); //btw resource has one 's'
$field = $q->fetchone();
$field->Owner['Iron'] += $field->ressource_amount;
$field->save();
EDIT:
Actually I don't know if that will work... this is more like what I do
$q = Doctrine_Query::create()
->select('*')
->from('Field')
->where('ressource_id = ?',1); //btw resource has one 's'
$field = $q->fetchone();
$user = $field->Owner;
$user['Iron'] += $field->ressource_amount; // I have never used a += like this, but in theory it will work.
$user->save();