-
Posts
579 -
Joined
-
Last visited
Posts posted by Drongo_III
-
-
Hi Requinix
I really appreciate your detailed response to this. It has helped hugely to realise the distinction between a Business Model and a Database model.
I've had a shot at a reworked example (not tested just typed atm) and I'd welcome your thoughts. It's pretty much your example but I've removed the auth dependency from the UserModel and changed up the factory a bit.
There is a table gateway acting as the User Database Model (i.e. just transacting data to and from the database for users) and the User Model now concentrates just on delegating to the table gateway and performing tasks on its own entity.
I would really welcome your feedback as this is helping me learn...hopefully how to do it the right way.
Here is the example:
class UserModel { private $userTableGateway; private $name; private $username; private $password; private $lastLogin; public function __construct($userTableGateway){ $this->userTableGateway; } /* * Getters/Setters */ /* * Everything below probably represents 'actions' */ public function validateLogin($hashedPassword){ if($hashedPassword == $this->password){ return true; } return false; } /* * Should these methods be outside the class? */ public function updateUser($data){ //loop data into current object //Delegate to $this->userTableGateway } public function deleteUser($id){ //Delegate to $this->userTableGateway //return boolean on success/failure } } class UserModelFactory { public function __construct(){ /* * $tableGateway encapsulating all the DB access for user table */ $this->tableGateway = new userTableGateway(); } /** * Required when you want to find a user and get back a populated UserModel */ public function getUserModelAsDBUser($userName){ //get data from db $dbUserData = $this->tableGateway->getUserData($userName); if($dbUserData) { //create instance and pass it data $userModel = $this->createUserModel($dbUserData); return $userModel; } return null; } /** * Required for creating an instance when you want to add a new user * and pass optional data to it to be populated into the UserModel */ public function createUserModel(array $data){ $userModel = new UserModel($this->tableGateway); if( !empty($data) ){ foreach($data as $k=>$v){ //Call $userModel setters to map raw data to object //Could be some sort of mapper class instead of foreach } } return $userModel; } } /* * Controller Code - i.e. Auth Controller */ $userModelFactory = new UserModelFactory(); $userModel = $userModelFactory->getUserModelAsDBUser($_POST['username']); //some class that runs the same hash algorithm as for stored users $hashedUserPassword = new passwordHasher($_POST['password']); if($userModel && $userModel->validateLogin($hashedUserPassword) ){ $userModel->setLastLogin(time()); $userModel->updateUser(); //i.e. refresh the user's db record }
And you said above "Oh, and you may be starting to feel like the way you're doing DI (by passing around the database and encryption stuff) isn't working very well. I would agree with that.". What would be a better way?
-
Thank Requinix
That certainly helped to clear up some stuff and its clear I need to go read more about MVC and especially Models.
I realise your answer was simple and intended to illustrate a point but in general is it ok for models, like a User Model to have mixed responsibilities. Like is it the responsibility of a user model to provision a login mechanism? I can see how a user model may be a part of that but it feels like the responsibility of dealing with the process shouldn't belong to a user model. Or should you have a specific LoginUserModel ?
Sorry for the extended question i just don't have a real world point of reference for what the model in an application should look like or how much you can put into it.
If it is considered ok for the user model to be packed with lots of stuff then is this approach correct?
//USER MODEL class UserModel { private $userId; private $userName; private $password; /** * Some instance of a DB class */ private $db; /** * Some encryption class which can generate cipher text */ private $enc; public function __construct($databaseClass, $encryptionClass){ //some database layer like a table gateway $this->db = $databaseClass; //some encryption class which can be used to test a password against a cipher $this->enc = $encryptionClass; } public function getFromLogin($username){ // 1. Retrieve $_POST[''username], $_POST['Password'] // 2. Set values to $this->username, $this->$password // 3. return boolean } public function validateLogin($password){ // 1. Turn pasword into cipher text // 2. Match against supplied password // 3. Return boolean } } //Authentication controller - receives request /AuthController/doLogin class AuthController { public function doLogin(){ $db = new $databaseClass(); //e.g. a tablegateway $user = new UserModel($db); if($user->getFromLogin($_POST['username'])){ $loginSuccess = $user->validateLogin(); //do stuff } } }
-
Hello
I'm slowly getting to grips with OOP/OOD but I would like some advice.
I try to follow the principles of single responsibility and high cohesion. I'm struggling a bit to see how these principles work when you try to use composition.
For instance lets says I have an Authentication class handling login on a website. On login the Authentication class needs to make a db call to find a given user and test against their stored password. The user also needs to be stored in session when they successfully login so I also compose Authentication with a Session Manager class.
The question is am I violating SRP by composing my class with these things? I'm using an MVC so is it better practice to do more in my controller (i.e. run these things as individual actions) rather than composing and encapsulating these things into a single class?
I find the principles a bit confusing sometimes so a steer in the right direction would be appreciated.
Drongo
-
Hello
I have a really basic regex on a rewrite rule that is causing a 500 error and I cannot see why it would.
I have a directory called 'help'. What I want is for anytime someone hits the help directory with a tailing url it will simply get rewritten back to help (there are some ajax generated pages).
so if someone hits /help/kittens they'll simply get rewritten back to help.
However, when I try to use the following rewriterule in htaccess it just gives me a 500 error.
RewriteEngine On RewriteRule ^help/([a-z]+) /help [NC,L]
Any help would be appreciated.
Drongo
-
This array feature which you appearently know from PHP is actually very exotic and really only makes sense in the super-sloppy PHP philosophy.
Technically speaking, you simply cannot apply the index operator to the empty value t['key1']. There's no such thing as null['key2']. If you try this in Ruby, your script will blow up with an error message. The same is true for Python. The only reason why PHP doesn't blow up is because it's specifically designed to accept errors. Instead of telling you to fix your code, it will guess what you mean and create a new subarray for you.
So this isn't how languages normally works. It's a PHPism.
Thanks Jacques. You're quite right, I'm a php developer first and didn't realise this was a feature particular to php. Makes much more sense now.
Drongo
-
I have a really basic question.
Why is it you can't create a multidimensional array like this in javascript:
t['key1']['key2'] = 123;
I have worked with JS for a long time and I get the proper form is to do something like:
t['key1'] = {'key2' : 123}
But I'm just wondering why it's not possible to do the first version? Is it because JS doesn't know what to cast the 'key2' to?
Thanks,
Drongo
-
Hi Guys
I don't know whether this is possible or not but I've been going down a lot of dead ends for a few hours now and I'm ready to defer to a higher power...
I want to create a function that will accept an array of keys as it's first argument and a value as it's second argument and basically add the keys in a multidimensional format to produce an array with the data as its final value.
So if I passed into the function:
someFunc(array('key1','key2'), 'data');
I would end up with an array that looks like: [key1][key2] = 'data'
I've been trying to do it with a while loop but I become unstuck in adding the subsequent layers to the array. I've also explored using the 'end' and 'key' method hoping I could just specify the pointer and add an element there but there doesnt appear to be anything like that. Any help is very welcome!
Dronogo
-
Thanks for the advice!
-
Yeah I could use a relative path but on other servers I've worked on they've set them up so you just use /includes/file-name.php and it doesnt matter where you then make the call from it still works. I guess I was just trying to work out how to configure xampp so it always looks at /htdocs/ as it's root when including files?
-
Hello
Hope someone can help and I'm sure this is a simple one.
I'm using a local copy of XAMPP at the moment and have a basic issue but I've been searching around and struggling to find the answer.
Usually when I work on a site, lets say it's domain is example.com, and I wish to include a file from a location like example.com/includes/, I would simply use a php's include as follows:
<?php include('/includes/some-file.php'); ?>
In this instance I'd expect the '/' to refer to the base domain - i.e. example.com - so that irrespective of where I include the file from it always has a sound reference.
However, on my local xampp i'm having issues.
So lets say I have a file I want to include located in in: /htdocts/ng/includes/some-file.php
And I try to include it from a sub directory /htdocs/ng/some-dir/ as per the code posted above I get an error:
"No such file or directory in C:\xampp\htdocs\ng\some-dir\some-file.php"
It's as if the include path is always trying to include from the current directory. So is there a setting in apache I need to change to ensure that the base domain is always referenced?
Hope that makes sense,
Drongo
-
The delay is part of the keyboard and operating system. Notice how if you hold down a letter in a text box, you get the same delay? That delay occurs on the keydown event as well.
One way to fix this is to assume that the key is held down until a keyup event occurs. So you press a key, it fires a keydown event and repeats that action until a keyup event occurs for the same key, which then stops the event. Does that make sense?
Scoot you're a genius sir! I hadn't considered this was symptomatic of the way the OS handles repeating keys. Your post got me to searching out how to overcome the delay and I found a solution along the lines of what you proposed. Essentially you have a loop monitoring a keyState object to determine whether a key is up or down and then it reacts accordingly. The solution also means multiple key presses can be used at once.
The code is below if anyone experiences the same problem:
<!doctype html> <html> <head> <style type="text/css"> canvas { border: 1px solid #888; } </style> <script> window.onload = function(){ //initialise canvas and context c.init(); window.addEventListener('keydown', function(e){ keyState[e.keyCode || e.which] = true; }, false); window.addEventListener('keyup', function(e){ keyState[e.keyCode || e.which] = false; }); } //holds key state var keyState = {} //canvas var c = { cvs : null, //canvas element ctx : null, //context pos : {y:0,x:0}, inc : 5, init : function(){ //create canvas obj and context this.cvs = document.getElementById('canvas1'); this.ctx = this.cvs.getContext('2d'); //draw initial rectangle at starting point c.ctx.fillStyle = 'black'; c.ctx.fillRect(0, 0, 60, 60); //start keystroke monitoring this.loopPosition(); }, animate: function(){ //clear the canvas this.clearContext(); //redraw in new position this.ctx.fillStyle = 'black'; this.ctx.fillRect(this.pos.x, this.pos.y, 60, 60); }, clearContext : function(){ c.ctx.clearRect(0,0,this.cvs.width,this.cvs.height); }, loopPosition: function(){ if(keyState[37]){ this.pos.x-=1; } if(keyState[39]){ this.pos.x+=1; } if(keyState[40]){ //down this.pos.y+=1; } if(keyState[38]){ //up this.pos.y-=1; } //then animate this.animate(); //loop the method setTimeout(this.loopPosition.bind(c),10); } } </script> </head> <body> <canvas id="canvas1" width="500" height="500"></canvas> </body> </html>
-
Hi
I'm testing out animation using canvas..
The code below just animates a square in response to holding down one of the arrow keys.
The problem is when I hold down an arrow key there appears to be a short delay before the square starts animating. I'm guessing it's something to do with the keydown event firing rapidly but I'm not sure.
So if anyone has any suggestions as to why this might be happening it would help me greatly! The desired effect is for the square to animate immediately without any delay.
Thanks,
Drongo
<!doctype html> <html> <head> <style type="text/css"> canvas { border: 1px solid #888; } </style> <script> window.onload = function(){ //initialise canvas and context c.init(); //set event handler for keydown window.addEventListener('keydown', c.setPosition.bind(c)); } //canvas var c = { cvs : null, //canvas element ctx : null, //context pos : {y:0,x:0}, inc : 5, init : function(){ //create canvas obj and context this.cvs = document.getElementById('canvas1'); this.ctx = this.cvs.getContext('2d'); //draw initial rectangle at starting point c.ctx.fillStyle = 'black'; c.ctx.fillRect(0, 0, 60, 60); }, animate: function(){ //clear the canvas this.clearContext(); //redraw in new position this.ctx.fillStyle = 'black'; this.ctx.fillRect(this.pos.x, this.pos.y, 60, 60); }, clearContext : function(){ c.ctx.clearRect(0,0,this.cvs.width,this.cvs.height); }, setPosition : function(e){ //increment position based on key console.log(e.keyCode); switch(e.keyCode){ case 40: this.pos.y += this.inc; break; case 38: this.pos.y -= this.inc; break; case 37: this.pos.x -= this.inc; break; case 39: this.pos.x += this.inc; break; } //then animate this.animate(); } } </script> </head> <body> <canvas id="canvas1" width="500" height="500"></canvas> </body> </html>
-
I think I see what you mean. Thanks.
-
Out of interest though can anyone explain why the window object works like that? How is the value of the variable gets used in that context?
-
Found the answer.
If this of any help to anyone you can call it by using the window object:
var a = new window[p]();
-
Hello
Probably a really basic answer here but I'm stuck and google isn't bringing me any closer.
Is it possible to dynamically create objects using a variable?
For instance in PHP I might do:
class turnip { public function __construct(){ echo 'created turnip'; } } $t = 'turnip'; $tt = new $t(); //echoes created turnip
However, trying to do something similar in JS is simply causing an error. So is there a special trick?
Lets say I wanted to do:
function Pawn(){...} var p = 'Pawn'; var a = new p(); //Can this be done somehow? Can you force the variable 'p' to evaluate down to it's value?
-
Hi Guys
I'm just wondering whether there's a more elegant way to access the event object in the following example.
I realise I could use jquery's $.proxy method but lets say we hypothetically had to use call() it doesn't seem very clean to have to pass 'e' into the anonymous function and as a parameter on call().
So is there a better way to access the event object in this scenario?
I know this is a bit of a pie in the sky question but I'm just keen to understand whether what follows is the only way or not.
Thanks,
Drongo
$(document).ready(function(){ $('#tt').on('click', function(e){ test.init.call(test,e,'some text as extra param'); }); }); var test = { init: function(e, g){ e.preventDefault(); console.log(e); console.log(g); } }
-
Thanks requinix. I though gd library wasn't the best idea but you'd be surprised how many websites recommend it.
I wouldnt have thought of base64 - really nice suggestion.
-
I'm currently planning out a pixel tracking PHP script.
From reading around there appears to be two ways to serve a pixel back to in the request:
1) creating a 1x1 pixel image using GD library
2) sending back 200 code in the header and serving no image at all
However, using GD library seems like quite an expensive way to serve a 1x1 pixel. So what I wanted to know was if I went down this route is there any advantage of using GD library over just serving a 1x1 pixel image (i.e. a 'physical' image) that's actually stored on the server?
Any advice is appreciated!
-
Firstly I wouldn't rely on client side JavaScript alone for verifying a password - you'll want to validate server side too.
In order to check for the presence of uppercase/lowercase/number you can use a function something similar to the one I've jotted below. This uses a simple regular expression to test a password string against different patterns.
You can easily adapt this to also count the number of instances of a particular character as the 'result' variable will get populated with each individual instance of either an uppercase letter, lowercase letter or number. So you can check result.length to see if the password provided meets your criteria.
Hope this helps get you on the right path.
<script> function testPassword(type, password){ var result, patterns = { uppercase : /[A-Z]{1,1}/g, lowercase : /[a-z]{1,1}/g, number : /[0-9]{1,1}/g, } //pass value of match to result - it becomes null if no match is found result = password.match(patterns[type]); //return true if a match is found or false if not return result === null ? false : true ; } var password = "AAcc"; console.log( testPassword('uppercase', password) ); //returns true as the password string has caps console.log( testPassword('lowercase', password) ); //returns true as there are lowercase characters console.log( testPassword('number', password) ); //returns false - no digits in the password str </script>
-
Hi Guys
I'm not entirely sure this is the right section but I need a little advice.
Three quick questions:
1) Can you force caching on a script (js) that's loaded from an external source over which you have no direct control. So lets say you have a script being loaded on a page async. - i.e. via createNewElement... Can you force that script to cache?
2) This may actually answer question one - is an external script served under the headers of the source server? So if that server had caching set on all script files and I incorporated a script from that server into a page on my server would that file be subject to the source servers caching?
3) If point two is the case - then does that count for all files incorporated from an external source?
Thanks,
Drongo
-
Thanks Ch0
That worked a treat. I've just re-read some tutorials on positive and negative lookaheads but something is confusing me.
If I had a pattern like this:
'/^([a-z0-9_\-\.]+)(?!\.jpg)$/i';
Why is it that preg_match matches the whole string (i.e. including the .jpg)? Doesn't that pattern mean "match alphabetical, numeric, underscore, dash and full stop BUT don't match if the string ends in .jpg"? So by my understanding, which appears to be wrong, that shouldn't have matched anything.
Thanks,
Drongo
-
How's this? Works for me.
RewriteEngine on RewriteRule ^user/([^/]+) user.php?id=$1
-
Hello
So I want to try and match everything preceding a file extension in a string using preg_match.
An example file name: "Images_home_blah.blah.jpg" .
I've tried the following regex:
/^([a-z0-9_\-\.]+)(?!\.jpg)/i
But this sadly appears to capture the whole string instead of ignoring the '.jpg' part. Can anyone point me in the right direction?
Thanks,
Drongo
OOP/OOD advice
in PHP Coding Help
Posted
Thanks for all your help Requinix!