|
I'm having some trouble with a php mysql query / database layout I want to set up. Perhaps someone can point me in the right direction. I have a main table that holds recipe information. recipes recipeID (INT auto_increment PK) recipeName(VARCHAR) recipeDescription dateCreated dateUpdated userID I have a table that holds ingredients ingredients ingredientID(INT auto_increment PK) ingredientName(VARCHAR) ingredientDescription(VARCHAR) Then I have a table connecting different ingredients to a recipe ingredientsRecipes ingredientRecipeID recipeID ingredientID I want to make a search query that allows me to say: Give me all the recipeIDs that contain eggs,flour,water, etc. However this would require me to query the same table columns multiple times. I'm not completely sure on how to set up a query like that. Normally I'd say: code:
Perhaps its really simple and I'm missing something. If my table setup is wrong please by all means correct me.
|
# ? Aug 7, 2009 10:39 |
|
|
# ? May 16, 2024 07:10 |
|
Jahuran posted:I want to make a search query that allows me to say: Give me all the recipeIDs that contain eggs,flour,water, etc. However this would require me to query the same table columns multiple times. I'm not completely sure on how to set up a query like that. code:
|
# ? Aug 7, 2009 16:36 |
|
Jahuran posted:I'm having some trouble with a php mysql query / database layout I want to set up. Perhaps someone can point me in the right direction. If Begby was correct, ignore this: If I read you correctly, you want recipes with eggs AND flour AND water? In which case Begby's answer won't be helping you at all, as IN is a shorthand for OR. What you want is subqueries: SELECT recipeID FROM recipesIngredients WHERE ingredientID = 'X' AND recipeID IN (SELECT recipeID FROM recipesIngredients WHERE ingredientID = 'Y') AND recipedID IN (SELECT ... Which basically lets you chain queries together, but have the SQL engine do the lifting for you still. (caveat: not tested that syntax, but see http://dev.mysql.com/doc/refman/5.0/en/subqueries.html) Edit: break those tables! p.s. this was also really an SQL question, there are likely SQL goons that are better at SQL than us PHP goons.
|
# ? Aug 7, 2009 22:02 |
|
PHP msqli question. Is there a non hack way to deal with dynamic mysqli prepared statements? Seriously msqli_stmt::bind_param and the bind_result functions are the worst pieces of poo poo functions I have ever had to deal with, ever.
|
# ? Aug 8, 2009 04:11 |
|
haywire posted:PHP msqli question. Can you be a little more specific? You mean like having a dynamic number of parameters in a statement? Here's a function I found somewhere that I've been using, borrowed from http://www.devmorgan.com/blog/2009/03/27/dydl-part-3-dynamic-binding-with-mysqli-php/ php:<? public function bindParams($stmt,$params) { if ($params != null) { $types = ''; //initial sting with types foreach($params as $param) { //for each element, determine type and add if(is_int($param)) { $types .= 'i'; //integer } elseif (is_float($param)) { $types .= 'd'; //double } elseif (is_string($param)) { $types .= 's'; //string } else { $types .= 'b'; //blob and unknown } } $bind_names[] = $types; //first param needed is the type string // eg: 'issss' for ($i=0; $i<count($params);$i++) {//go through incoming params and added em to array $bind_name = 'bind' . $i; //give them an arbitrary name $$bind_name = $params[$i]; //add the parameter to the variable variable $bind_names[] = &$$bind_name; //now associate the variable as an element in an array } //call the function bind_param with dynamic params call_user_func_array(array($stmt,'bind_param'),$bind_names); } return $stmt; //return the bound statement } ?> php:<? $stmt = $mysqli->bindParams($mysqli->prepare($query),$queryParams); ?>
|
# ? Aug 8, 2009 06:48 |
|
quote:Is there a non hack way to deal with dynamic mysqli prepared statements? Can't use PDO instead?
|
# ? Aug 8, 2009 06:55 |
|
KuruMonkey posted:If Begby was correct, ignore this: Thank you for the replies. I saw the thread about database questions so I figured my question would be better off there. Above suggestion with IN does work for me.
|
# ? Aug 8, 2009 10:06 |
|
Golbez posted:Can you be a little more specific? You mean like having a dynamic number of parameters in a statement? I think that is pretty much the money, but for small queries, is doing all that code going to be slowing me down? I'm trying to write a query that would get a list of about 10 items every second (it generates json). It needs to be really fast. How would you manage the output? (IE making a function that returned an array like in fetch_array or PDO's fetchAll) McGlockenshire posted:Can't use PDO instead? I read somewhere that PDO was significantly slower than mysqli/mysql. If I'm wrong, please say. I really like PDO but this is going to need to be as fast as possible. Also, doesn't PDO have pretty much the same issue? Rat Supremacy fucked around with this message at 18:25 on Aug 8, 2009 |
# ? Aug 8, 2009 16:13 |
|
Does anyone know of a guide to successfully installing phpMyAdmin? I've tried it so many times and literally never gotten it to work. I downloaded the .zip and unzipped it. Then I added a config.inc.php file. My hosting company, 1and1, has a guide on how to edit it to configure with their mysql databases. My ultimate goal is to put all of my databases (from different servers) onto the same phpmyadmin page, so I don't have to constantly be going from one to another on 1and1's annoying control panel. Here's the contents of the config.inc.php file. The all caps stuff obviously has the correct host/username/pass for my mysql database. php:<? /* vim: set expandtab sw=4 ts=4 sts=4: */ /** * phpMyAdmin sample configuration, you can use it as base for * manual configuration. For easier setup you can use setup/ * * All directives are explained in Documentation.html and on phpMyAdmin * wiki <[url]http://wiki.cihar.com[/url]>. * * @version $Id: config.sample.inc.php 11781 2008-11-06 05:29:28Z rajkissu $ */ /* * This is needed for cookie based authentication to encrypt password in * cookie */ $cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */ /* * Servers configuration */ $i = 0; /* * First server */ $i++; /* Authentication type */ $cfg['Servers'][$i]['auth_type'] = 'config'; $cfg['Servers'][$i]['user'] = 'MYSQL_DATABASE_USERNAME'; $cfg['Servers'][$i]['password'] = 'MYSQL_DATABASE_PASSWORD'; $cfg['Servers'][$i]['only_db'] = 'MYSQL_DATABASE_DB_NAME'; /* Server parameters */ $cfg['Servers'][$i]['host'] = 'MYSQL_DATABASE_HOST'; $cfg['Servers'][$i]['connect_type'] = 'tcp'; $cfg['Servers'][$i]['compress'] = false; /* Select mysqli if your server has it */ $cfg['Servers'][$i]['extension'] = 'mysql'; /* rajk - for blobstreaming */ $cfg['Servers'][$i]['bs_garbage_threshold'] = 50; $cfg['Servers'][$i]['bs_repository_threshold'] = '32M'; $cfg['Servers'][$i]['bs_temp_blob_timeout'] = 600; $cfg['Servers'][$i]['bs_temp_log_threshold'] = '32M'; /* User for advanced features */ // $cfg['Servers'][$i]['controluser'] = 'pma'; // $cfg['Servers'][$i]['controlpass'] = 'pmapass'; /* Advanced phpMyAdmin features */ // $cfg['Servers'][$i]['pmadb'] = 'phpmyadmin'; // $cfg['Servers'][$i]['bookmarktable'] = 'pma_bookmark'; // $cfg['Servers'][$i]['relation'] = 'pma_relation'; // $cfg['Servers'][$i]['table_info'] = 'pma_table_info'; // $cfg['Servers'][$i]['table_coords'] = 'pma_table_coords'; // $cfg['Servers'][$i]['pdf_pages'] = 'pma_pdf_pages'; // $cfg['Servers'][$i]['column_info'] = 'pma_column_info'; // $cfg['Servers'][$i]['history'] = 'pma_history'; // $cfg['Servers'][$i]['designer_coords'] = 'pma_designer_coords'; /* Contrib / Swekey authentication */ // $cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey-pma.conf'; /* * End of servers configuration */ /* * Directories for saving/loading files from server */ $cfg['UploadDir'] = ''; $cfg['SaveDir'] = ''; ?> What the hell does that even mean? If I leave the config.inc.php file the way it was when I unzipped the whole package, it just goes to a login screen, and asks for a username and password that I don't have (or know where to find). I really wish this would work, it would save me so much time, but it really never has.
|
# ? Aug 9, 2009 03:54 |
|
haywire posted:I read somewhere that PDO was significantly slower than mysqli/mysql. If I'm wrong, please say. I really like PDO but this is going to need to be as fast as possible. quote:Also, doesn't PDO have pretty much the same issue? Mr Viper posted:Does anyone know of a guide to successfully installing phpMyAdmin? 2) Use the included configuration utility (in like /setup/ or /configuration/ or /install/ or something like that) to create your config.inc.php file 3) Copy the created file into the right place and nuke the setup directory 4) Works! But what you have now looks like it SHOULD work... But quote:
|
# ? Aug 9, 2009 08:19 |
|
McGlockenshire posted:Unless you're making tens of thousands of queries in a single script run and need it NOW NOW NOW NOW NOW NOW NOW you won't notice any slowdown. I've never noticed any performance difference. Even then, if performance is what you're looking for, why are you working with PHP? The issue isn't speed AS such but the results are time critical (auctions being bid), and it needs to be able to handle lots of requests. quote:What issue? You have a query, you have the placeholders, you have a list of stuff to replace the placeholders with. Maybe I don't really understand what problem you're encountering... Having a variable number of placeholders. IE for a select where IN( ?, ? ) query, but there could be lots of question marks.
|
# ? Aug 10, 2009 17:15 |
|
haywire posted:Having a variable number of placeholders. IE for a select where IN( ?, ? ) query, but there could be lots of question marks. In that case you have to create the select clause dynamically. If there are 10 items that go in the clause, then you add 10 questions marks to the string.
|
# ? Aug 10, 2009 17:46 |
|
Begby posted:In that case you have to create the select clause dynamically. If there are 10 items that go in the clause, then you add 10 questions marks to the string. Yeah that part isn't hard, it is the binding of those parameters to things. I don't think PDO has this issue, on reflection. mysqli_stmt::bind_param has the most loving retarded syntax ever.
|
# ? Aug 10, 2009 18:07 |
|
haywire posted:Yeah that part isn't hard, it is the binding of those parameters to things. I don't think PDO has this issue, on reflection. mysqli_stmt::bind_param has the most loving retarded syntax ever. Ah, yes, now I understand. Unfortunately I don't know of anything short of a custom solution that fixes the problem. It was one of the things that drove me up the wall when switching to PHP from Perl. With DBI, you can just pass in an array reference, and it'll automatically understand to use that for one and only one placeholder...
|
# ? Aug 10, 2009 20:23 |
|
McGlockenshire posted:Ah, yes, now I understand. Yeah, it is just that one, poorly written function. I expect you could hack up the extension quite easily, but I don't want my code to only work on modded install.
|
# ? Aug 11, 2009 00:05 |
|
haywire posted:Yeah, it is just that one, poorly written function. I expect you could hack up the extension quite easily, but I don't want my code to only work on modded install. You can extend PDO quite easily without hacking the actual install. You just include your PDO class with your code. Another option is to look at Zend_DB from Zend Framework. Overall I don't like the framework too much, but one thing its got going is that all the parts are completely independent, so you can just use the Zend_DB part and ignore the rest. Its really quite simple to use. Also, it includes a mysqli and a pdo adapter. So you can write all your code to use Zend_DB, then switch between mysqli or pdo with a simple config change and not have to modify your code.
|
# ? Aug 11, 2009 01:57 |
|
Begby posted:You can extend PDO quite easily without hacking the actual install. You just include your PDO class with your code. I meant extending mysqli, and I don't think my extension of the mysqli class quite has the capability. I want to avoid using too much 3rd party stuff, too. So I'll just have to do some independant PDO vs mysqli research, or look at other ways at speeding things up, or just stick with straight up queries for some things.
|
# ? Aug 11, 2009 08:01 |
|
Here's a simple newbie question, I'm doing a wordpress blog at the moment and everything has gone smoothly with redesigning the format, css, and getting it to do what I want. The last thing I'm looking to do is automatically post a small stock image in the top left corner of the blog post. The image posted will depend on the wordpress category i'm using. code:
LuckySevens fucked around with this message at 08:20 on Aug 11, 2009 |
# ? Aug 11, 2009 08:12 |
|
Is there an easy way to mask the source of a download link? For example, I have an file at http://192.168.0.1/soundfile.mp3, but I want it to appear to be coming from http://www.example.com/soundfile.mp3 Can this be done easily? Thanks
|
# ? Aug 11, 2009 10:09 |
|
Treytor posted:Is there an easy way to mask the source of a download link? For example, I have an file at http://192.168.0.1/soundfile.mp3, but I want it to appear to be coming from http://www.example.com/soundfile.mp3 Do you own https://www.example.com If so, you'd put a file on there that gets the http://192.168.0.1/soundfile.mp3 (assuming that it is actually a web accessible IP and not a lan one) and builds the mime header, then shoves the contents to the client.
|
# ? Aug 11, 2009 10:47 |
|
Yes you are correct on your assumptions. I guess I just have no idea how to do what you're saying, but it's promising to hear that it is possible.
|
# ? Aug 11, 2009 12:40 |
|
Actually I change my question, I managed to find a wp plugin which does the job nicely, the only problem now is getting the category image to format nicely with the blog post text. When I put the functions together:code:
Edit: In case its needed, documentation on the function from the plugin here LuckySevens fucked around with this message at 13:22 on Aug 11, 2009 |
# ? Aug 11, 2009 13:18 |
|
Treytor posted:Yes you are correct on your assumptions. I guess I just have no idea how to do what you're saying, but it's promising to hear that it is possible. 192.168 sounds like an internal IP, not external, which means unless https://www.example.com is on that same network this will probably not work as you intend. BUT: For default browser handling, whatever that might be (streaming, download, etc): php:<? // set the header header('Content-Type: audio/mpeg'); // prepare the request $ch = curl_init('http://192.168.0.1/example.mp3'); // make the request curl_exec($ch); // cleanup curl_close($ch); ?> Now, if you name the above file example.mp3 then you have to tell PHP to process MP3 files. The easier way to do this is just point it to example.php. If it needs to be .mp3, then you'll have to use an .htaccess file to tell your server to process it as PHP. How to do that depends on how your server is set up, there's no one solution. Supervillin fucked around with this message at 16:25 on Aug 11, 2009 |
# ? Aug 11, 2009 16:22 |
|
Thanks again for the help, I really appreciate it. The two servers in question here are not on the same network, but are both web accessible. I don't want my end user to be aware of the IP address server, only the domain name.
|
# ? Aug 11, 2009 21:18 |
|
haywire posted:I think that is pretty much the money, but for small queries, is doing all that code going to be slowing me down? I'm trying to write a query that would get a list of about 10 items every second (it generates json). It needs to be really fast. The output is managed like any other output, we're talking about a dynamic number of variables, not a dynamic number of selected columns...
|
# ? Aug 11, 2009 21:19 |
|
Golbez posted:The output is managed like any other output, we're talking about a dynamic number of variables, not a dynamic number of selected columns... Oh, I think I see, that does make sense. Doesn't change the params issue, thought Anyone got suggestions on the fluent interfacing query generation thing? I want to do something like php:<? while( $row = $db->select("hi","bye")->from("sup","hmoo")->where("blah","blah") ) { echo $row['hi']; } ?>
|
# ? Aug 11, 2009 23:50 |
|
haywire posted:Oh, I think I see, that does make sense. Doesn't change the params issue, thought quote:Anyone got suggestions on the fluent interfacing query generation thing? I want to do something like I know I've seen that done somewhere but I couldn't tell you where off the top of my head. Personally, I have no use for it, I hate abstraction and love working with the actual queries, though actually some of these things look very useful, like using an associative array for a mass insert in Zend_DB... but on the other hand, I figure, if you're putting it into the array, you can put it into the query. Same effort, and in my opinion, a tiny bit easier to debug. It would be nice to be able to use this kind of thing for a dynamic number of parameters though, of course. It's really annoying you can't just repeat $mysqli->bind_param for each parameter. (And, for that matter, using an abstraction layer to repeatedly bind new "WHERE"s, so I wouldn't have to care about if "AND" or "WHERE" was used correctly... anyone know anything like that?
|
# ? Aug 12, 2009 03:38 |
|
Golbez posted:I'm pretty sure any params issue you have, I've confronted in the past. What issue, you mean the fact that you have to use that big function just to have a dynamic number of params, or ...? Share the issue, we'll work it out Show the query you want generated and we'll figure how to get there. Dynamic # of parameters is exactly what I meant in my exact post. Say you are getting a string in the format 1,6,3,5,7 from your GET. This can be any amount long. You want to get this as a prepared statement. You can easily make the query using implode or whatever and substituting the numbers with ?. However, you have to use the loving bindParam syntax which is utterly nasty in every shape and form.
|
# ? Aug 12, 2009 07:57 |
|
haywire posted:Dynamic # of parameters is exactly what I meant in my exact post. Yes, it is. But there are ways around it. Make a function that, for every entry in an array, adds a "?," to your query (then trim the last comma, or do whatever feels right), then use the function I gave above to process a dynamic number of incoming parameters. So you have $query = "SELECT * FROM table WHERE RowID IN ($questionmarks)", $questionmarks consisting of "?,?,?,?,?", $values being an array consisting of 1, 6, 3, 5, and 7, and running that through the bindParams function earlier. It's not pretty, but it gets the job done.
|
# ? Aug 12, 2009 15:17 |
|
haywire posted:Oh, I think I see, that does make sense. Doesn't change the params issue, thought You can do the fluent interface thing with Zend_DB using mysqli as the driver and it will use prepared statements (Also, Zend_DB doesn't saddle you with the gay rear end mysqli::bind_param bullshit). The problems you are having really aren't that big of a deal and you can solve them most by using Zend_DB, extending Zend_DB, extending PDO, or rolling your own mysqli wrapper. Writing a fluent interface on your own isn't too difficult, you have an object return itself, the methods each write to arrays in the object, then the execute() method you take all the crap from the arrays and create a fancy SQL statement. Making sure the AND/WHERES get sorted out is as simple as doing implode(' AND ', $valuepairs) and sticking a WHERE in front. Creating the question marks for IN is as simple as doing implode(',', $arrayOfQuestionMarks) A fluent interface can be done by returning a self reference code:
You should really check out Zend_DB for ideas at the very least. Give PDO a try too. Yeah, its a bit slower, but I don't think its going to be noticeably slower even under heavy load. We use it on a database with about 30 million records under pretty high load where I work. Personally if it came down to it getting slow, I would much rather buy faster hardware than spend the time and headaches to move to mysqli.
|
# ? Aug 12, 2009 15:43 |
|
Begby posted:You can do the fluent interface thing with Zend_DB using mysqli as the driver and it will use prepared statements (Also, Zend_DB doesn't saddle you with the gay rear end mysqli::bind_param bullshit). I see what you mean, I do all of this already in this class: http://github.com/radiosilence/cheapo/blob/ddbea0c21badb639b6fd83dc5ecc85e26f6a791f/cheapo/query.php But I'm looking at making it an extension of db class or something to make using it less irritating. I presume Zend_DB is part of the Zend framework? If so, do I have to use Zend framework in order to use Zend DB? What do people think of out the Zend framework in general?
|
# ? Aug 12, 2009 19:15 |
|
haywire posted:I see what you mean, I do all of this already in this class: Overall I am really not that happy with a lot of the zend framework stuff. However, one thing they did very right was to make it so there is very little interdependency between the modules. So if you want to use Zend_DB, all you have to do is include that one thing in your project, you don't have to use anything else in their framework. (a lot of other frameworks require you to use all their crap) I think you could go so far as to delete everything except the Zend_DB folder and be good to go. (and by the way I already told you this about 15 posts back) I use Zend_DB within codeigniter for a lot of stuff with no ill effects. Zend_DB has a fluent interface. I don't use it though, all I use is an extension of the Zend_DB_Adapter class which I added a few minor odds and ends to.
|
# ? Aug 12, 2009 19:26 |
|
Begby posted:Overall I am really not that happy with a lot of the zend framework stuff. However, one thing they did very right was to make it so there is very little interdependency between the modules. So if you want to use Zend_DB, all you have to do is include that one thing in your project, you don't have to use anything else in their framework. (a lot of other frameworks require you to use all their crap) I think you could go so far as to delete everything except the Zend_DB folder and be good to go. (and by the way I already told you this about 15 posts back) I'll definitely look into it. I've got usage of my query fluent interface down to this: php:<? $db->build_query() ->select( "id" ) ->from( "auctions" ) ->where( "a", 1 ) ->order( 'tl', 'asc' ) ->limit( 8 ); $db->do_query( $result );?>
|
# ? Aug 12, 2009 20:22 |
|
PHPLinq can do that - http://www.codeplex.com/PHPLinq
|
# ? Aug 12, 2009 21:22 |
|
A Flaming Chicken posted:PHPLinq can do that - http://www.codeplex.com/PHPLinq That looks nice. I want to write my own though, that is why I am a little negative towards sessions of Zend. I'm hand rolling every part of my project (apart from the FirePHP debug class and jQuery) as I learn more that way and know exactly how to fix things. Also I'm adverse to including masses of files and 3rd party things every run because inclusions really slow things down without caching.
|
# ? Aug 12, 2009 21:46 |
|
haywire posted:That looks nice. I want to write my own though, that is why I am a little negative towards sessions of Zend. I'm hand rolling every part of my project (apart from the FirePHP debug class and jQuery) as I learn more that way and know exactly how to fix things. Its good to learn it. However, I think in the long run you should ditch the whole fluent interface for SQL thing. There is a reason why a lot of people don't use that, its nifty and slick, but inflexible. In the time it takes you to write out the all the code to create a query in a fluent interface you could have written it in raw SQL. Then there will be queries where you have to go tinker with your class, like if you decide you need to do a subquery or a complicated AND clause requiring a lot of parenthesis. You are better off trying to encapsulate all your database stuff into a set of classes that act as gateways for domain objects to your database with well written SQL instead of trying to code a sweet swiss army knife of sql.
|
# ? Aug 13, 2009 02:32 |
|
I am sorry to just drop this here but it has been a very frustraiting evening and I thought this was working earlier. I am trying to get a form to email using php and oddly enough it works fine in IE and does nothing in firefox. I have even drilled it down to making the form painfully simple Form code on one page code:
email-address = an actual email address. The forums seems to be adding things for me. code:
edit - forums adding email tags Spaceguns fucked around with this message at 06:00 on Aug 13, 2009 |
# ? Aug 13, 2009 05:56 |
|
If it works in one browser and not another then the issue has to be in the rendered html of the form. It can't be in your form handling/emailing code as thats not run in the browser. I'd suggest you replace mailer.php temporarily with a version that just var_dump()s $_POST to screen, and run the form through both browsers - check what the output of our temp page is, because one is probably giving garbage. Edit: and make sure the server is displaying errors while doing this. Then run your form page through an html / xhtml validator as appropriate, as it might help you find the issue faster. Its probably something really silly like an unclosed tag higher up in the page. Especially if IE is happy but FF shits it out.
|
# ? Aug 13, 2009 08:03 |
|
Begby posted:Its good to learn it. However, I think in the long run you should ditch the whole fluent interface for SQL thing. There is a reason why a lot of people don't use that, its nifty and slick, but inflexible. I've been wanting to implement django style models for a while now (manage.py sync-db, etc) but it is quite an odd issue.. I did it (sort of) in my first evar framework but it felt bloated. The models (or "metaclasses" as I called them) looked something like this: php:<?php /** * user.metaclass.php * * @version $Id$ * @copyright 2007 */ /** * * */ class user extends metaclass { /** * Constructor * @access protected */ /* Metaclass Property Setup */ public static $title = "User"; public static $table = "testUsers"; public static $propertyDefinitions = array( 'username' => array( 'type' => 'alphanumeric', 'title' => 'Username', 'requirements' => array( 'exists' => true, 'unique' => true, ) ), 'displayname' => array( 'type' => 'string', 'title' => 'Display Name', ), 'registrationDate' => array( 'type' => 'date', 'title' => 'Registration Date', 'hidden' => 'true', ), 'password' => array( 'type' => 'password', 'title' => 'Password', 'requirements' => array( 'exists' => true, ), ), 'email' => array( 'type' => 'string', 'title' => 'E-mail', 'requirements' => array( 'exists' => true, ), ), 'group' => array( 'type' => 'foreign', 'requirements' => array( 'exists' => true, 'real' => 'group', ), ), ); /* Start of Functions */ public function setPassword($newPassword,$oldPassword=null) { if($oldPassword) { if(janitor::createPasswd($oldPassword,md5($this->property['registrationDate'])) !== $this->property['password']) { throw new Exception("oldpassworddoesnotmatch"); } } $this->setProperty('password',janitor::createPasswd($newPassword,md5($this->property['registrationDate']))); } public function registerNewUser () { } } ?> php:<?php /** * metaclass.class.php * * @version $Id$ * @author James Cleveland * @copyright 2007 * * The idea is that every class has a database table, and this class handles * putting things into and out of the database, creating the database needed * generating queries, etc. * Not that it should be used for every part of the system, just most of it. * It is built using php's existing class system, for speed. */ abstract class metaclass { public static $classesLoaded = array(); public static $classesSkipped = array(); public static $db; public static $tablesLoaded = array(); public $invalid; private $id; private $properties; public static function init($db) { self :: $db = $db; } public static function loadClass($class, $rel = null) { $classString = ($rel ? $rel.'/' : null).$class; if (!(in_array($classString, metaclass :: $classesSkipped) !== false)) { if (!(in_array($classString, metaclass :: $classesLoaded) !== false)) { $siteMetaPath = config :: get('site/path').'/metaclasses/'. ($rel ? $rel.'/' : null).$class.'.class.php'; $quickboxMetaPath = config :: get('quickbox/path').'/metaclasses/'. ($rel ? $rel.'/' : null).$class.'.class.php'; $path = file_exists($siteMetaPath) ? $siteMetaPath : $quickboxMetaPath; if (file_exists($path)) { require_once $path; metaclass :: $classesLoaded[] = $classString; } else { metaclass :: $classesSkipped[] = $classString; } } } } public static function create($class, $rel = null) { $classString = ($rel ? $rel.'/' : null).$class; self :: loadClass($class, $rel); if (!in_array($classString, metaclass :: $classesSkipped)) { return new $class; } else { return false; } } public static function load($class, $id) { $object = metaclass :: create($class); $classVars = metaclass :: getClassVars($class); $result = self :: $db -> query("SELECT * FROM `".$classVars['table']."` WHERE `id` = '$id' LIMIT 1"); $row = self :: $db -> assoc($result); $object -> setId($id); foreach ($classVars['propertyDefinitions'] as $k => $v) { $object -> setProperty($k, $row[$k]); } return $object; } public function save() { $classVars = metaclass :: getClassVars(get_class($this)); try { # Validation bit $validate = new validate(metaclass :: $db); $validate -> exec($this); if (!$validate -> valid) { $this -> invalid = $validate -> invalid; return false; } else { if (!in_array($classVars['id'], self :: $tablesLoaded)) { if (!metaclass :: $db -> tableExists($classVars['table'])) { metaclass::createTable($classVars['table'], $classVars['propertyDefinitions']); } metaclass::$tablesLoaded[] = $classVars['table']; } if (janitor::notNull($this -> id)) { # Inserting new row, creating object. $query.= "UPDATE `".metaclass::$db -> getProperty('database')."`.`".$classVars['table']."`\n"; $query.= "SET\n"; foreach ($classVars['propertyDefinitions'] as $k => $v) { $queryRows[].= '`'.$k.'` = \''.janitor::cleanData($this -> properties[$k]).'\''; } $query.= implode(",\n", $queryRows); $query.= "\nWHERE `".$classVars['table']."`.`id` = '".janitor::cleanData($this -> id)."'"; if (!metaclass::$db -> query($query)) { return false; } } else { # Updating existing row, editing object. $query.= "INSERT INTO `".metaclass::$db -> getProperty('database')."`.`".$classVars['table']."`\n"; foreach ($this -> properties as $k => $v) { $queryFields[].= '`'.$k.'`'; $queryData[].= '\''.janitor::cleanData($v).'\''; } $query.= "(".implode(",\n", $queryFields).")\n"; $query.= "VALUES\n (".implode(",\n", $queryData).")"; if (!metaclass::$db -> query($query)) { return false; } } return true; } } catch(Exception $e) { trigger_error($e -> getMessage(), E_USER_ERROR); } } public static function getClassVars($class) { self::loadClass($class); return get_class_vars($class); } private static function createTable($tableName, $propertyDefinitions) { $query.= " CREATE TABLE `".metaclass::$db -> getProperty('database')."`.`$tableName` (\n"; $query.= " `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,\n"; foreach ($propertyDefinitions as $k => $v) { $vars = metaclass::getClassVars($v['type']); $querylines[].= "`$k` ". (janitor::notNull($vars['fieldtype']) ? $vars['fieldtype'] : 'VARCHAR( 255 )')." NOT NULL "; } $query.= implode(",\n", $querylines); $query.= ")"; metaclass::$db -> query($query); } public function setProperty($property, $value) { $this -> properties[$property] = $value; } private function setId($value) { $this -> id = $value; } public function getProperty($property) { return $this -> properties[$property]; } public function getItems($table,$fields=false) { $query = 'SELECT '.(is_array($fields) ? implode(',',$fields) : '*').' FROM `'.$table.'`'; $result = metaclass::$db->query($query); while ($row = metaclass::$db->assoc($result)) { $return[] = $row; } return $return; } } ?> e: updated metaclass with a slightly newer version. Rat Supremacy fucked around with this message at 08:20 on Aug 13, 2009 |
# ? Aug 13, 2009 08:06 |
|
|
# ? May 16, 2024 07:10 |
|
haywire posted:Cool model class stuff I think thats good that you are learning all of that, and I went down that same road. However, practically you may find that it might get inflexible down the road and hard to maintain. I posted a bunch of stuff on these and other forums and people told me to not do it, and I did it, and now I am in trouble with a bunch of old poo poo that is really really difficult to maintain and overly complex. If you do want to do that, its good to learn it, but really you should use something that is community supported, or become a contributor to an existing project. How I personally do it is this (not saying that you should do it this way, or its the right way, others might say I am crazy). I do this in both PHP and C#. I have a set of domain classes. These represent the data that my application interacts with. These are by not always 1:1 mappings to a database. Some of the classes get reused within other classes, some are immutable value objects, etc. For instance, right now I am working with orders and shipments and such. A few of my domain objects are something like Address Weight Country Shipment Package Item Dimensions An address contains a country, and a shipment contains two address objects, one for from and the other for destination. Shipment contains a weight object for total weight of all packages, package contains a weight object for total weight of all items, and items contains a weight object. A shipment has a list of packages, and a package has a list of items. The weight object allows me to read out ounces/pounds, or get it as a decimal. Dimensions allows for calculating total volume, converting between cm and in, etc. The only thing that goes in these domain objects is data and some logic to manipulate and check said data. Having these completely separate from the database allows me to structure them however makes most sense for working with the objects. It also allows me to easily unit test everything. Then for the above domain objects I have one class that reads and writes shipments to the database (since my application pretty much treats shipments like a single entity and deals with them in their entirety) and has methods like Shipments.Validate(Shipment shipment) Shipments.Save(Shipment shipment) Shipments.Void(Shipment shipment) Shipments.Find(shipmentID) Shipments.FindByReference(reference1) Shipments.Search(SearchParams search) Search params is a simple class where you can assign things like a date range, vendor, etc. Then the shipments class turns it into a where clause. All the database stuff is stored within the shipments class. When you save a shipment it writes to something like 8 different normalized tables which differ somewhat from the domain objects. For instance weight is stored as just a decimal, dimensions are stored as three fields for length height and width, and the addresses (even though they are a separate object) are stored in the main shipments table like fromCompany, toCompany, fromName, toName etc. This approach might seem like it might take longer to write since there is a lot of classes to create and queries to write. However, its very easy to maintain and I think if I tried to do it with some sort of magic class I would run into issues and have to change my domain objects so they worked with the db class or do some hacking.
|
# ? Aug 13, 2009 17:56 |