I have a Competition model, that has many Entry models.
[edit] Schema looks (roughly) like this:
Competition:
id INT(11)
name VARCHAR(50)
date DATETIME
Entry:
id INT(11)
competition_id INT(11)
user_id INT(11)
answer VARCHAR(50)
isWinner INT(1)
In my pickWinner view, I have a form that loops through all related entries - offering the isWinner field to allow the user to pick an entry as the winner. Saving the related model etc is pretty standard and that all works fine.
I'm trying to validate the form so that at least one of the Entry models has isWinner set to true (the user has to pick at least one winner).
I obviously can't apply the validation rule to the Entry model - as each model only knows about itself and not the values of the other models.
Only one Entry model should be set as the winner - how do I add a validation rule to Competition, so that it can detect that one of its child Entry models has isWinner set to true?
One way to achieve this would be to add a relation to the Competition model to detect if it has a winner, something like;
public function relations()
{
return array(
...
'winners' => array(self::STAT, 'Entry', 'competition_id', 'condition'=>'`t`.`isWinner` = true'),
...
);
}
Then the following should return the number of winners for the given competition:
$competition = Competition::model()->findByPk($id);
$winners = $competition->winners;
Not tested, so you may need to alter a little.
EDIT
Ok, to get this info before you save you could do something like the following: if for example in your pickWinner view you have a field for each model and it's submitting back as an array, for example like $_POST[Entry][$model->id]['isWinner'] for each model, can you not simply cycle through those making sure one is set to true? e.g:
$winners = 0;
foreach(array_keys($_POST[Entry]) as $key)
{
if($_POST[Entry][$key]['isWinner']=='true')
$winners++;
}
if($winners==0)
{
echo "You selected no winners.";
} else if($winners>1) {
echo "You selected too many winners.";
} else if($winners==1) {
echo "Woot, 1 winner!";
}
Again, this depends on how your pickWinner form is laid out.
Related
What i want to achieve?
Show user which pacts he is following.
What I am trying
I have designed two tables which are 'pacts' & 'pacts_follwers'
Table 'pacts' has the details of all the pacts
Table 'pacts_follwers' has details of users following a particular pact.
These links will give you the images of both the tables
For Schema Refer Images
So how to get pacts that user is following.
What I have tried?
Sql Query
SELECT pacts.*, (SELECT pactsid FROM pacts_follwers WHERE pacts.id = pacts_follwers.pactsid
and pacts_follwers.userid = 2 ) as pactID FROM `pacts`
Sql query Result
This query will give pactId some value, where the value is null means the user is not following that pact. If this is the solution then i would need Eloquent for this which i am unable to make.
1st table pacts
id
title
about
created_at
updated_at
pactsImage
2nd table pacts_follwers
id
pactsid
userid
created_at
updated_at
Controller Code
$pacts = DB::select("SELECT pacts.*, (SELECT pactsid FROM pacts_follwers WHERE pacts.id =
pacts_follwers.pactsid and pacts_follwers.userid = ".Auth::id()." ) as pactID FROM `pacts`");
You need to setup hasManyThrough relationship for User and Pact.
class User extends Model {
public function pacts() {
return $this->hasManyThrough(
Pact::class,
PactFollower::class
'userid',
'pactsid'
);
}
}
I don't fully understand if you want to achieve "get user's all pacts" or "if pact is followed by user". Either way, you need to setup related relationships.
Or really simple (and not efficient way)
class Pact extends Model {
public function followers() {
return $this->hasMany(PactFollower::class, 'pactsid')
}
}
Now you can use something like
$userIdsForPact = Pact::followers()->pluck('userid');
if ($userIdsForPact->has($user->id)) {
// your operation
}
Edit: For "if pact is followed by user", you need to setup belongsToThrough relationship. It doesn't come out of the box with Laravel but staudenmeir/belongs-to-through package should serve you well.
After setting the relationship properly, you can use something like this.
Pact::with('user')->get();
Or add some methods in your Pact model:
public function followedByUser($user) {
return $this->users->has($user);
}
The title says it all, but to give an example. I have a Member record and a Group. A member can have memberships in many groups and a group can have many members. (So that's many to many and I would have a pivot table for it.)
Now, each group has membership grades. E.g., (Free, Freemium, Premium, Super Premium). So the membership_grade shall belong to the pivot table, right? But here's the problem, not all groups share the same grades. Some might have Free and Freemium only, some might have all.
In the fields.yaml of the Membership pivot model, I defined the membership_grades as a Relation Widget, like this:
pivot[grade]:
label: Membership Grade
span: full
type: relation
nameFrom: name
And in its relationship in Membership.php like this:
public $belongsTo = [
'grade' => [
'Acme\Models\Grade',
]
];
Obviously, this will expose ALL grades, since I'm pulling data from the Grade model. What I want is to expose the grades that is just available on that group, not all.
What I've thought to do (but I didn't, because it seemed impossible) is to try to pull data from the grades relationship of the Group, but how am I suppose to do that? (Since Relation widget manages the relation of the Model, I cannot simply pull data from other sources just like that).
Also I've tried to do scopes but how am I suppose to pass the current Group I'm in? Since it is needed as the filter, like this:
// Membership.php
public $belongsTo = [
'grade' => [
'Acme\Models\Grade',
'scope' => 'filteredIt'
],
// added this relationship to try the scopes approach
'group' => [
'Acme\Models\Group'
]
];
// Grade.php
public function scopeFilteredIt($query, Membership $m)
// yes, the second parameter in the scope will be the
// current Membership model. I've tried it.
{
// this won't work, since we want the overall relation filter;
// an instance of Membership won't help.
// this would work if I can find a way to pass the
// current Group (record) selected, and get its grades, then use it here.
return $query->whereIn('id', $m->group->grades->pluck('id')->all());
}
Any thoughts?
I have noticed some post values during pivot model ajax call.
When you add new record and when your pivot model opens post values are like this
Array (
[_relation_field] => groups
[_relation_extra_config] => W10=
[foreign_id] => 1
[_session_key] => VrSCoKQrSkIsZNGIju5QIqpdbS3AADoGQRHAsv1e
)
So good thing is that we can now get foreign_id as it will be your selected group id
and we can use it at creation time and for update time you know we have relation so we use that.
public function scopefilteredIt($query, Membership $m)
{
// we are checking relation is there or not
if($m->group) {
// yes group is there we use it
return $query->whereIn('id', $m->group->grades->pluck('id')->all());
}
else {
// seems new record then use foreign_id
$foreign_id = post('foreign_id'); //<-this will be your selected group id
if($foreign_id) { // <- double check if its there
$group = Group::find($foreign_id);
return $query->whereIn('id', $group->grades->pluck('id')->all());
}
}
return $query;
}
please comment if you get any issue.
to check post
public function scopefilteredIt($query, Membership $m)
{
// will show flash message with post data array
$post = print_r(post(), true);
\Flash::success($post);
// we are checking relation is there or not
if($m->group) {
// yes group is there we use it
return $query->whereIn('id', $m->group->grades->pluck('id')->all());
}
else {
// seems new record then use foreign_id
$foreign_id = post('foreign_id'); //<-this will be your selected group id
if($foreign_id) { // <- double check if its there
$group = Group::find($foreign_id);
return $query->whereIn('id', $group->grades->pluck('id')->all());
}
}
return $query;
}
I have three tables (simplified) which are:
And I have to display all houses for each user.
In my controller I have a function like this:
public function create_houses_table($usr_id)
{
$crud = new grocery_CRUD();
$crud->set_language("italian");
$crud->set_theme('datatables');
$crud->set_subject('Casette');
$crud->set_table('tbl_houses');
$crud->set_relation_n_n('Casette',
'tbl_users_houses',
'tbl_users',
'house_id',
'user_id',
'usr_name',
NULL,
array('user_id' => $usr_id));
...
}
and what I get is this:
Every time I select a user from the combo I need to refresh my list filtering on usr_id...but I get always all the houses.
What I'm wrong?
This is not the intended usage for set_relation_n_n (it will show all the user houses in one field inside the user row).
What you want can be better done listing from tbl_users_houses, filtering by client with $crud->where() and linking with the other tables with two simple relations.
If I understand correctly you are trying to fetch only the records for the logged in User... and u have multiple users per house, hence the n-n relation.
I also faced this problem and here's what I did.
$myprojects = $this->admin_model->get_employee_projects($this->user_id);
$myprojectids = array_column($myprojects, 'id');
//get only one column from the multi-dimensional array
$crud->where("`projects`.id IN", "(" . implode(",", $myprojectids) . ")", false);
// the false disables escaping
$crud->set_relation_n_n('assigned_employees', 'project_employees', 'employees', 'project', 'employee', 'name');
//Only so it also still shows the name of Users assigned
So basically projects here is like houses, and I am using the WHERE IN clause to filter the records based on the projects I get from my model method...
I have to tables with these schema:
users(id, name, email)
user_details (id, user_id, physical_address, otherinfo)
I would like to display all contents of both tables in one grid using grocery crud
when i try to use set relation on the first table as shown: Note: I have reducted the part that does the rendering of the view;
$crud = new grocery_CRUD();
$crud->set_table('users');
$crud->set_relation('id', 'user_details', '{physical_address} + {otherinfo}');
the values of the id field as well as the referenced table don't appear in the grid, so it does not seem to work when using primary keys.
So I decided to start with the contents of the second table like so:
$crud = new grocery_CRUD();
$crud->set_table('user_details');
$crud->set_relation('user_id', 'users', '{name} + {email}');
This works, but the problem is that the values appear in one column in the grid. I would like to know how i can separate them to different columns and make them editable in separate input fields.
my way kinda ridiculous,
if i were really need the field to be separated, i might use callback_column then use active records to return the value using $row->user_id, and callback each record
just like:
return $this->some_model->get_name($row->user_id); for name field
and
return $this->some_model->get_name($row->user_id); for email field
but, as i tested with some dummy records, it can't be sorted, (i dont know if anyone could)
There is no direct way to show multiple columns but i found an work around for this problem.
here is how
set name column as follows.
$crud->columns('name','email'); // define all required columns
$crud->callback_column(unique_field_name('user_id'),array($this,'callback_set_user_name'));
function unique_field_name($field_name)
{
return 's'.substr(md5($field_name),0,8);
}
public function callback_set_user_name($value, $row)
{
$row->full_name = $row->s447d3092; // before getting to know s447d3092 key return json_encode($row); you will key pair with {name} + {email} ex: {"s447d3092":"shiva + shiv#gmail.com"}
return explode("+",$value)[0]; // here you will have only name
}
$crud->callback_column('email',array($this,'callback_set_email'));
public function callback_set_email($value, $row)
{
return explode("+",$row->full_name)[1];
}
I am 100% sure this will help you
A database table for Event model has following fields:
user_id, name, title
in the Event add view the user is asked to insert the name, hours and minutes as following:
echo $this->Form->input('hours');
echo $this->Form->input('minutes');
echo $this->Form->input('name');
Now the name would be obviously stored as it should, but the problem occurs when I want to concacinate the hours and minutes inserted by user and store them into the DBs "title" field.
Any suggestions for how to achieve this?
use the model's beforeSave function to add any fields you like. In this case a title is being injected
in Event.php
public function beforeSave($options=array()){
parent::beforeSave($options);
$this->data['Event']['title'] = $this->data['Event']['hours'].$this->data['Event']['minutes'];
//do other stuff
return true;
}