I want to display multiple images in a gridviews single row. For example: I have table A, Table B and table C.
Table A has my_id.
In Table B my_id is the foreign key. Along with my_id it has c_id.
Table C has c_id which is in reference in Table B.
Table C also has a filepath to display images.
in Table A i have my_id as follows:
1, 2, 3, 4, 5, 6.
In Table B i have my_id as follows.
1 ,1 ,1 ,2 ,3, 3.
In Table B i also have c_id as follows.
1, 2, 3, 4, 5, 6.
In table C my c_id's are:
1, 2, 3, 4, 5, 6. and these id's have filepath associated with each of them. They are different images.
Now my gridview should display 3 different images for my_id because of the foreign key constraints. but it displays only 1 image.
My code is below:
In my model
public function getPictogramsID()
{
$pictogramsID = SdsrefGhsPictograms::find()->where(['sdsref_id' => $this->sdsref_id])->all();
foreach ($pictogramsID as $picID){
return $picID->pictogram_id;
}
}
public function getPictogramPath()
{
$pictogramsID = GhsPictogram::find()->where(['pictogram_id' => $this->getPictogramsID()])->all();
foreach ($pictogramsID as $picID){
$pic = $picID->pictogram_filepath;
}
return $pic;
}
public function getPictogramUrl()
{
//var_dump($this->getPictogramPath()); exit();
return \Yii::$app->request->BaseUrl.'/web'.$this->getPictogramPath() ;
}
my index file grid view image code
[
'label' => 'Hazards',
'format' => 'raw',
'value' => function ($data) {
return Html::img($data->getPictogramUrl(), ['alt'=>'myImage','width'=>'20','height'=>'30']);
},
],
I am also trying to add a bootstrap tool tip to this.. tool tip is displaying successfully but I think the looping is not not done in a correct way so it is repeating my images.
here is my updated gridview code.
[
'label' => 'Hazards',
'format' => 'raw',
'value' => function ($data) {
$images = '';
// append all images
foreach($data->getPictogramName() as $name)
foreach ($data->getPictogramUrl() as $url)
$images = $images.Html::img($url,['alt'=>'','width'=>'30','height'=>'30', 'data-toggle'=>'tooltip','data-placement'=>'left','title' => $name ,'style'=>'cursor:default;']);
return $images;
}
],
You have few logical errors in model and grid view. In all these areas you are dealing with one item instead of three.
In your model
public function getPictogramsID()
{
$ids = [];
$pictogramsID = SdsrefGhsPictograms::find()->where(['sdsref_id' => $this->sdsref_id])->all();
foreach ($pictogramsID as $picID){
$ids[] = $picID->pictogram_id;
}
return $ids;// returning all three ids
}
public function getPictogramPath()
{
$pic = [];
$pictogramsID = GhsPictogram::find()->where(['pictogram_id' => $this->getPictogramsID()])->all();
foreach ($pictogramsID as $picID){
$pic[] = $picID->pictogram_filepath;
}
return $pic;
}
public function getPictogramUrl()
{
$url = [];
foreach($this->getPictogramPath() as $path):
$url[] = \Yii::$app->request->BaseUrl.'/web'.$path;
endforeach;
return $url; // returning al urls
}
Now in you view loop over all urls and append images with each url
[
'label' => 'Hazards',
'format' => 'raw',
'value' => function ($data) {
$images = '';
// append all images
foreach($data->getPictogramUrl() as $url):
$images = $images.Html::img($url, ['alt'=>'myImage','width'=>'20','height'=>'30']);
endforach;
return $images;
},
],
Related
I have a table that contains foreign keys of product properties and their values.
product_id
feature_id
value_id
1
1
2
1
1
3
1
2
4
How to get a collection of that values using Eloquent?
Something like this
product => [
id => 1,
...
features => Collection: [
Feature: [
id => 1,
name => Size,
values => [
Value: [
id => 2,
name => M
],
Value: [
id: 3,
name: L
]
]
],
Feature: [
id => 2,
name => Color,
values => [
Value: [
id => 4,
name => Red
]
]
]
]
]
This is my solution.
class Product extends Model
{
protected $appends = ['features'];
protected array $features;
protected bool $featuresAppend = false;
public function getFeaturesAttribute(): Collection
{
if ($this->featuresAppend === false) {
$this->appendFeatures();
}
return collect($this->features);
}
public function productFeatures(): BelongsToMany
{
return $this->belongsToMany(Feature::class, 'product_features');
}
public function productFeatureValues(): BelongsToMany
{
return $this->belongsToMany(
FeatureValue::class,
'product_features',
'product_id',
'value_id'
);
}
protected function appendFeatures(): void
{
// Get futures and values by relationships
$features = $this->productFeatures()->get()->keyBy('id');
$values = $this->productFeatureValues()->get()->keyBy('id');
// Create features-values structure
$features->each(
function ($f) {
$this->features[$f->id] = new \StdClass();
$this->features[$f->id]->feature = $f;
}
);
// Appends values to future
$values->each(
function ($v) {
if (array_key_exists($v->feature_id, $this->features)) {
$this->features[$v->feature_id]->values[$v->id] = $v;
}
}
);
$this->featuresAppend = true;
}
}
I'm looking for a better solution to this problem or a solution using native Laravel features.
I have a page model and a textblock model for creating pages with as many textblocks as needed. I'm using sortable from jquery ui to sorter the textblocks by position field in migration table. So every time I'm creating a textblock the position will count + 1, starting from 1.
Now I'm setting up 2 faker factories, 1 for pages and 1 for generating dummy textblocks on the pages. I'm wondering how I can count the amount of random textblocks the factory will create? So I can say every time the page factory creates a page with a few textblocks the counter won't override the amount of textblocks each page has.
$factory->define(Textblock::class, function (Faker $faker) {
return [
'page_id' => Page::all()->random()->id,
'title' => $faker->sentence(rand(2, 5)),
'summary' => $faker->text,
'position' => // how can i code this ?
'visible' => $faker->boolean($chanceOfGettingTrue = 50),
]; });
You could create a Counter object to keep all the incrementations in memory. Something similar to:
class Counter
{
private static $counters = [];
public static function nextCounterFor($key, $default = 0)
{
if (!isset(self::$counters[$key])) {
if (is_callable($default)) {
$default = $default();
}
if (!is_int($default)) {
throw new \RuntimeException('The default value must be an integer');
}
self::$counters[$key] = $default;
}
return ++self::$counters[$key];
}
}
Then you can use it to generate new positions for the given page ID. If there is no key defined yet, you must take the last position used for that page from the db (if it exists)
$factory->define(Textblock::class, function (Faker $faker) {
$page = Page::inRandomOrder()->first();
$position = Counter::nextCounterFor($page->id, static function() use ($page) {
$lastPosition = Textblock::where('page_id', $page->id)->orderBy('position', 'DESC')->first();
return $lastPosition !== null ? $lastPosition->position : 0;
});
return [
'page_id' => $page->id,
'title' => $faker->sentence(rand(2, 5)),
'summary' => $faker->text,
'position' => $position,
'visible' => $faker->boolean($chanceOfGettingTrue = 50),
];
});
i have 2 table, 1st tabel name trans_tmbh_qty for record history value inserted to tabel 2nd frm_fancpu
this my structure tabel 1st
and this tabel 2nd with name frm_monitor
this now my full function on controller trans_tmbh_qty
public function create_action()
{
$this->_rules();
if ($this->form_validation->run() == FALSE) {
$this->create();
} else {
$data = array(
'merk' => $this->input->post('merk',TRUE),
'av_mobo' => $this->input->post('av_mobo',TRUE),
'av_prc' => $this->input->post('av_prc',TRUE),
'av_ram' => $this->input->post('av_ram',TRUE),
'av_hdd' => $this->input->post('av_hdd',TRUE),
'av_psu' => $this->input->post('av_psu',TRUE),
'av_fancpu' => $this->input->post('av_fancpu',TRUE),
'user_modify_av' => $this->input->post('user_modify_av',TRUE),
'date_modify_av' => $this->input->post('date_modify_av',TRUE),
);
$fancpu = $this->input->post('merk', TRUE);
$av_fancpu = $this->input->post('av_fancpu', TRUE);
$this->M_fancpu->av_fancpu($fancpu,$av_fancpu
);
$this->M_fancpu->av_fancpu($fancpu,$av_fancpu);
$this->M_trans_tmbhqty->insert($data);
$this->session->set_flashdata('message', 'Create Record Success');
redirect(site_url('trans_tmbhqty'));
}
}
I want to update stock on qty_available_fancpu. if previously filled 10, and I inserted 5 on form. I need result 15. I have code now only replace number 10 with 5. and this my controller
$fancpu = $this->input->post('merk', TRUE);
$av_fancpu = array(
'qty_available_fancpu' => $this->input->post('av_fancpu'),
);
$this->M_fancpu->av_fancpu($fancpu,$av_fancpu);
and it my model on M_fancpu
function av_fancpu($fancpu,$av_fancpu)
{
$this->db->where('tipe_fancpu', $fancpu);
$this->db->update('tbl_fancpu', $av_fancpu);
}
You can try this solution for your problem :-
Controller.php file
class fancpu {
$fancpu = $this->input->post('merk', TRUE);
$av_fancpu = $this->input->post('av_fancpu', TRUE);
$this->M_fancpu->av_fancpu($fancpu,$av_fancpu);
}
Model.php file
function av_fancpu($fancpu,$av_fancpu) {
$this->db->set('qty_available_fancpu', 'qty_available_fancpu + ' . (int) $av_fancpu, FALSE);
$this->db->where('tipe_fancpu', $fancpu);
$this->db->update('tbl_fancpu');
}
I hope it will help.
I used Yii 2.
To be clear:
The two tables, content and task, is 1:1 relation, task.content_id =
content.id;
and I referenced
doc.
in view file, I used Gridview to show data.
and I wanna the content is also searchable even it is in another
table.
Maybe the following sql can explain what I want:
SELECT
c.content,
t.publish_status
FROM
content c, task t
WHERE
c.content LIKE '%keywordInContent%' AND
t.publish_status = 1 AND
c.id = t.content_id
ORDER BY
updated_at
LIMIT 20;
Here is my controller code:
public function actionIndex()
{
$searchModel = new TaskSearch;
$dataProvider = $searchModel->search(Yii::$app->getRequest()->get());
return $this->render('index', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
]);
}
and search model code:
public function search($params)
{
$query = Task::find()->trashed(Task::TRASHED_NO);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->andFilterWhere(['publish_status' => $this->publish_status]);
return $dataProvider;
}
I have settled it by searching like clause before and adding the resulted content_id to searchModel query, code like follow:
if (!empty($this->keyword)) {
$contentIdArr = Content::find()->select('id')->where(['like', 'content', $this->keyword])->column();
if (empty($contentIdArr)) {
$contentIdArr = -1;
}
$query->andFilterWhere(['content_id' => $contentIdArr]);
}
I wonder is there a way to construct the sql I wrote at begin in Yii 2 ?
thanks for help.
Could you try this:
public function search($params)
{
$query = Task::find()->trashed(Task::TRASHED_NO);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
if(!empty($this->keyword))
$query->leftJoin('content', 'content.id=task.content_id')
->andWhere(['publish_status' => 1])
->andWhere(['LIKE', 'content', $this->keyword])
->orderBy('updated_at');
return $dataProvider;
}
But the updated_at shouldn't be part of the search, I guess. This is more about sorting. Look here for an example.
I think you can do it by first getting Content data and have a relation with Task model.
You can achieve relation by this link. Relation in Content model:
public function getTask()
{
return $this->hasOne(Task::className(), ['content_id' => 'id']);
}
and search query
$searchResult = Content::find()
->select('content, publish_status')
->with('task')
->where(['LIKE', 'content', 'keywordInContent'])
->andWhere(['publish_status' => 1])
->orderBy('updated_at')
->limit(20)
->all();
I think this might help you.
I'm trying to build my first app on CodeIgniter. This is also my first time trying to stick to OOP and MVC as much as possible. It's been going ok so far but now that I'm trying to write my first model I'm having some troubles. Here's the error I'm getting:
A Database Error Occurred
Error Number: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Castledine' at line 3
SELECT * FROM (authors) WHERE author = Earle Castledine
Which, as you'll see below, relates to the following line in my model:
$this->db->get_where('authors', array('author' => $author));
I'm not quite sure why it's throwing the error. Is it because Earle Castledine isn't in quotes? If so, why doesn't CI put them in there? I would doubt that's the issue, rather to think it's my fault, but I'm not sure.
I'm having another issue as well. Neither tags nor authors are getting inserted into their respective tables. Their insert statement is wrapped in a conditional that's supposed to be making sure they don't already exist, but it seems to be failing and the insert never happens. I assume it's failing because the tags aren't getting put in the database and it's down in the author section before it tosses the error. I know how to do this with pure PHP but I'm trying to go about doing it the pure CI ActiveRecord way.
Here's the statement I'm using:
if ($this->db->count_all_results() == 0)
And I'm using that instead of what I'd normally use:
if (mysql_num_rows() == 0)
Am I doing it wrong?
Here are my model and controller (only the functions that matter), commented as best I could.
Model:
function new_book($book, $tags, $authors, $read) {
// Write book details to books table
$this->db->insert('books', $book);
// Write tags to tag table and set junction
foreach ($tags as $tag) {
// Check to see if the tag is already in the 'tags' table
$this->db->get_where('tags', array('tag' => $tag));
// trying to use this like mysql_num_rows()
if ($this->db->count_all_results() == 0) {
// Put it there
$this->db->insert('tags', $tag);
}
// Set the junction
// I only need the id, so...
$this->db->select('id');
// SELECT id FROM tags WHERE tag = $tag
$query = $this->db->get_where('tags', array('tag' => $tag));
// INSERT INTO books_tags (book_id, tag_id) VALUES ($book['isbn'], $query->id)
$this->db->insert('books_tags', array('book_id' => $book['isbn'], 'tag_id' => $query->id));
}
// Write authors to author table and set junction
// Same internal comments apply from tags above
foreach ($authors as $author) {
$this->db->get_where('authors', array('author' => $author));
if ($this->db->count_all_results() == 0) {
$this->db->insert('authors', $author);
}
$this->db->select('id');
$query = $this->db->get_where('authors', array('author' => $author));
$this->db->insert('authors_books', array('book_id' => $book['isbn'], 'author_id' => $query));
}
// If the user checked that they've read the book
if (!empty($read)) {
// Get their user id
$user = $this->ion_auth->get_user();
// INSERT INTO books_users (book_id, tag_id) VALUES ($book['isbn'], $user->id)
$this->db->insert('books_users', array('book_id' => $book['isbn'], 'user_id' => $user->id));
}
}
Controller:
function confirm() {
// Make sure they got here by form result, send 'em packing if not
$submit = $this->input->post('details');
if (empty($submit)) {
redirect('add');
}
// Set up form validation
$this->load->library('form_validation');
$this->form_validation->set_error_delimiters('<h3 class="error">', ' Also, you’ll need to choose your file again.</h3>');
$this->form_validation->set_rules('isbn','ISBN-10','trim|required|exact_length[10]|alpha_numeric|unique[books.isbn]');
$this->form_validation->set_rules('title','title','required');
$this->form_validation->set_rules('tags','tags','required');
// Set up upload
$config['upload_path'] = './books/';
$config['allowed_types'] = 'pdf|chm';
$this->load->library('upload', $config);
// If they failed validation or couldn't upload the file
if ($this->form_validation->run() == FALSE || $this->upload->do_upload('file') == FALSE) {
// Get the book from Amazon
$bookSearch = new Amazon();
try {
$amazon = $bookSearch->getItemByAsin($this->input->post('isbn'));
} catch (Exception $e) {
echo $e->getMessage();
}
// Send them back to the form
$data['image'] = $amazon->Items->Item->LargeImage->URL;
$data['content'] = 'add/details';
$data['error'] = $this->upload->display_errors('<h3 class="error">','</h3>');
$this->load->view('global/template', $data);
// If they did everything right
} else {
// Get the book from Amazon
$bookSearch = new Amazon();
try {
$amazon = $bookSearch->getItemByAsin($this->input->post('isbn'));
} catch (Exception $e) {
echo $e->getMessage();
}
// Grab the file info
$file = $this->upload->data();
// Prep the data for the books table
$book = array(
'isbn' => $this->input->post('isbn'),
'title' => mysql_real_escape_string($this->input->post('title')),
'date' => $amazon->Items->Item->ItemAttributes->PublicationDate,
'publisher' => mysql_real_escape_string($amazon->Items->Item->ItemAttributes->Publisher),
'pages' => $amazon->Items->Item->ItemAttributes->NumberOfPages,
'review' => mysql_real_escape_string($amazon->Items->Item->EditorialReviews->EditorialReview->Content),
'image' => mysql_real_escape_string($amazon->Items->Item->LargeImage->URL),
'thumb' => mysql_real_escape_string($amazon->Items->Item->SmallImage->URL),
'filename' => $file['file_name']
);
// Get the tags, explode by comma or space
$tags = preg_split("/[\s,]+/", $this->input->post('tags'));
// Get the authors
$authors = array();
foreach ($amazon->Items->Item->ItemAttributes->Author as $author) {
array_push($authors, $author);
}
// Find out whether they've read it
$read = $this->input->post('read');
// Send it up to the database
$this->load->model('add_model', 'add');
$this->add->new_book($book, $tags, $authors, $read);
// For now... Later I'll load a view
echo 'Success';
}
}
Could anyone help shed light on what I'm doing wrong? Thanks much.
Marcus
Where you are using count_all_results(), I think you mean to use num_rows(). count_all_results() will actually create a SELECT COUNT(*) query.
For debugging your problems...
If you want to test if an insert() worked, use affected_rows(), example:
var_dump($this->db->affected_rows());
At any point you can output what the last query with last_query(), example:
var_dump($this->db->last_query());
You can also turn on the Profiler so you can see all the queries being run, by adding in the controller:
$this->output->enable_profiler(TRUE);
I managed to figure this out on my own. The controller didn't really change, but here's the new model:
function new_book($book, $tags, $authors, $read) {
// Write book details to books table
$this->db->insert('books', $book);
// Write tags to tag table and set junction
foreach ($tags as $tag) {
// Check to see if the tag is already in the 'tags' table
$query = $this->db->get_where('tags', array('tag' => $tag));
// trying to use this like mysql_num_rows()
if ($query->num_rows() == 0) {
// Put it there
$this->db->insert('tags', array('tag' => $tag));
}
// Set the junction
// I only need the id, so...
$this->db->select('id');
// SELECT id FROM tags WHERE tag = $tag
$query = $this->db->get_where('tags', array('tag' => $tag));
$result = $query->row();
// INSERT INTO books_tags (book_id, tag_id) VALUES ($book['isbn'], $query->id)
$this->db->insert('books_tags', array('book_id' => $book['isbn'], 'tag_id' => $result->id));
}
// Write authors to author table and set junction
// Same internal comments apply from tags above
foreach ($authors as $author) {
$query = $this->db->get_where('authors', array('author' => mysql_real_escape_string($author)));
if ($query->num_rows() == 0) {
$this->db->insert('authors', array('author' => mysql_real_escape_string($author)));
}
$this->db->select('id');
$query = $this->db->get_where('authors', array('author' => mysql_real_escape_string($author)));
$result = $query->row();
$this->db->insert('authors_books', array('book_id' => $book['isbn'], 'author_id' => $result->id));
}
// If the user checked that they've read the book
if (!empty($read)) {
// Get their user id
$user = $this->ion_auth->get_user();
// INSERT INTO books_users (book_id, tag_id) VALUES ($book['isbn'], $user->id)
$this->db->insert('books_users', array('book_id' => $book['isbn'], 'user_id' => $user->id));
}
}