CakePHP - conditions on associated model - php

Problem in short: I want to set
conditions on an associated model. How
do I do it?
I'm having a problem with the associations in my CakePHP application.
The associations looks like this:
Event has many EventSum belongs to Account has many AccountUser belongs to User
Event has many EventDebt ... (the rest is the same as above)
Event also belongs to User
The application is a private econonmy program in PHP and uses the CakePHP framework.
An Event is a financial event, a purchase, transaction between accounts etc. It only holds information about date, title and user.
An EventSum holds information about an Account and how much to debit or credit (in one column, just positive or negative).
Account holds information about title of the account.
AccountUser holds an id of an Account and a User. This indicates that
So, now I want to fetch Events based on what accounts a User is associated to. How can I do this?
I want to fetch the following info:
Event, together with the EventSum. The Events are fetched from Accounts where the User has access.
Thanks for any help,
/Magnus

It seems like you want to be able to query your Event class with the following conditions:
'Account.user_id =' => $userId
Is my assumption correct?
When doing queries which require conditions on associated models, you can use either the Containable behaviour (comes with CakePHP 1.3) or the 'Linkable' behaviour (which can be found here).
What happens when you try this (be sure to attach the Containable behaviour to your models first):
$condition = array('Account.user_id =' => $userId);
$contain = array('EventSum' => array('Account'), 'EventDebt' => array('Account'));
$result = $this->Event->find('all', compact('condition', 'contain'));
Note that you might experience issues when 'containing' both EventSum and EventDebt if both of their associations to Account use the same alias name.

Related

Database Setup for Multilevel User Rights

I'm looking to create a database for users with multi-level user rights and I don't know how to go about doing this. What I mean is that I want a manager of a business to be able to purchase my product; that person would be given Owner rights, but would also be able to grand additional users under that license--those people would be given Manager or User rights. Each level (as well as my level: Admin, and my staff: SuperUser) would obviously have individual rights/privileges).
What I'm asking, more specifically, is how to set up the database. For example, if my business is a corporate calendar/organizer, the Owner would set up departments, each with a Manager and many Users. What's the best and most efficient way to structure the database? Like, would each user (and each calendar entry) have to be associated with an ID that belongs to that specific Owner account? I'm just a little lost as to what the best way to organize the database to keep everything together, as I will have multiple different Owners with their own company structure under them.
I want to use MySQL and PHP.
I tried to make this as logical as possible. I think I'm making it too hard, but I am sure there is a standard that makes it easier....Thanks in advance.
At the very least every product/object whatsoever needs a foreign_key in its table, as for example the user's id. This is necessary and sets the relation from the product/object with the user.
And then it depends on how complex you want your system to become. An easy way would be to just use boolean columns in the user table, like an admin, an editor column and so on, with only true and false as values. In your code you could then use if and case to check if a user is an admin and show him parts of your app or not. Like a delete link for example. But you could also restrict updating and deleting to people whose user has a true value in the sufficient column.
The more complex route would include other id-fields in the tables which set a relation of something to something else. Like say you want the user to be a seller or a buyer, then you would add seller_id and buyer_id columns to the products table and check if the ids correspond with the user_id. But not "the" user_id, but a different user_id which you saved when the user created the product listing for example. This way you could guarantee, that besides your staff the user who created this thing has rights to edit it, too, because of the product's user_id being the same as his user_id (current user) when he is logged in to your system.
You could do even more complex relations but then you'd have to create another table and save other ids in it which relate certain users with say other users. In this table you save let's say a maintainer_id and a maintained_id, both have values of certain user_ids but this way you could make a relation between objects one user could change, though they belong to others. Or if you're talking of customers so the mainter_id would be allowed to write messages to those people with maintained_id, like if someone is a seller and the others are potential buyers.
I'm having a little trouble understanding exactly what you're looking for. From what I've gathered, it seems you want a database that holds permissions, users, and departments. In this very basic example I've created 3 tables. (assuming one user can only belong to one department)
You could set a foreign key in the users table which links to the primary key in the permissions table. The departments table would have the foreign key of the user_id.
You could base all of the logic on what each permission can do with your queries and application side logic.
(I can't embed images due to not having 'enough rep')

Eloquent querying 1:n relationship

I have 2 tables in my database, a notifications table and a notifications_user table.
A notification can have many notification users. And a result in my notification model I have the following relationship,
public function user()
{
return $this->belongsToMany('User')->withPivot('is_read');
}
What I am wanting to achieve is to get all notifications that are unread (or is_read = 0), the is_read column is in the notification user table though and I cannot work out how to run a query on it becuase of that.
Current I have this,
$unread = Notification::has('user')->with('user')->get();
Now this pulls the relationship into the results, but takes no account of the is_read value.
Is there a way to select all the data from a table based on a value in its 1:n relationship.
You can query on the relationship by doing something like:
$unread = Notification::has('user')->with('user')->where('is_read','!=', 0)->get();
Check the docs: http://laravel.com/docs/5.1/eloquent-relationships#querying-relations
So while it may make sense to have the relation that notifications have many users it really doesn't make sense from an ownership. Notifications are one-time things while users persist in a way. So try to think of users as the base object and notifications as the abundant resource.
The goal here is to get the users notifications so out of this you have to choose whether to duplicate notifications for each user or have one notification for many users. In one case where it's universal notifications (admin panel maybe) and the other is notifications that are personal to the user. If you're doing the latter you don't really need a pivot table and just a notifications table.
User -> hasOne -> Notification
Notification -> belongsTo -> User
This enables you to really customize the notifications per-user than relying on maybe another table for read notifications you can just mark it as "read" in the row.
If however you need universal notifications the structure just implements a third table called a pivot as you know. (I noticed you have the class names pluralized which is not recommended)
User -> Notification_User -> Notification
For ease you also could just soft-delete the notification_user row or notification themselves. You can simply just say ->withTrashed()->limit(x) to get previous notifications.
This really simplifies the work done by the DB and your code. The personal notifications allows you to order by creation/update and deal with read in two ways, soft-deletion and IsRead variables.
Your code becomes as simple as this.
Auth::user()->notifications()
Your User class has the following (assuming standard naming schemes)
public function notifications()
{
//You're free to append other requirements here
return $this->hasMany('App\Notification','id','user_id');
}
The Notification class has the inverse
public function user()
{
//You're free to append other requirements here
return $this->belongsTo('App\User','user_id','id');
}
If for some reason you require to know all unread notifications universally just query the Notification table.
Notification::where('isRead','null')->get();
Alternatively you can lazy load the users for each notification or group by users in this case for whatever purpose you need.
If this helped you to your solution could you mark it as the answer?
You can use the wherePivot and orWherePivot functions provided by laravel for relations. Link

Good Practices MVC

Assume I had a database with two tables:
customer
payment_info
The table customer had fields: name, address, payment_info_id
payment_info_id is a foreign key that links to a row in payment_info. payment_info has fields: id (which is linked to payment_info_id), bank, account number.
Because of my application's logic, each time a customer is created their payment information is stored in a separate row in the payment_info field which is linked to their row in the customer table.
I am using an MVC architecture.
Does it make more sense to keep this 'pure' and make two separate models, one for each table, and then crossload them and call methods from payment_info_controller in customer_controller, or to make a hybrid one which as soon as it creates a row in customer also creates one in payment_info?
Hope this makes sense!
You shouldn't be relying on controllers to do this. Put the logic in your model, behind a service layer(if desired), and call that from your controllers.
You should also reverse the FK setup. Stick customer id in payment_info and remove it payment_info_id from customer. That will make it so a customer can have multiple payments.
in the controller:
$user = new User(name, etc...);
$payment = new Payment(payment details...);
$user->applyPayment($paymentInfo);
$userService->save($user)
in the service:
function save($user){
//save user and update it with an id)
$user = $userDal->save($user);
//now that user has an id, you can generate/save payments.
$payment->save($user->getPayments());
}
You could then have the userService load the Data access layer for both user and payment.
Service/Facade info: http://www.dofactory.com/net/facade-design-pattern
NOTE: - you might want to come up with a better naming convention so its obvious that the payment will be saved/generated by that particular service. e.g SaveUserAndPayment($user)
Always keep it pure you dont need more unused methods to load than you could also from customer you do stuff while you have some customer params and need get something related to it, from payment you do stuff when you have some payment params and need dig something from that. You can always use payment or customer or any other models from any controller so keep it as pure as you can gl and hf ;)

How to keep data separate for businesses or groups of customers?

I've done quit a bit of programming with php/mysql on small scale personal projects. However I'm working on my first commercial app that is going to allow customers or businesses to log in and perform CRUD operations. I feel like a total noob asking this question but I have never had to do this before and cannot find any relevant information on the net.
Basically, I've created this app and have a role based system set up on my data base. The problem that I'm running into is how to separate and fetch data for the relevant businesses or groups.
I can't, for example, set my queries up like this: get all records from example table where user id = user id, because that will only return data for that user and not all of the other users that are related to that business. I need a way to get all records that where created by users of a particular business.
I'm thinking that maybe the business should have an id and I should form my queries like this: get all records from example where business id = business id. But I'm not even sure if that's a good approach.
Is there a best practice or a convention for this sort data storing/fetching and grouping?
Note:Security is a huge issue here because I'm storing legal data.
Also, I'm using the latest version of laravel 4 if that's any relevance.
I would like to hear peoples thoughts on this that have encountered this sort problem before and how they designed there database and queries to only get and store data related to that particular business.
Edit: I like to read and learn but cannot find any useful information on this topic - maybe I'm not using the correct search terms. So If you know of any good links pertaining to this topic, please post them too.
If I understand correctly, a business is defined within your system as a "group of users", and your whole system references data belonging to users as opposed to data belonging to a business. You are looking to reference data that belongs to all users who belong to a particular business. In this case, the best and most extensible way to do this would be to create two more tables to contain businesses and business-user relations.
For example, consider you have the following tables:
business => Defines a business entity
id (primary)
name
Entry: id=4, name=CompanyCorp
user => Defines each user in the system
id (primary)
name
Entry: id=1, name=Geoff
Entry: id=2, name=Jane
business_user => Links a user to a particular business
user_id (primary)
business_id (primary)
Entry: user_id=1, business_id=4
Entry: user_id=2, business_id=4
Basically, the business_user table defines relationships. For example, Geoff is related to CompanyCorp, so a row exists in the table that matches their id's together. This is called a relational database model, and is an important concept to understand in the world of database development. You can even allow a user to belong to multiple different companies.
To find all the names of users and their company's name, where their company's id = 4...
SELECT `user`.`name` as `username`, `business`.`name` as `businessname` FROM `business_user` LEFT JOIN `user` ON (`user`.`id` = `business_user`.`user_id`) LEFT JOIN `business` ON (`business`.`id` = `business_user`.`business_id`) WHERE `business_user`.`business_id` = 4;
Results would be:
username businessname
-> Geoff CompanyCorp
-> Jane CompanyCorp
I hope this helps!
===============================================================
Addendum regarding "cases" per your response in the comments.
You could create a new table for cases and then reference both business and user ids on separate columns in there, as the case would belong to both a user and a business, if that's all the functionality that you need.
Suppose though, exploring the idea of relational databases further, that you wanted multiple users to be assigned to a case, but you wanted one user to be elected as the "group leader", you could approach the problem as follows:
Create a table "case" to store the cases
Create a table "user_case" to store case-user relationships, just like in the business_user table.
Define the user_case table as follows:
user_case => Defines a user -> case relationship
user_id (primary)
case_id (primary)
role
Entry: user_id=1, case_id=1, role="leader"
Entry: user_id=2, case_id=1, role="subordinate"
You could even go further and define a table with definitions on what roles users can assume. Then, you might even change the user_case table to use a role_id instead which joins data from yet another role table.
It may sound like an ever-deepening schema of very small tables, but note that we've added an extra column to the user_case relational table. The bigger your application grows, the more your tables will grow laterally with more columns. Trust me, you do eventually stop adding new tables just for the sake of defining relations.
To give a brief example of how flexible this can be, with a role table, you could figure out all the roles that a given user (where user_id = 6) has by using a relatively short query like:
SELECT `role`.`name` FROM `role` RIGHT JOIN `user_case` ON (`user_case`.`role_id` = `role`.`id`) WHERE `user_case`.`user_id` = 6;
If you need more examples, please feel free to keep commenting.

How do you setup relationships with many foreign keys from the same table in PHP ActiveRecord?

I am building a real estate related website that real estate agents and investors can use to track properties submitted in the system and keep track of who is owed what profits. I have the following tables that I am having trouble figuring out how to setup the relationships for in my models using PHP ActiveRecord:
properties
id
primary_profit_sharing
secondary_profit_sharing
commission
referral_payment
users
id
name
email
payments
id
type (commission, referral_payment, etc.)
property_id
user_id
What is the proper way to setup these relationships using PHP ActiveRecord? I would like to be able to access the user information for each payment by something like $property->commission and $property->referral_payment but I can't figure out how to setup the relationships in the models to allow that.
I currently have payments belonging to users and properties, and users/payments have many payments. All the information I was is returned in the query, but not in an accessible ways. I have $property->users but no way of getting the user information for a particular payment type.
The only way I can think of to accomplish what I'm looking for is to setup a table for each payment type, but that doesn't seem like the best way to do it.
In the payments table, instead of using property_id and user_id, maybe you should use fk_object as the foreign key and do your joins using that field. fk_object represents the id of the user or the id of the property.

Categories