Questions about ZF-Oauth "official" database schema - php

I have a couple of questions about zf-oauth (Apigility), and php-oauth server database schema.
The database schema is:
CREATE TABLE oauth_clients (
client_id VARCHAR(80) NOT NULL,
client_secret VARCHAR(80) NOT NULL,
redirect_uri VARCHAR(2000) NOT NULL,
grant_types VARCHAR(80),
scope VARCHAR(2000),
user_id VARCHAR(255),
CONSTRAINT clients_client_id_pk PRIMARY KEY (client_id)
);
CREATE TABLE oauth_access_tokens (
access_token VARCHAR(40) NOT NULL,
client_id VARCHAR(80) NOT NULL,
user_id VARCHAR(255),
expires TIMESTAMP NOT NULL,
scope VARCHAR(2000),
CONSTRAINT access_token_pk PRIMARY KEY (access_token)
);
CREATE TABLE oauth_authorization_codes (
authorization_code VARCHAR(40) NOT NULL,
client_id VARCHAR(80) NOT NULL,
user_id VARCHAR(255),
redirect_uri VARCHAR(2000),
expires TIMESTAMP NOT NULL,
scope VARCHAR(2000),
id_token VARCHAR(2000),
CONSTRAINT auth_code_pk PRIMARY KEY (authorization_code)
);
CREATE TABLE oauth_refresh_tokens (
refresh_token VARCHAR(40) NOT NULL,
client_id VARCHAR(80) NOT NULL,
user_id VARCHAR(255),
expires TIMESTAMP NOT NULL,
scope VARCHAR(2000),
CONSTRAINT refresh_token_pk PRIMARY KEY (refresh_token)
);
CREATE TABLE oauth_users (
username VARCHAR(255) NOT NULL,
password VARCHAR(2000),
first_name VARCHAR(255),
last_name VARCHAR(255),
CONSTRAINT username_pk PRIMARY KEY (username)
);
CREATE TABLE oauth_scopes (
type VARCHAR(255) NOT NULL DEFAULT "supported",
scope VARCHAR(2000),
client_id VARCHAR (80),
is_default SMALLINT DEFAULT NULL
);
CREATE TABLE oauth_jwt (
client_id VARCHAR(80) NOT NULL,
subject VARCHAR(80),
public_key VARCHAR(2000),
CONSTRAINT jwt_client_id_pk PRIMARY KEY (client_id)
);
You can find it at:
https://github.com/zfcampus/zf-oauth2
https://bshaffer.github.io/oauth2-server-php-docs/
https://apigility.org/documentation/modules/zf-oauth2
So, this schema seems really "standard" because is adopted by Zend Technologies (zend framework and apigility), but I have some questions:
Why aren't any "ordinary" primary keys? (int auto increment field).
I would to use oauth_users table for registration account and the form's fields are "email" and "password". I could store email into oauth_users.username field, but It does not seem a good idea to use this field as a foreign key. Finally, my url looks better in profile-url/[:id] than profile-url/[:username/] (email in my case). So, I have to create a custom primary key or I could go against problems?
Why aren't any foreign keys? this questions is related to the first. I have to add foreign keys or I could go against problems? using oauth_users.username as foreign key for my other tables, It does not seem a good idea.

As you can see in the composer json require list ZF-Oauth2 is built on top of bshaffer/oauth2-server-php for which you can find the original documentation here. It has some nice explanations on the working of OAuth2. It is also the same repository that #Adam is referring to.
You can definitely customize these OAuth modules to a certain extend (like use your own table names). To do this you can introduce a custom OAuthAdapter with your own logic. There are also other modules available that do exactly that, like for example this zf-oauth2-doctrine module that is made for using OAuth2 with Doctrine 2.
That one comes with the following database diagram (source: https://github.com/API-Skeletons/zf-oauth2-doctrine):

Related

Why won't my foreign key create in MySQL?

I've tried many different ways to create table with a foreign key and trying to insert into phpMyAdmin. However, it just not working as I was expected.
Here are what I've so far:
CREATE TABLE user (
user_id BIGINT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(50) NOT NULL,
user_password VARCHAR(50) NOT NULL);
This works perfectly fine. However, if I try to add a table with a foreign key thus, it refuses to create:
CREATE TABLE article (
article_id INT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
article_title VARCHAR(100) NOT NULL,
article_content VARCHAR(1000) NOT NULL,
user_id INT(10) NOT NULL,
FOREIGN KEY (user_id) REFERENCES user (user_id));
This would not work as expected and would not add the table to the MySQL database. I get this error:
Cannot add foreign key constraint
How can I fix it?
We discovered in the comments that if a primary key is defined thus:
user_id BIGINT(10) UNSIGNED
then a foreign key like this will not work, since it needs to match on signedness (and I think type too):
user_id INT(10) NOT NULL
This works fine:
user_id BIGINT(10) UNSIGNED NOT NULL
Here's a Fiddle to demonstrate it working.

Define relationships in database for CakePHP

Im trying out a sample project in CakePHP. It is taken from the cakePHP documentation. It has a total of 4 tables and two of the are listed here.
CREATE TABLE users (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password CHAR(40) NOT NULL,
group_id INT(11) NOT NULL,
created DATETIME,
modified DATETIME
);
CREATE TABLE posts (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_id INT(11) NOT NULL,
title VARCHAR(255) NOT NULL,
body TEXT,
created DATETIME,
modified DATETIME
);
As you can see the id from the users table is added to the posts table as a foreign key in the form of user_id. But in the sample there are no relationships defined. I mean normally we would explicitly define user_id as a foreign key by adding the constraints (in my case using the Relation View of phpMyAdmin). But it is not done here or we are not instructed to do so. When using Cake Bake console to bake our Models do we need this foreign key constraints in place or does cakephp figure them out automatically?
Convention over configuration
Cakephp figures them out automatically for you but you have to follow the naming conventions

Codeigniter managing user roles

How to divide multiple users access and permissions? i did it first time by creating different dashboard for 3 type users for example administrators redirected to user/admin/dashboard and moderators to user/moderator/dashboard and and so on. but i want to find an easy way to do this by knowing user roles and manage their access.
my user table is something looks likes :
mysql:
CREATE TABLE IF NOT EXISTS `users` (
`user_id` int(9) NOT NULL AUTO_INCREMENT,
`email_add` varchar(35) COLLATE utf8_bin DEFAULT NULL,
`password` varchar(128) COLLATE utf8_bin NOT NULL,
`last_login` datetime NOT NULL,
`usr_typ_id` int(4) DEFAULT NULL,
`permissions` varchar(50) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `email_add` (`email_add`),
KEY `fk_usr_typ_id` (`usr_typ_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=92090005 ;
-
ALTER TABLE `users`
ADD CONSTRAINT `fk_usr_typ_id` FOREIGN KEY (`usr_typ_id`) REFERENCES `user_type` (`type_id`);
Once i used drupal it was perfect, i wish just something look likes that,nothing completely like that.:)
Use the Permission Class.
Watch this video to see this in action.
I usually use a separated table to define user acces. Let's say its name is tbl_acces and it has 2 columns: usr_typ_id & menu_id.
A menu_id is can be a page or a function in the controllers. So if user access a function in controller via URL it will do some checking whether user is authorized to access that page/menu.

Polymorphic Associations or something easier

This is my first post and I can't seem to find the answer anywhere....
I have a database that has multiple companies,each company has multiple locations.
I'm running into problems trying to define the contacts. Some contacts need to be global and available
at any location....some contacts only need to exist for one location. In the contact_info table below
we specify the visibility of the contact (company or location). However the location needs to choose its primary contact.
That leaves a FK from contact -> location and from location -> contact.
I know there is another table involved but I can't seem to conceptualize it.
CREATE TABLE `company_info` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`));
CREATE TABLE `location_info` (
`id` INT NOT NULL AUTO_INCREMENT,
`company_info` INT NOT NULL DEFAULT -1,
`name` VARCHAR(100) NOT NULL DEFAULT '',
`primary_contact_id` INT NOT NULL DEFAULT -1,
PRIMARY KEY(`id`),
UNIQUE KEY(`company_id`,`name`),
FOREIGN KEY (company_id) REFERENCES company_info(id)
FOREIGN KEY (primary_contact_id) REFERENCES contact_info(id));
CREATE TABLE `contact_info` (
`id` INT NOT NULL AUTO_INCREMENT,
`company_id` INT
`location_id` INT,
`type` ENUM('Company','Location') NOT NULL DEFAULT 'Company',
`first_name` VARCHAR(50) NOT NULL DEFAULT '',
`last_name` VARCHAR(50) NOT NULL DEFAULT '',
PRIMARY KEY(`id`),
UNIQUE KEY(`id`,`company_id`,`location_id`),
FOREIGN KEY (location_id) REFERENCES location_info(id),
FOREIGN KEY (company_id) REFERENCES company_info(id)
The most effective way would be splitting it up so that there's a table for your companies, a table with your users, and a table solely for the purpose of storing all connections (i.e. EntryID, UserID, CompanyID). This way you'll be able to easily load them afterwards.

MySQL Structure for a social network

I'm experimenting by making a social network from scratch in PHP/MySQL, but I'm having trouble thinking of the optimal MySQL structure for it, currently I have:
This is a table which stores all user info:
fname varchar (300),
sname varchar (300),
pass varchar (400),
email varchar (300),
gender varchar (300),
dob varchar (200),
uid varchar (300),
PRIMARY KEY (id)
This is created when a user signs up, their own personal table:
id int(20) NOT NULL auto_increment,
uid varchar (300),
photo_url varchar (400),
pfid varchar (300),
phototime datetime,
video_url varchar (400),
vfid varchar (300),
videotime datetime,
status longtext,
sid varchar (300),
statustime datetime,
blog longtext,
bid varchar (300),
blogtime datetime,
about_bio longtext,
about_current_job longtext,
about_secondary_school longtext,
about_primary_school longtext,
about_college longtext,
about_university longtext,
about_workemail longtext,
about_homeemail longtext,
about_phonenumber longtext,
about_relationshipstatus longtext,
about_relationshipwith longtext,
PRIMARY KEY (id)
)";
The sessions table to track whether someone is logged in or not:
id int(20) NOT NULL auto_increment,
sid varchar(300),
uid varchar(300),
PRIMARY KEY (id)
Haven't gotten onto relationships yet but I was thinking:
id int(20) NOT NULL auto_increment,
requestby varchar(200),
requestto varchar(200),
status varchar(200)
(Before anyone asks, this is purely just for the learning experience, nothing more)
Well, you definitely shouldn't have one table per user. I think a database structure more like this would work really well:
CREATE TABLE users (
userID INT NOT NULL AUTO_INCREMENT,
firstName VARCHAR(30),
lastName VARCHAR(30),
password CHAR(32), -- should be encrypted, CHAR is better if the field is always the same length
email VARCHAR(64) NOT NULL, -- not null if this is what you will use as a "username"
PRIMARY KEY (userID)
);
CREATE TABLE personalInfo (
userID INT NOT NULL,
gender ENUM ('MALE', 'FEMALE'),
dateOfBirth DATE,
phoneNumber VARCHAR(15),
personalEmail VARCHAR(64), -- may or may not be the same as the email field in the "users" table
workEmail VARCHAR(64),
bio TEXT,
FOREIGN KEY (userID) REFERENCES users (userID)
);
/* this table is not specific to any single user. It is just a list of jobs that have been created */
CREATE TABLE jobs (
jobID INT NOT NULL AUTO_INCREMENT,
company VARCHAR(100),
title VARCHAR(100),
description TEXT,
PRIMARY KEY (jobID)
);
/* the workInfo table will hold one entry per user per job. So if a user has held five jobs,
there will be five rows with that userID in this table, each with a different jobID, which
refers to an entry in the "jobs" table above. */
CREATE TABLE workInfo (
userID INT NOT NULL,
jobID INT NOT NULL,
startDate DATE,
endDate DATE, -- can set this to null if it's the user's current job
FOREIGN KEY (userID) REFERENCES users (userID),
FOREIGN KEY (jobID) REFERENCES jobs (jobID)
);
CREATE TABLE schools (
schoolID INT NOT NULL AUTO_INCREMENT,
schoolName VARCHAR(100),
-- any other information you want to provide about the school (city, address, phone, etc)
PRIMARY KEY (schoolID)
);
CREATE TABLE schoolPrograms (
programID INT NOT NULL AUTO_INCREMENT,
programName VARCHAR(100),
-- any other information you want to provide about the program (department, teachers, etc)
PRIMARY KEY (programID)
);
CREATE TABLE educationInfo (
userID INT NOT NULL,
schoolID INT,
programID INT,
startDate DATE,
endDate DATE,
FOREIGN KEY (userID) REFERENCES users (userID),
FOREIGN KEY (schoolID) REFERENCES schools (schoolID),
FOREIGN KEY (programID) REFERENCES schoolPrograms (programID)
);
CREATE TABLE relationships (
userID INT NOT NULL,
userID2 INT, -- allowed to be null if the user is single or does not specify who they are in a relationship with
status ENUM ('SINGLE', 'IN A RELATIONSHIP', 'MARRIED', 'IT''S COMPLICATED' /* etc */),
FOREIGN KEY (userID) REFERENCES users (userID)
);
/* each photo is created here. This way, when a user wants to share a photo,
we don't have to duplicate each column. We just create another row in
the "userPhotos" table below that) REFERENCES the same photoID. */
CREATE TABLE photos (
photoID INT NOT NULL AUTO_INCREMENT,
url VARCHAR(200),
caption VARCHAR(200),
dateOfUpload TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (photoID)
);
CREATE TABLE userPhotos (
userID INT NOT NULL,
photoID INT NOT NULL,
FOREIGN KEY (userID) REFERENCES users (userID),
FOREIGN KEY (photoID) REFERENCES photos (photoID)
);
/* vidoes, handled exactly the same as photos */
CREATE TABLE videos (
videoID INT NOT NULL AUTO_INCREMENT,
url VARCHAR(200),
caption VARCHAR(200),
dateOfUpload TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (videoID)
);
CREATE TABLE userVideos (
userID INT NOT NULL,
videoID INT NOT NULL,
FOREIGN KEY (userID) REFERENCES users (userID),
FOREIGN KEY (videoID) REFERENCES videos (videoID)
);
CREATE TABLE status (
userID INT NOT NULL,
status TEXT,
FOREIGN KEY (userID) REFERENCES users (userID)
);
Don't use large varchars for all those fields. Friendship status can be just an int if you keep a lookup table (or a list in your code) that explains each value.
If the user table has an auto incrementing ID, you could use that ID for foreign key relationships. Even if you don't want UID to be an integer, you could still make it a GUID or something else that is much, much smaller than a varchar.
These tables only specify a profile and maybe a relationship, but there is so much more. Even something as simple as Twitter has a table of tweets, lists, accounts to put in a list, users that follow a list, direct messages (although those could theoretically be in the same table as Tweets), linked apps, blocked users and much, much more.
So I think first of all, you should think about what your social network should be, what it should look like, what features should it have. Then, strip that down to only the most essential features. Then, strip it down a little more, you're still thinking too big. ;)
When you got clear what your minimum desirement are, it will probably be much clearer to you what table you would need.
Don't forget to add constraints and indexes!
Note that in practice, Twitter, Facebook and the other large networks don't use MySQL at all, but to practice, MySQL is fine.

Categories