Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Σε αυτή την περιοχή μπορείτε να βρείτε ή να αναζητήσετε πληροφορίες σχετικές με την PHP

Συντονιστές: WebDev Moderators, Super-Moderators, PHP Moderators

Άβαταρ μέλους
Khronos
Δημοσιεύσεις: 754
Εγγραφή: 11 Δεκ 2006 14:43
Τοποθεσία: Ηράκλειο

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από Khronos » 30 Σεπ 2013 23:15

korgr έγραψε:Αν το ότι αισθάνομαι υπερήφανος για ένα έργο που το δουλεύω τρία χρόνια (και καλά να είμαι να το συνεχίζω), ισούται με την έκφραση "καβάλησα το καλάμι", τότε ναι, δηλώνω ένοχος των κατηγοριών.

Και ειλικρινά δηλώνω με απόλυτη σιγουριά, πως αν ήμουν "παιδί των πανεπιστημίων", δεν θα το είχα καταφέρει. Δυστυχώς πολύ λίγοι έσκυψαν πάνω σε αυτό το έργο και κατάλαβαν πόσο διαφορετική φιλοσοφία κρύβεται από πίσω. Οι περισσότεροι θεωρούν πως είναι απλά ένας content type generator -σιγά τα ωά- και απλά επιστρέφουν είτε στα δημοφιλή CMS είτε στα δημοφιλή PHP Frameworks. Στην πορεία κατάλαβα πως το πρόβλημα έγκειται στο ότι δεν μπόρεσα εγώ να τους δώσω να καταλάβουν και έτσι έμεινε να εξυπηρετεί κάποιους λίγους αιρετικούς που πλέον παράγουμε σύνθετα έργα πολύ γρήγορα και εύκολα.

Κάποια πράγματα για να τα συλλάβεις και να τα υλοποιήσεις πρέπει να σκέφτεσαι out of the box. Σε αυτό εξέφρασα την αντίρρηση μου όταν άκουσα το "ΜΗΝ ΤΟ ΚΑΝΕΙΣ"! Τα στεγανά περιορίζουν τα μυαλά και τα μυαλά πρέπει να είναι ελεύθερα να δημιουργούν ακόμα και στα όρια της φαντασίας! Αυτό που για κάποιους είναι λάθος, μερικές φορές μπορεί να είναι ο θεμέλιος λίθος για κάτι πραγματικά ξεχωριστό!
Καλά κάνεις και είσαι υπερήφανος αλλά το "είμαι υπερήφανος" απο το "έχω φτιάξει δικό μου framework και δουλεύει άρα εγώ είμαι σωστός (στο repeat)" είναι τελείως διαφορετικά πράγματα.

Επίσης το θέμα με το "ΜΗΝ ΤΟ ΚΑΝΕΙΣ" το έκανες θέμα επειδή χρησιμοποιείς εσύ μια τέτοια φιλοσοφία στο σύστημα σου. Δεν εξέτασες αν ταιριάζει ή όχι στη συγκεκριμένη περίπτωση.

Αυτά απο μένα (εντελώς φιλικά). Έχει και breaking bad...

geomagas
Δημοσιεύσεις: 667
Εγγραφή: 06 Απρ 2013 13:36
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από geomagas » 30 Σεπ 2013 23:29

fafos έγραψε:@geomapa... me poly fora mas mphkes kai mas to paizeis polyxeros..
Σε ποιον μπήκα;;; Από την αρχή του post απλά απαντώ σε ερωτήσεις. Και σε όλα τα άλλα posts το ίδιο.
Μήπως απλά τρολάρεις;
fafos έγραψε:se afhno na ektithese giati myalo den vazeis...
Πότε εκτέθηκα;;;
Μήπως απλά τρολάρεις;
fafos έγραψε: Tha se symvouleua an den exeis skylo na pareis enan kai na ton kaneis voltes sto tetragono..
Να αφήσεις τις συμβουλές. Δεν σου ζήτησα καμία, και δεν είσαι σε θέση.
Μήπως απλά τρολάρεις;
fafos έγραψε:Sto thema tou thread.. aplos katevase thn vash tou phpbb kai pairneis auto pou zhtas ston tropo pou dinei levels stous users... ektos kai an mas apodeixei o geomapas poso "xountini" einai kai oi developers tou phpbb kai pame paso.. :lol:
ΕΓΩ θα κατεβάσω τη βάση του phpbb για να σου αποδείξω ότι δεν έχεις ιδέα για τί πράγμα μιλάς; Πας καλά;;;
ΕΣΥ ισχυρίστηκες ότι όλα αυτά λύνονται με έναν πίνακα. Πούντος;;;;

Δεν αφήνεις την υπεροψία και να παραδεχτείς ότι δεν έχεις τίποτα να πεις, απλά τρολάρεις;
(βέβαια πάντα στα πλαίσια της αλληλεγγύης των Illuminati... ok...)

Άβαταρ μέλους
fafos
Script Master
Δημοσιεύσεις: 6231
Εγγραφή: 30 Νοέμ 2004 03:09

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από fafos » 30 Σεπ 2013 23:39

Apo pou thes na arxiso? apo to thread pou mou eipes na "ksekouvalhso" giati elega asxeta pragmata? (nautakia pou p..me ginate kapetanaioi) kai sto telos apodeixthke oti esy eleges sto palikari alla ntalon? (kai sto telos tou thn eipes kiolas)

To phpbb to proteino sto palikari pou anoixe to thema.. esena ti na sou po? esy eisai san ton Jack Norris..

toulaxiston emathes ti einai to domdocument? :lol:
Οι πάνες και οι πολιτικοί πρέπει να αλλάζονται συχνά για τον ίδιο λόγο...

Άβαταρ μέλους
korgr
Honorary Member
Δημοσιεύσεις: 5067
Εγγραφή: 07 Οκτ 2008 18:30
Τοποθεσία: Corinth
Επικοινωνία:

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από korgr » 30 Σεπ 2013 23:43

fafo περισσεύει καθόλου popcorn? :D

@Khronos
Αιτιολόγησα τον λόγο της παρέμβασης μου.
Φυσικά ο καθένας έχει το δικαίωμα να θεωρεί ότι θέλει.

Πάντως κατάλαβα το ύφος των λεγομένων σου, no hard feelings :)
Γνωρίζω πως ο γραπτός λόγος μου είναι εύκολα παρεξηγήσιμος...

geomagas
Δημοσιεύσεις: 667
Εγγραφή: 06 Απρ 2013 13:36
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από geomagas » 30 Σεπ 2013 23:56

fafos έγραψε:Apo pou thes na arxiso? apo to thread pou mou eipes na "ksekouvalhso" giati elega asxeta pragmata?
Σε κανέναν δεν είπα ποτέ να "ξεκουβαλήσει". Ψεύδεσαι. Σου είπα ότι ήσουν άσχετος με το θέμα, και δεν προσέφερες τίποτα στη συζήτηση.
Και είχα προφανώς δίκιο, γιατί αλλιώς θα καθόσουν και θα συνέχιζες. Εσύ αντίθετα έβαλες την ουρά στα σκέλια, και το κράτησες μανιάτικο.
Και ο μόνος λόγος που τρολάρεις, ψεύδεσαι και προσβάλλεις είναι εκείνο το post.
Αλλά είδες; Η ιστορία επαναλαμβάνεται. Και πάλι είσαι άσχετος με το θέμα, και πάλι δεν βοηθάς σε τίποτα, και πάλι κάποια άλλη φορά θα με περιμένεις στη γωνία για να προσποιηθείς ότι με εκδικείσαι...
fafos έγραψε:(nautakia pou p..me ginate kapetanaioi)
Αν νομίζεις ότι είσαι ο πρώτος που προσπαθεί να με κάνει να χάσω την ψυχραιμία μου με προσβολές, κάνεις λάθος.
Αυτά τα κάναμε και στο Γυμνάσιο. Απλά, εγώ μεγάλωσα από τότε....
fafos έγραψε: kai sto telos apodeixthke oti esy eleges sto palikari alla ntalon? (kai sto telos tou thn eipes kiolas)
...Πως ακριβώς αποδείχθηκε αυτό;;;; :roll:
fafos έγραψε:To phpbb to proteino sto palikari pou anoixe to thema.. esena ti na sou po? esy eisai san ton Jack Norris..
Τι να μου πεις; Να σεβαστείς τον εαυτό σου, να σταματήσεις το τρολάρισμα και να εξηγήσεις αυτό που ξεκίνησες.
ΠΟΥ είναι ο πίνακας; Οεοοοο;
Α, και είναι CHUCK Norris. C-H-U-C-K.
fafos έγραψε:toulaxiston emathes ti einai to domdocument? :lol:
Ναι. Τι σχέση έχει;
Αλλά ξέχασα... Δεν χρειάζεται να έχει....

Antonis78
Δημοσιεύσεις: 60
Εγγραφή: 24 Φεβ 2006 14:41

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από Antonis78 » 01 Οκτ 2013 11:08

Ρε παιδιά, γιατί τόση αντιπαλότητα και αμφισβήτηση; Ο καθένας έχει τα διαπιστευτήριά του, τη εμπειρία του και τις γνώσεις του. Δεν χρειάζεται να τσακωνόμαστε! Να διαφωνούμε, ναι, άλλωστε έτσι υπάρχει εξέλιξη, να παίρνουμε τα καλά απ' ότι προτείνει ο καθένας και να φτιάχνουμε το καλύτερο δυνατό.

Στο θέμα μας τώρα, τα παιδιά που λένε ότι υπάρχει καλύτερη λύση, ας την προτείνουν να το δούμε. Ευχαρίστως θα έβλεπα μία άλλη λύση, και εγώ και όλοι νομίζω. Για αυτό άνοιξα το θέμα, για να πάρω ιδέες. Προς το παρόν ακολουθώ τον τρόπο σκέψης του geomagas για να δω που θα καταλήξει και αν όντως κάνει αυτό που θέλω θα το χρησιμοποιήσω, όπως θα κάνω και με τις δικές σας προτάσεις.
geomagas έγραψε:Εδώ κάνεις ένα λάθος. Είπαμε ότι RegisteredCustomer is a Customer και ταυτόχρονα RegisteredCustomer is a User.
Άρα, το κύριο κλειδί θα πρέπει να είναι συγχρόνως και ξένο κλειδί προς τους δύο πίνακες.
Ένας πίνακας σαν αυτόν που λες,
- αφ' ενός θα σου επιτρέψει να εισάγεις εγγραφές με customer<>userId (δηλ. άλλο person σαν χρήστης και άλλο σαν customer) και
- αφ' ετέρου θα έχεις πολλαπλή αντιστοίχιση users/customers, πχ οι εγγραφές με customer=48 και customer=65 να αντιστοιχούν και οι δύο στο userid=76.
Το σωστό είναι να υπάρχει ένα μόνο πεδίο: RegisteredCustomer(customer [pk][fk Customer][fk User]).
Άρα ο πίνακας γίνεται έτσι:
RegisteredCustomers
customer -> pk, fk Customers, fk Users
geomagas έγραψε:Νόμιζα ότι η σχέση Admin<-->Supervisor είναι 1:Ν (ο κάθε supervisor είναι κάτω από έναν και μόνο admin).
Αν είναι έτσι, προσθέτεις ένα admin [fk Admins] στον Supervisor και καταργείς τον Admins_Supervisors.
Κατά τα άλλα, συμφωνούμε.
Όχι, όλοι οι Admins μπορούν να δούν όλους τους Supervisors, για αυτό έφτιαξα τον πίνακα Admins_Supervisors.
geomagas έγραψε:Ναι θα μπορούσες, αλλά δεν βλέπω τη σκοπιμότητα (τι θα κερδίσεις).
Επίσης, είναι λεπτή η γραμμή που χωρίζει το flexibility από την αναρχία... Σκέψου το.
Σκεφτόμουν έναν πίνακα Persons2Persons γιατί θέλω να αποφύγω όταν φτιάχνω καινούργιο επίπεδο να πρέπει να φτιάξω τις σχέσεις των πινάκων και κατα συνέπεια τα queries από την αρχή.
nbc έγραψε:Η ουσία είναι πως το πρόβλημα του Antonis78 είναι πολύ απλό και λύνεται με 1 πίνακα για τους πρακτικούς, και 2 για τους πιουρίστες.
Δώσε μου ένα παράδειγμα, πως θα το υλοποιούσες εσύ, γιατί και εγώ αυτό σκεφτόμουν στην αρχή αλλά στην πορεία δεν μου βγήκε.
fafos έγραψε:Sto thema tou thread.. aplos katevase thn vash tou phpbb kai pairneis auto pou zhtas ston tropo pou dinei levels stous users...
Το εγκατέστησα και το βλέπω τώρα. Απλά να επισημάνω ότι δεν έχω θέμα με permissions (τι μπορεί να κάνει ένας χρήστης και τι όχι) αλλά με σύνδεση χρηστών. Θέλω να φτιάξω ένα δέντρο δηλαδή. Thanks!

Σας ευχαριστώ ΟΛΟΥΣ!

geomagas
Δημοσιεύσεις: 667
Εγγραφή: 06 Απρ 2013 13:36
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από geomagas » 01 Οκτ 2013 11:54

Antonis78 έγραψε:Ρε παιδιά, γιατί τόση αντιπαλότητα και αμφισβήτηση; Ο καθένας έχει τα διαπιστευτήριά του, τη εμπειρία του και τις γνώσεις του. Δεν χρειάζεται να τσακωνόμαστε! Να διαφωνούμε, ναι, άλλωστε έτσι υπάρχει εξέλιξη, να παίρνουμε τα καλά απ' ότι προτείνει ο καθένας και να φτιάχνουμε το καλύτερο δυνατό.
Στη θεωρία ναι. Στην πράξη δυστυχώς, ορισμένοι απλά δεν αντέχουν να υπάρχει διαφορετική άποψη από τη δική τους.
Πρέπει να τη χλευάσουν, να τη φιμώσουν, να τη λασπώσουν ώστε να μη χρειαστεί να αναμετρηθούν ποτέ με αυτή (σάμπως είναι θέμα αναμέτρησης... τεσπα!).
Antonis78 έγραψε:Στο θέμα μας τώρα, τα παιδιά που λένε ότι υπάρχει καλύτερη λύση, ας την προτείνουν να το δούμε. Ευχαρίστως θα έβλεπα μία άλλη λύση, και εγώ και όλοι νομίζω. Για αυτό άνοιξα το θέμα, για να πάρω ιδέες. Προς το παρόν ακολουθώ τον τρόπο σκέψης του geomagas για να δω που θα καταλήξει και αν όντως κάνει αυτό που θέλω θα το χρησιμοποιήσω, όπως θα κάνω και με τις δικές σας προτάσεις.
geomagas έγραψε:Εδώ κάνεις ένα λάθος. Είπαμε ότι RegisteredCustomer is a Customer και ταυτόχρονα RegisteredCustomer is a User.
Άρα, το κύριο κλειδί θα πρέπει να είναι συγχρόνως και ξένο κλειδί προς τους δύο πίνακες.
Ένας πίνακας σαν αυτόν που λες,
- αφ' ενός θα σου επιτρέψει να εισάγεις εγγραφές με customer<>userId (δηλ. άλλο person σαν χρήστης και άλλο σαν customer) και
- αφ' ετέρου θα έχεις πολλαπλή αντιστοίχιση users/customers, πχ οι εγγραφές με customer=48 και customer=65 να αντιστοιχούν και οι δύο στο userid=76.
Το σωστό είναι να υπάρχει ένα μόνο πεδίο: RegisteredCustomer(customer [pk][fk Customer][fk User]).
Άρα ο πίνακας γίνεται έτσι:
RegisteredCustomers
customer -> pk, fk Customers, fk Users
Ναι, αυτό λέω.
Antonis78 έγραψε:
geomagas έγραψε:Νόμιζα ότι η σχέση Admin<-->Supervisor είναι 1:Ν (ο κάθε supervisor είναι κάτω από έναν και μόνο admin).
Αν είναι έτσι, προσθέτεις ένα admin [fk Admins] στον Supervisor και καταργείς τον Admins_Supervisors.
Κατά τα άλλα, συμφωνούμε.
Όχι, όλοι οι Admins μπορούν να δούν όλους τους Supervisors, για αυτό έφτιαξα τον πίνακα Admins_Supervisors.
Άλλο τι είναι κάποιος (σχέσεις is-a και αφορά classifcation), άλλο σε ποιόν "ανήκει" (η δομή που περιέγραψεις στην αρχή και αφορά ιεραρχία/delegation) και άλλο τι βλέπει κάποιος.
Τα δυο πρώτα είναι θεμελιώδη, και θα πρέπει (αν καταλήξεις σε τέτοιο σχήμα) να τα υλοποιήσεις σαν constraints στο επίπεδο 0 της ΒΔ, δηλαδή στους πίνακες.
Το τρίτο είναι παραγόμενο από τα δυο πρώτα, και υλοποιείται σε πιο πάνω επίπεδο, με select (είτε σε views, είτε όσο ψηλότερα θέλεις να το σπρώξεις -- βλ. php). Επίσης, εδώ παίζει το Row Level Security.
Antonis78 έγραψε:
geomagas έγραψε:Ναι θα μπορούσες, αλλά δεν βλέπω τη σκοπιμότητα (τι θα κερδίσεις).
Επίσης, είναι λεπτή η γραμμή που χωρίζει το flexibility από την αναρχία... Σκέψου το.
Σκεφτόμουν έναν πίνακα Persons2Persons γιατί θέλω να αποφύγω όταν φτιάχνω καινούργιο επίπεδο να πρέπει να φτιάξω τις σχέσεις των πινάκων και κατα συνέπεια τα queries από την αρχή.
Ναι εκεί πήγε και μένα το μυαλό μου.
Σημείωσε πάντως ότι δεν γλιτώνεις, απαραίτητα, και πολλά με αυτόν τον τρόπο. Αν χρειαστεί να κάνεις αλλαγές, πάλι θα χρειαστεί να τις κάνεις στην εφαρμογή, όπου εκ των πραγμάτων θα έχεις μετατοπίσει εξ αρχής τον έλεγχο εγκυρότητας / συνέπειας των δεδομένων σου.
Φαινομενικά έχεις δυο επιλογές:
α) Την "αυστηρή", τυποποιημένη προσέγγιση με τους πολλούς πίνακες, τα constraints και τη δουλειά που χρειάζεται στη σχεδίαση
β) Την εντελώς "χύμα", με έναν πίνακα που όλοι είναι εκεί μέσα, άντε κι άλλον ένα Person2Person που να ορίζει το δένδρο.
Φαινομενικά όμως. Στην πραγματικότητα έχεις όλο το φάσμα των επιλογών από το (α) ως το (β) και μπορείς να καταλήξεις σε τι βαθμό και με ποιο συνδυασμό θα βρεις τη δική σου "χρυσή τομή", όπως είχα πει και σ' ένα άλλο post.
Antonis78 έγραψε:
nbc έγραψε:Η ουσία είναι πως το πρόβλημα του Antonis78 είναι πολύ απλό και λύνεται με 1 πίνακα για τους πρακτικούς, και 2 για τους πιουρίστες.
Δώσε μου ένα παράδειγμα, πως θα το υλοποιούσες εσύ, γιατί και εγώ αυτό σκεφτόμουν στην αρχή αλλά στην πορεία δεν μου βγήκε.
fafos έγραψε:Sto thema tou thread.. aplos katevase thn vash tou phpbb kai pairneis auto pou zhtas ston tropo pou dinei levels stous users...
Το εγκατέστησα και το βλέπω τώρα. Απλά να επισημάνω ότι δεν έχω θέμα με permissions (τι μπορεί να κάνει ένας χρήστης και τι όχι) αλλά με σύνδεση χρηστών. Θέλω να φτιάξω ένα δέντρο δηλαδή. Thanks!
Δεν θα έπρεπε να χρειάζεται να το επαναλαμβάνεις...
Αλλά μην αγχώνεσαι, εγώ ήμουν ο στόχος. Έχουμε προηγούμενα.... :-?
Antonis78 έγραψε:Σας ευχαριστώ ΟΛΟΥΣ!

Antonis78
Δημοσιεύσεις: 60
Εγγραφή: 24 Φεβ 2006 14:41

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από Antonis78 » 01 Οκτ 2013 12:45

geomagas έγραψε:Άλλο τι είναι κάποιος (σχέσεις is-a και αφορά classifcation), άλλο σε ποιόν "ανήκει" (η δομή που περιέγραψεις στην αρχή και αφορά ιεραρχία/delegation) και άλλο τι βλέπει κάποιος.
Δεν το εξέφρασα σωστά, εννοώ ότι όλοι οι Supervisors ανήκουν σε όλους τους Admins, όπως πολύ σωστά επισημαίνεις.
geomagas έγραψε:Ναι εκεί πήγε και μένα το μυαλό μου.
Σημείωσε πάντως ότι δεν γλιτώνεις, απαραίτητα, και πολλά με αυτόν τον τρόπο. Αν χρειαστεί να κάνεις αλλαγές, πάλι θα χρειαστεί να τις κάνεις στην εφαρμογή, όπου εκ των πραγμάτων θα έχεις μετατοπίσει εξ αρχής τον έλεγχο εγκυρότητας / συνέπειας των δεδομένων σου.
Φαινομενικά έχεις δυο επιλογές:
α) Την "αυστηρή", τυποποιημένη προσέγγιση με τους πολλούς πίνακες, τα constraints και τη δουλειά που χρειάζεται στη σχεδίαση
β) Την εντελώς "χύμα", με έναν πίνακα που όλοι είναι εκεί μέσα, άντε κι άλλον ένα Person2Person που να ορίζει το δένδρο.
Φαινομενικά όμως. Στην πραγματικότητα έχεις όλο το φάσμα των επιλογών από το (α) ως το (β) και μπορείς να καταλήξεις σε τι βαθμό και με ποιο συνδυασμό θα βρεις τη δική σου "χρυσή τομή", όπως είχα πει και σ' ένα άλλο post.
Δηλαδή, απ' ότι καταλαβαίνω, με την δομή αυτή που χρειάζομαι δεν μπορώ να έχω το flexibility που θέλω. Να μπορώ να φτιάξω καινούργια επίπεδα μέσω της εφαρμογής χωρίς να χρειάζεται να αλλάξω πίνακες, σχέσεις πινάκων και queries. Σωστά; Επιμένω σε αυτό γιατί αυτή την στιγμή πρέπει να ξαναγράψω την εφαρμογή γιατί ο προηγούμενος είχε προβλέψει 4 επίπεδα χρηστών (Admins -> Supervisors -> Account Managers -> Customers) και ήταν όλα "hardcoded" στην εφαρμογή. Τώρα λοιπόν, που παρουσιάστηκε η ανάγκη για ένα ενδιάμεσο level (Sales Admins) πρέπει εγώ να ξαναφτιάξω την εφαρμογή (ο άλλος έφυγε)!!!! Το ιδανικό σενάριο, θα ήταν κάτι το οποίο θα μου δίνει την δυνατότητα αν μου ζητήσουν άλλο ένα level (πχ Sub Admin, ενδιάμεσα Admin & Supervisor) να το κάνω μέσα από το administration interface και μην χρειάζεται να αλλάξω queries. Σε αυτό πήγαινε η σκέψη του να έχω πίνακα με ιεραρχίες και ονόματα πινάκων.
geomagas έγραψε:
Antonis78 έγραψε:Τι μορφή θα έχει το query αν θέλουμε πχ να δούμε τους Customers ενός Supervisor;
Ακόμα δεν φτάσαμε εκεί. Το παραπάνω σχήμα σου εξασφαλίζει τις απαιτήσεις σου, όλες εκτός από μία:
Antonis78 έγραψε:- Ο καθε Account Manager μπορεί να ανήκει σε πολλούς Sales Admin (του ίδιου Supervisor όμως)
Αλλά επειδή είναι λίγο πιο πολύπλοκο, προτιμώ να το πούμε αφού ξεκαθαρίσουμε με τα υπόλοιπα.
Νομίζω ότι είναι είναι ξεκάθαρα τα υπόλοιπα, πως θα υλοποιήσουμε αυτό;

geomagas
Δημοσιεύσεις: 667
Εγγραφή: 06 Απρ 2013 13:36
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από geomagas » 01 Οκτ 2013 14:23

Antonis78 έγραψε:
geomagas έγραψε:Άλλο τι είναι κάποιος (σχέσεις is-a και αφορά classifcation), άλλο σε ποιόν "ανήκει" (η δομή που περιέγραψεις στην αρχή και αφορά ιεραρχία/delegation) και άλλο τι βλέπει κάποιος.
Δεν το εξέφρασα σωστά, εννοώ ότι όλοι οι Supervisors ανήκουν σε όλους τους Admins, όπως πολύ σωστά επισημαίνεις.
Αν είναι έτσι, δεν χρειάζεσαι ούτε 1:Ν συσχέτιση (FK) ούτε M:N (ξεχωριστό πίνακα).
Να ξέρεις ότι πάντα οι συσχετίσεις αφορούν (και επιβάλλουν) περιορισμούς. Αν δεν υπάρχει περιορισμός, δεν χριεάζεται να εφαρμόσεις κανόνα.
Antonis78 έγραψε:
geomagas έγραψε:Ναι εκεί πήγε και μένα το μυαλό μου.
Σημείωσε πάντως ότι δεν γλιτώνεις, απαραίτητα, και πολλά με αυτόν τον τρόπο. Αν χρειαστεί να κάνεις αλλαγές, πάλι θα χρειαστεί να τις κάνεις στην εφαρμογή, όπου εκ των πραγμάτων θα έχεις μετατοπίσει εξ αρχής τον έλεγχο εγκυρότητας / συνέπειας των δεδομένων σου.
Φαινομενικά έχεις δυο επιλογές:
α) Την "αυστηρή", τυποποιημένη προσέγγιση με τους πολλούς πίνακες, τα constraints και τη δουλειά που χρειάζεται στη σχεδίαση
β) Την εντελώς "χύμα", με έναν πίνακα που όλοι είναι εκεί μέσα, άντε κι άλλον ένα Person2Person που να ορίζει το δένδρο.
Φαινομενικά όμως. Στην πραγματικότητα έχεις όλο το φάσμα των επιλογών από το (α) ως το (β) και μπορείς να καταλήξεις σε τι βαθμό και με ποιο συνδυασμό θα βρεις τη δική σου "χρυσή τομή", όπως είχα πει και σ' ένα άλλο post.
Δηλαδή, απ' ότι καταλαβαίνω, με την δομή αυτή που χρειάζομαι δεν μπορώ να έχω το flexibility που θέλω. Να μπορώ να φτιάξω καινούργια επίπεδα μέσω της εφαρμογής χωρίς να χρειάζεται να αλλάξω πίνακες, σχέσεις πινάκων και queries. Σωστά; Επιμένω σε αυτό γιατί αυτή την στιγμή πρέπει να ξαναγράψω την εφαρμογή γιατί ο προηγούμενος είχε προβλέψει 4 επίπεδα χρηστών (Admins -> Supervisors -> Account Managers -> Customers) και ήταν όλα "hardcoded" στην εφαρμογή. Τώρα λοιπόν, που παρουσιάστηκε η ανάγκη για ένα ενδιάμεσο level (Sales Admins) πρέπει εγώ να ξαναφτιάξω την εφαρμογή (ο άλλος έφυγε)!!!! Το ιδανικό σενάριο, θα ήταν κάτι το οποίο θα μου δίνει την δυνατότητα αν μου ζητήσουν άλλο ένα level (πχ Sub Admin, ενδιάμεσα Admin & Supervisor) να το κάνω μέσα από το administration interface και μην χρειάζεται να αλλάξω queries. Σε αυτό πήγαινε η σκέψη του να έχω πίνακα με ιεραρχίες και ονόματα πινάκων.
Δεν έχει να κάνει η δομή της ΒΔ με το αν κάνεις πράγματα από το interface ή όχι. Η DDL είναι κι αυτή μέρος της SQL.
Κανείς δεν σε εμποδίζει από το να φτιάξεις ένα interface που θα διαχειρίζεται τη συγκεκριμένη δομή, σε επίπεδο metadata. Με άλλα λόγια, αντί να χρησιμοποιείς insert/update/delete θα χρησιμοποιείς create/alter/drop.
Και πάλι, η απόφαση είναι δική σου.
Antonis78 έγραψε:
geomagas έγραψε:
Antonis78 έγραψε:Τι μορφή θα έχει το query αν θέλουμε πχ να δούμε τους Customers ενός Supervisor;
Ακόμα δεν φτάσαμε εκεί. Το παραπάνω σχήμα σου εξασφαλίζει τις απαιτήσεις σου, όλες εκτός από μία:
Antonis78 έγραψε:- Ο καθε Account Manager μπορεί να ανήκει σε πολλούς Sales Admin (του ίδιου Supervisor όμως)
Αλλά επειδή είναι λίγο πιο πολύπλοκο, προτιμώ να το πούμε αφού ξεκαθαρίσουμε με τα υπόλοιπα.
Νομίζω ότι είναι είναι ξεκάθαρα τα υπόλοιπα, πως θα υλοποιήσουμε αυτό;
Οκ, λοιπόν:

Υπονοείται ότι ο κάθε Account Manager ανήκει και σε έναν Supervisor (αυτό ισχύει και για τις υπόλοιπες σχέσεις, απλά στις 1:Ν υλοποιείται μεταβατικά, ενώ στις Μ:Ν όχι).
Μάλιστα, η πληροφορία αυτή είναι πιο ισχυρός περιορισμός από τον "Account Manager ανήκει σε Sales Admin".
Κατά συνέπεια, θα πρέπει να υπάρχει πεδίο στον AccountManagers, ως εξής: supervisorId [fk Supervisors].

Στη συνέχεια, θα πρέπει να εξασφαλίσουμε ότι κάθε συσχέτιση στον SalesAdmins_AccountManagers συμμορφώνεται με τον κανόνα. Για να γίνει αυτό, θα πρέπει κι εκεί να προστεθεί ένα πεδίο supervisorId, που θα είναι ο κοινός Supervisor του ζευγαριού.
Αλλά και τα FKs θα πρέπει να αλλάξουν, και ο πίνακας να γίνει:
SalesAdmins_AccountManagers
salesAdminId -> pk,
accountManagerId -> pk,
supervisorId,
fk (salesAdminId,supervisorId)-> SalesAdmins(userId,supervisorId),
fk (accountManagerId,supervisorId)-> AccountManagers(userId,supervisorId)

Και μια τεχνική λεπτομέρεια: για να είναι "νόμιμα" τα παραπάνω FK, θα πρέπει να ορίσεις unique(userId,supervisorId) στους δυο πίνακες.

Τώρα έχουμε και το εξής bonus (bug, feature, εσύ κρίνεις...): Ο κάθε AccountManager ανήκει πριν απ' όλα σε έναν Supervisor, μέχρι αυτός να τον "αναθέσει" σε έναν ή περισσότερους SalesAdmins. Αλλά κανείς δεν μένει "ξεκρέμαστος" από Supervisor.

Στο' πα... ήταν πολυπλοκο...

nbc
Honorary Member
Δημοσιεύσεις: 526
Εγγραφή: 05 Σεπ 2009 20:12
Επικοινωνία:

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από nbc » 02 Οκτ 2013 00:11

Κώδικας: Επιλογή όλων

<?php

error_reporting&#40;-1&#41;;
ini_set&#40;'display_errors', TRUE&#41;;

/**
 *  
 */

class Antonis78
&#123;
    /**
     *  
     */

    const Z_DB_SERVER   = 'localhost';
    const Z_DB_USERNAME = 'root';
    const Z_DB_PASSWORD = '';
    const Z_DB_NAME     = 'Antonis78';

    const Z_TBL_USERS   = 'users';
    const Z_USR_ROOT    = 'Root';
    
    /**
     *  
     */

    public  $ermsg = '';
    private $link;
    
    /**
     *  
     */

    function __construct&#40;&#41;
    &#123;
        $this->link = mysql_connect&#40;
            self&#58;&#58;Z_DB_SERVER,
            self&#58;&#58;Z_DB_USERNAME,
            self&#58;&#58;Z_DB_PASSWORD,
            TRUE // new link
            &#41;;

        if &#40;$this->link&#41;
        &#123;
            $dbok = mysql_select_db&#40;self&#58;&#58;Z_DB_NAME, $this->link&#41;;
            
            if &#40;!$dbok && TRUE&#41; 
            &#123;
                mysql_query&#40;sprintf&#40;'CREATE DATABASE %s CHARACTER SET utf8 COLLATE utf8_general_ci', self&#58;&#58;Z_DB_NAME&#41;, $this->link&#41;;

                $dbok = mysql_select_db&#40;self&#58;&#58;Z_DB_NAME, $this->link&#41;;
            &#125;
            
            if &#40;$dbok&#41;
                mysql_query&#40;"SET NAMES 'utf8'", $this->link&#41;;
            else
                $this->ermsg = sprintf&#40;'Could not select database %s', self&#58;&#58;Z_DB_NAME&#41;;
        &#125;
        else
        &#123;
            $this->ermsg = sprintf&#40;'Could not connect to datanase server at %s', self&#58;&#58;Z_DB_SERVER&#41;;
        &#125;
        
        #
        
        if &#40;empty&#40;$this->ermsg&#41;&#41;
        &#123;
            $sql = sprintf&#40;'SELECT COUNT&#40;*&#41; FROM %s', self&#58;&#58;Z_TBL_USERS&#41;;
            $res = mysql_query&#40;$sql, $this->link&#41;;
            
            if &#40;!$res&#41;
            &#123;
                $this->create_users&#40;&#41;;
                $res = mysql_query&#40;$sql, $this->link&#41;;
            &#125;

            if &#40;!$res&#41;
            &#123;
                $this->ermsg = sprintf&#40;'Could not create table %s', self&#58;&#58;Z_TBL_USERS&#41;;
            &#125;
        &#125;
    &#125;

    /**
     *  
     */
    
    public
    function html&#40;$user&#41;
    &#123;
        if &#40;empty&#40;$user&#41;&#41;
        &#123;
            $user = 'Admin1';
        &#125;
        
        if &#40;!preg_match&#40;'~^&#91;a-z0-9&#93;&#123;3,16&#125;$~i', $user&#41;&#41;
        &#123;
            return 'Bad username!';
        &#125;
        
        $USER = $this->get_user&#40;$user&#41;;
        
        if &#40;!$USER&#41;
        &#123;
            return 'Bad username!';
        &#125;
        
        $TREE = $this->select_user_tree&#40;$USER&#41;;
        
        if &#40;$TREE&#41;
        &#123;
            $html = '';
            
            foreach &#40;$TREE as $NODE&#41;
            &#123;
                $html .= str_repeat&#40;'    ', $NODE&#91;'depth'&#93;-$USER&#91;'depth'&#93;&#41;.
                         sprintf&#40;'<a href="?user=%s">%s</a>',$NODE&#91;'name'&#93;,$NODE&#91;'name'&#93;&#41;.
                         "\n";
            &#125;
        &#125;
        else
        &#123;
            $html = 'No tree for you!';
        &#125;
        
        return "<pre>\n$html\n</pre>";
    &#125;

    /**
     *  
     */
    
    private
    function select_user_tree&#40;$USER&#41;
    &#123;
        $cols  = '*';
        $from  = '`'.self&#58;&#58;Z_TBL_USERS.'`';
        $order = '`left_` ASC';
        
        if &#40;$USER&#91;'left_'&#93; > 0&#41;
        &#123;
            if &#40;empty&#40;$USER&#91;'foster'&#93;&#41;&#41;
            &#123;
                $where = sprintf&#40;'`left_` BETWEEN %d AND %d', $USER&#91;'left_'&#93;, $USER&#91;'right_'&#93;&#41;;
            &#125;
            else
            &#123;
                $ids   = $USER&#91;'id'&#93;.','.$USER&#91;'foster'&#93;;
                $cols  = 'P.*';
                $from  = "$from AS C, $from AS P";
                $order = 'C.depth, P.left_ ASC';
                $where = 'C.id IN &#40;'.$ids.'&#41; AND P.left_ BETWEEN C.left_ AND C.right_ ';
            &#125;
        &#125;
        else
        if &#40;$USER&#91;'foster'&#93; == '*'&#41;
        &#123;
            $where = '`left_` > 0';
        &#125;
        else
        &#123;
            $where = '1=2';
        &#125;

        $sql = "SELECT $cols FROM $from WHERE $where ORDER BY $order";
        $res = mysql_query&#40;$sql, $this->link&#41;;
        
        $SET = array&#40;&#41;;
        
        if &#40;$res&#41;
        &#123;
            while&#40;$ROW = mysql_fetch_assoc&#40;$res&#41;&#41;
            &#123;
                $SET&#91;&#93; = $ROW;
            &#125;
        &#125;
        
        return $SET;
    &#125;
    
    /**
     *  
     */
    
    private
    function create_users&#40;&#41;
    &#123;
        $tbl = self&#58;&#58;Z_TBL_USERS;
        $sql = <<<EOS
CREATE TABLE IF NOT EXISTS `&#123;$tbl&#125;` 
&#40;
`id`     int&#40;10&#41; unsigned AUTO_INCREMENT PRIMARY KEY,
`name`   VARCHAR&#40;16&#41; NOT NULL,
`pass`   VARCHAR&#40;32&#41; NOT NULL,
`foster` varchar&#40;255&#41; NOT NULL,
`left_`  int&#40;10&#41; unsigned NOT NULL,
`right_` int&#40;10&#41; unsigned NOT NULL,
`depth`  int&#40;10&#41; unsigned NOT NULL,
KEY `left_` &#40;`left_` &#41;,
UNIQUE 
KEY `name`  &#40;`name`  &#41;
&#41; ENGINE=MyISAM DEFAULT CHARSET=utf8;
EOS;
        $res = mysql_query&#40;$sql, $this->link&#41;;
        
        if &#40;$res&#41;
        &#123;
            $this->add_row&#40;array&#40;
                'name'   => self&#58;&#58;Z_USR_ROOT,
                'pass'   => $this->hash&#40;self&#58;&#58;Z_USR_ROOT&#41;,
                'foster' => '',
                'left_'  => 1,
                'right_' => 2,
                'depth'  => 0,
                &#41;&#41;;

            $this->add_user&#40;'Supervisor1', self&#58;&#58;Z_USR_ROOT&#41;;
            $this->add_user&#40;'Supervisor2', self&#58;&#58;Z_USR_ROOT&#41;;
            $this->add_user&#40;'SalesAdmin1', 'Supervisor1'&#41;;
            $this->add_user&#40;'SalesAdmin2', 'Supervisor1'&#41;;
            $this->add_user&#40;'SalesAdmin3', 'Supervisor2'&#41;;
            $this->add_user&#40;'SalesAdmin4', 'Supervisor2'&#41;;
            $this->add_user&#40;'AccountMgr1', 'SalesAdmin1'&#41;;
            $this->add_user&#40;'AccountMgr2', 'SalesAdmin2'&#41;;
            $this->add_user&#40;'AccountMgr3', 'SalesAdmin3'&#41;;
            $this->add_user&#40;'AccountMgr4', 'SalesAdmin4'&#41;;
            $this->add_user&#40;'Customer1'  , 'AccountMgr1'&#41;;
            $this->add_user&#40;'Customer2'  , 'AccountMgr2'&#41;;
            $this->add_user&#40;'Customer3'  , 'AccountMgr3'&#41;;
            $this->add_user&#40;'Customer4'  , 'AccountMgr4'&#41;;
            # foster childs
            $this->add_user&#40;'AccountMgr2', 'SalesAdmin1'&#41;;
            $this->add_user&#40;'AccountMgr3', 'SalesAdmin4'&#41;;
            # off tree user
            $this->add_user&#40;'Admin1'     , TRUE&#41;;
            $this->add_user&#40;'Normal1'    , FALSE&#41;;
        &#125;
    &#125;

    /**
     *  
     */
    
    private
    function add_user&#40;$child, $parent&#41;
    &#123;
        if &#40;$parent === TRUE || $parent === FALSE&#41;
        &#123;
            return $this->add_row&#40;array&#40;
                'name'   => $child,
                'pass'   => $this->hash&#40;$child&#41;,
                'foster' => $parent ? '*' &#58; '',
                'left_'  => 0,
                'right_' => 0,
                'depth'  => 0,
                &#41;&#41;;
        &#125;
        
        $CHILD  = $this->get_user&#40;$child &#41;;
        $PARENT = $this->get_user&#40;$parent&#41;;

        if &#40;$PARENT&#41;
        &#123;
            if &#40;$CHILD&#41;
            &#123;
                if &#40;$this->can_foster&#40;$CHILD, $PARENT&#41;&#41;
                &#123;
                    $ids = $PARENT&#91;'foster'&#93;;
                    $IDS = empty&#40;$ids&#41;?array&#40;&#41;&#58;explode&#40;',',$ids&#41;;
                    $IDS&#91;&#93; = $CHILD&#91;'id'&#93;;
                    $ids = implode&#40;',', array_unique&#40;$IDS&#41;&#41;;
                    $tbl = self&#58;&#58;Z_TBL_USERS;
                    $sql = "UPDATE `$tbl` SET `foster`='$ids' WHERE `id`=".$PARENT&#91;'id'&#93;;
                    $res = mysql_query&#40;$sql, $this->link&#41;;
                &#125;
            &#125;
            else
            if &#40;$this->lock_tree&#40;TRUE&#41;&#41;
            &#123;
                $tbl = self&#58;&#58;Z_TBL_USERS;
                $rgt = $PARENT&#91;'right_'&#93;;

                $sql = "UPDATE `$tbl` SET `right_`=`right_`+2 WHERE `right_`>=$rgt";
                $res = mysql_query&#40;$sql, $this->link&#41;;

                $sql = "UPDATE `$tbl` SET `left_` =`left_` +2 WHERE `left_` > $rgt";
                $res = mysql_query&#40;$sql, $this->link&#41;;

                $this->add_row&#40;array&#40;
                    'name'   => $child,
                    'pass'   => $this->hash&#40;$child&#41;,
                    'foster'  => '',
                    'left_'  => $PARENT&#91;'right_'&#93;,
                    'right_' => $PARENT&#91;'right_'&#93;+1,
                    'depth'  => $PARENT&#91;'depth' &#93;+1,
                    &#41;&#41;;
                
                $this->lock_tree&#40;FALSE&#41;;
            &#125;
        &#125;
    &#125;

    /**
     *  
     */
    
    private
    function can_foster&#40;$CHILD, $PARENT&#41;
    &#123;
        return TRUE;
    &#125;
    
    /**
     *  
     */

    private
    function lock_tree&#40;$lock&#41;
    &#123;
        $tbl = self&#58;&#58;Z_TBL_USERS;
        
        if &#40;$lock&#41;
            $sql = "LOCK TABLES `$tbl` WRITE";
        else
            $sql = "UNLOCK TABLES";
            
        return mysql_query&#40;$sql, $this->link&#41;;
    &#125;

    /**
     *  
     */
    
    private
    function get_user&#40;$idorname&#41;
    &#123;
        $sql = sprintf&#40;'SELECT * FROM `%s` WHERE `%s` = %s', 
            self&#58;&#58;Z_TBL_USERS,
            is_int&#40;$idorname&#41; ? 'id' &#58; 'name',
            is_int&#40;$idorname&#41; ? $idorname &#58; "'".mysql_real_escape_string&#40;$idorname, $this->link&#41;."'"
            &#41;;
        $res = mysql_query&#40;$sql, $this->link&#41;;

        $SET = array&#40;&#41;;
        
        if &#40;$res&#41;
        &#123;
            while&#40;$ROW = mysql_fetch_assoc&#40;$res&#41;&#41;
            &#123;
                $SET&#91;&#93; = $ROW;
            &#125;
        &#125;
        
        if &#40;count&#40;$SET&#41; == 1&#41;
            return $SET&#91;0&#93;;
        else
            return FALSE;
    &#125;

    /**
     *  
     */
    
    private
    function add_row&#40;$ROW&#41;
    &#123;
        $names  = '';
        $values = '';
        
        foreach &#40;$ROW as $name => $value&#41;
        &#123;
            $names  .= sprintf&#40;', `%s`', $name&#41;;
            $values .= sprintf&#40;", '%s'", mysql_real_escape_string&#40;$value, $this->link&#41;&#41;;
        &#125;

        $sql = sprintf&#40;'INSERT INTO `%s` &#40;%s&#41; VALUES &#40;%s&#41;', self&#58;&#58;Z_TBL_USERS, substr&#40;$names, 2&#41;, substr&#40;$values, 2&#41;&#41;;
        $res = mysql_query&#40;$sql, $this->link&#41;;
        
        return $res;
    &#125;

    /**
     *  
     */
    
    private
    function hash&#40;$pass&#41;
    &#123;
        return md5&#40;$pass&#41;;
    &#125;
&#125;

/**
 *  
 */

$Tree = new Antonis78&#40;&#41;;

if &#40;$Tree->ermsg&#41;
&#123;
    die&#40;$Tree->ermsg&#41;;
&#125;

?>
<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Antonis78</title>
</head>

<body>
<?php print&#40;$Tree->html&#40;@$_GET&#91;'user'&#93;&#41;&#41;; ?>

</body>

</html>

geomagas
Δημοσιεύσεις: 667
Εγγραφή: 06 Απρ 2013 13:36
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από geomagas » 02 Οκτ 2013 08:09

[offtopic]
Ομολογώ ότι στην αρχή πίστευα ότι δεν θα ανταποκριθείς. Έκανα λάθος.
Σ' ευχαριστώ που βοηθάς να αποδειχθεί ότι η τεχνική της "σουπιάς" (αμολάω μελάνι, θολώνω τα νερά και φεύγω) δεν είναι κανόνας σ' αυτό το forum, αλλά εξαίρεση.
Το θεωρώ πολύ αξιοπρεπές εκ μέρους σου.

Επίσης, προσωπικά χαίρομαι που χρησιμοποιείς αντικειμενοστρεφή προσέγγιση, γιατί μου είναι πιο εύκολο να διαβάσω τον κώδικά σου. Προσωπικά.
Αν και η μεγάλη μου ένσταση είναι ότι μιλούσαμε για το επίπεδο της ΒΔ, και δεν ειπώθηκε λέξη για php.
[/offtopic]

Αλλά επειδή ξέρω ότι ο Antonis78 ενδιαφέρεται για μια τέτοια εναλλακτική, θα περιμένω τα σχόλια και τις απορίες του (και τυχόν άλλων) και μετά θα πω τα δικά μου, τα οποία έχω ήδη μαζέψει.

Antonis78
Δημοσιεύσεις: 60
Εγγραφή: 24 Φεβ 2006 14:41

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από Antonis78 » 02 Οκτ 2013 10:59

@nbc
Σε ευχαριστώ για τον κόπο σου. Απ' ότι κατάλαβα χρησιμοποιείς Nested Set Model για την ιεραρχία, σωστά; Θα είναι λίγο δύσκολο να το διατηρήσω λόγω όγκου δεδομένων, η εφαρμογή σαν κεντρική ομπρέλα έχει εταιρείες όπου κάθε εταιρεία έχει τους δικούς της πελάτες. Αυτήν την στιγμή υπάρχουν 5 εταιρείες με ~ 5000 πελάτες η κάθε μία που σημαίνει ~ 25000 πελάτες (and counting). Σε τέτοιο όγκο δεδομένων πως είναι από ταχυτητα;
Επίσης, δεν το έχω ξαναδουλέψει το μοντέλο αυτό, αλλά το διαβάζω τώρα. Σίγουρα είναι μία εναλλακτική που θα την λάβω σοβαρά υπόψην. Thanks!

Antonis78
Δημοσιεύσεις: 60
Εγγραφή: 24 Φεβ 2006 14:41

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από Antonis78 » 02 Οκτ 2013 14:47

geomagas έγραψε:Οκ, λοιπόν:

Υπονοείται ότι ο κάθε Account Manager ανήκει και σε έναν Supervisor (αυτό ισχύει και για τις υπόλοιπες σχέσεις, απλά στις 1:Ν υλοποιείται μεταβατικά, ενώ στις Μ:Ν όχι).
Μάλιστα, η πληροφορία αυτή είναι πιο ισχυρός περιορισμός από τον "Account Manager ανήκει σε Sales Admin".
Κατά συνέπεια, θα πρέπει να υπάρχει πεδίο στον AccountManagers, ως εξής: supervisorId [fk Supervisors].

Στη συνέχεια, θα πρέπει να εξασφαλίσουμε ότι κάθε συσχέτιση στον SalesAdmins_AccountManagers συμμορφώνεται με τον κανόνα. Για να γίνει αυτό, θα πρέπει κι εκεί να προστεθεί ένα πεδίο supervisorId, που θα είναι ο κοινός Supervisor του ζευγαριού.
Αλλά και τα FKs θα πρέπει να αλλάξουν, και ο πίνακας να γίνει:
SalesAdmins_AccountManagers
salesAdminId -> pk,
accountManagerId -> pk,
supervisorId,
fk (salesAdminId,supervisorId)-> SalesAdmins(userId,supervisorId),
fk (accountManagerId,supervisorId)-> AccountManagers(userId,supervisorId)

Και μια τεχνική λεπτομέρεια: για να είναι "νόμιμα" τα παραπάνω FK, θα πρέπει να ορίσεις unique(userId,supervisorId) στους δυο πίνακες.

Τώρα έχουμε και το εξής bonus (bug, feature, εσύ κρίνεις...): Ο κάθε AccountManager ανήκει πριν απ' όλα σε έναν Supervisor, μέχρι αυτός να τον "αναθέσει" σε έναν ή περισσότερους SalesAdmins. Αλλά κανείς δεν μένει "ξεκρέμαστος" από Supervisor.

Στο' πα... ήταν πολυπλοκο...
Βασικά, αυτό το bonus με βοηθάει πολύ, γιατί μάλλον θα έχω τέτοιες περιπτώσεις! Σύμφωνα με αυτά που έχουμε πει, τι μορφή θα έχει το query για να τραβήξω πχ. τους πελάτες ενός Supervisor;

geomagas
Δημοσιεύσεις: 667
Εγγραφή: 06 Απρ 2013 13:36
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από geomagas » 02 Οκτ 2013 15:07

Δεδομένων των πινάκων:

Customers
personId -> pk, fk Persons
accountManagerId -> fk AccountManagers

AccountManagers
userId -> pk, fk Users
supervisorId -> fk Supervisors


έχουμε και λέμε:

Κώδικας: Επιλογή όλων

select c.personId 
from Customers c, AccountManagers am
where c.accountManagerId=am.userId
and am.supervisorId= ..... /* <-- enter supervisor id here */

Άβαταρ μέλους
jpk
Δημοσιεύσεις: 441
Εγγραφή: 09 Μαρ 2011 21:17

Διαχείριση Ιεραρχίας Χρηστών (User Levels)

Δημοσίευση από jpk » 03 Οκτ 2013 01:58

Άκου μια ακόμα ιδέα. Θα επιμείνω λίγο στην συγκέντρωση των στοιχείων σε όσους λιγότερους πίνακες γίνεται , υπάρχει ένα στοιχείο που δεν έχω (ή σε όλες αυτές τις σελίδες μπορεί και να το είπες) το ποιος τελικά βάζει τον customer στο σύστημα. Υποθέτω ο Account Manager . Υπάρχει και κάτι ακόμα που είπες «Ο καθε Account Manager μπορεί να ανήκει σε πολλούς Sales Admin (του ίδιου Supervisor όμως) » που απέκλεισε κάθε linear &#8211; γραμμική λύση του ζητήματος &#8230; αυτό το ΜΠΟΡΕΙ &#8230; μπορεί και όχι , άρα αυτό κάποιος θα πρέπει να το καθορίζει και υποπτεύομαι ότι το καθορίζει ο Supervisor του. Άρα επί της ουσίας καταλήγω σε 3 πίνακες (θα μπορούσα και σε δύο αλλά πάλι υποπτεύομαι ότι ο customer έχει τελείως διαφορετικές ιδιότητες άρα πρέπει να είναι ένας πίνακας από μόνος του).
1 customers
ID (ΙΝΤ 10)
ADMIN_ID (ΙΝΤ 10)
Στοιχεία άλλα για τον customer &#8230;

2 admins
ID (ΙΝΤ 10)
PARENT_ID (ΙΝΤ 10)
LEVEL (1 Super Admin 2 Supervisor 3 Sales Admin 4 Account Manager) (ΤΙΝΥΙΝΤ)
Στοιχεία admin (px user name ή blowfish password ή ότι άλλο θες)


3 admins_map
ID (INT 10)
ADMIN_ID (INT 10) (Σε ποιον admin ανεφερόμαστε ότι έχει το δικαίωμα)
ADMIN_REF_ID (INT 10) (Ποιανού admin έχει δικαίωμα να βλέπει ο χρήστης)

Όταν ο super admin φτιάχνει ένα Supervisor τότε προστίθεται μια εγγραφή στο admin_maps με admin_id το δικό του και ADMIN_REF_ID αυτού που έφτιαξε. Όταν ο Supervisor φτιάχνει έναν Sales Admin προστίθεται μια εγγραφή στο admin_maps με admin_id το δικό του και ADMIN_REF_ID αυτού που έφτιαξε. Όταν ο Sales Admin φτιάχνει έναν Account Manager προστίθεται μια εγγραφή στο admin_maps με admin_id το δικό του και ADMIN_REF_ID αυτού που έφτιαξε ΑΛΛΑ ταυτόχρονα πηγαίνει μήνυμα (ή ότι θες) στον Superviror να αποδώσει και άλλους Sales Admins αν θέλει σε αυτόν τον Account Manager. Του αποδίδει απλά επιλέγοντας του από τους απογόνους του και προσθέτοντας τους στον admins_map.

Το πώς θα δημιουργηθεί αυτή η δομή δεν έχει τόσο νόημα , σου είπα απλά την φυσιολογική ροή , όλο αυτό μπορεί να γίνει απλά και με κάποιο CSV αν ήδη υπάρχουν δεδομένα.

Στην τελική όταν θέλεις να πάρεις του πελάτες και να τους δεις σε συγκεκριμένο admin id δεν έχεις παρά να κάνεις ένα join με τον πίνακα customers και τον πίνακα admins_map.
Τελευταία επεξεργασία από το μέλος jpk την 03 Οκτ 2013 02:33, έχει επεξεργασθεί 1 φορά συνολικά.

Απάντηση

Επιστροφή στο “PHP Προγραμματισμός”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 0 επισκέπτες