Jump to content

mac_gyver

Staff Alumni
  • Posts

    4,831
  • Joined

  • Days Won

    146

Everything posted by mac_gyver

  1. VSC reporting that the function is not defined is because VSC is not smart enough to know that the function can be defined in a separate file or if the code you posted at the top of this thread is an accurate arrangement of code in a single file (doubtful now), that you can define a function anywhere in a php project with respect to where it is called, provided it's not conditionally defined or conditionally required/included (the first two cases I posted.) You have been side-tracked by VSC's reporting of a problem that doesn't actually exist. You are going to have to actually learn the fundamentals of php programming so that you are smarter then the Microsoft tool you are trying to use.
  2. relying on a Microsoft product as a programming aid is foolish. if you are not posting actual errors that you got from PHP on your localhost web server when you tried to run your code, you are wasting yours and our time. if you are not posting, copy/pasting, your actual code, you are wasting our time as well.
  3. the posted code contains a php syntax error (a closing ?> tag inside the function definition) and doesn't run at all, so that's not the actual code producing that error. a few possibilities why the function definition is not present in the current program scope - the function definition is inside of a conditional statement, and so isn't defined until the code where that statements is at has been executed and the conditional statement is true. the function definition is inside of another function definition, and so isn't defined until the parent function has been called. the function definition is being required (you should use require for things your program just have) using a url, not a file system path, and is not in the same instance of your program as the function call. after you correct the php syntax error, the posted code produces an undefined constant error because the function call is before the point where the constants are defined. it would take seeing the actual code producing the error to help with what is wrong with it.
  4. if you use the email address, that was just created for you at your web hosting, as the To: email address, you can probably get the mail() function to work.
  5. gmail has recently stopped accepting emails that are being sent by unknown, unauthenticated email clients/systems, such as a sending mail server at some random web hosting. you must generate an OAuth token and use it to authenticate when sending to gmail. see the following post and thread it is in - prior to this, you were required to use smtp authentication against your gmail mailbox, which the php mail() function does not support, so you need to use either the phpmailer or swiftmailer class in any case.
  6. most database errors are fatal problems, due to programming mistakes, or due to data issues like have been listed in this thread. since there's no user interaction with this code, there's no case where a database statement error is recoverable by the non-existent user. therefore, all database statement errors should simply get logged. the simplest way of doing this, which requires no code in the application (the current catch logic, if it is being executed at all, is only logging the error message, it does not include the filename and line number where the error occurred, and it is allowing execution to continue when a fatal problem has occurred) is to use exceptions for database statement errors and simply let php catch the exception, where php will use its error related settings to control what happens with the actual error information (database statement errors will 'automatically' get displayed/logged the same as php errors.) the PDO connection already always uses exceptions for errors, but if there's tri/catch code present that isn't properly dealing with a connection error, it's not helping, and should be removed anyways. setting the PDO error mode to use exceptions, applies to all the rest of the statements - query, prepare, and execute. after insuring that this is being set, for what this application is for, any try/catch code should be removed so that php will catch the database exceptions.
  7. as a separate post. this code is typical misuse of OOP. someone took a few lines of main code, building and executing an insert query, threw a class definition around it, then to make it 'work' had to add $this-> in front of everything, add a bunch more code to build the input properties, code to instantiate the class, code to call the various methods, code (if any) to test the returned values, and code (if any) to use the output properties. if this method gets called and there isn't a database connection (what the first few lines of code are testing), it means that the connection code doesn't have error handling that would have stopped the whole database dependent application from being executed upon a connection error, and for the rare cases where a connection was successfully made, but lost during execution of the code, the fatal php error that would have occurred when the non-existent connection was used should be getting logged to let you know what type of problems are occurring. edit: since the code is just returning in this case, and it's doubtful that the returned value is causing any sort of logging/reporting to occur, you will never know if this is the cause of the missing inserted data. this brings up an additional point for debugging the problem. php's error_reporting should be set to E_ALL and log_errors should be set to ON, preferably in the php.ini on the system, so that all php errors will get reported and logged. if the php/web server error log is empty, either this is not the case or the log file settings are not setup.
  8. if the PDO error mode IS set to use exceptions, the $this->_debugOn code won't have any effect, since it won't ever get executed upon an error. if the PDO error mode is not set to use exceptions, the $this->_debugOn code will be executed, but it is then up to the application code to actually test and use those class properties. since this code apparently doesn't have a user interface, the $this->_debugOn code was probably only ever there for direct requests during developmental testing. for the the try/catch code to 'work' the PDO error mode must be set to use exceptions. there would be something in the database connection code using PDO::ATTR_ERRMODE and PDO::ERRMODE_EXCEPTION if this setting is on. without investigating (logging) what the actual sql syntax being built is and what is being supplied to the ->execute(...) call, there's no guarantee that this is an actual prepared query, and if an emulated prepared query is being used, sql special characters in a value can still break the sql query syntax if the character set that php is using is not the same as the character set of the database tables. posting the database connection code, less any connection credentials, would show the error mode setting, emulated prepared query setting, and any character set setting.
  9. when data insertion fails occasionally, it's usually because of sql special characters in a value breaking the sql query syntax, data containing duplicate values that violate a unique index or other constraint, or data that is out of range for a column definition. these conditions would produce query errors, so, the question becomes does the php code have error handling for all the database statements that can fail - connection, query, prepare, and execute that would be logging the errors to the php error log or is the mysql general query log enabled (it's not by default)?
  10. here's a big problem with the existing table per category. the ids are repeated, so, having an id doesn't uniquely tell you what the item is, nor does it let you find (sub)items related to the item. when someone selects an item, you cannot just store the item id and the quantity. you must also store the category_id, requiring more data storage and more code for every operation. are you actually reading and getting the information in the replies? there's a post above stating how simple you can build the category and item tables from the table data you have shown us. the code to do so would look like (untested) - <?php // get or build a list of table information $tables = []; // table - is the existing table name // name - is the item name, which unfortunately repeats part of the table name, making everything harder than necessary // category - is the desired category name $tables[] = ['table'=>'rifles','name'=>'rifleName','category'=>'rifle']; $tables[] = ['table'=>'shotguns','name'=>'shotgunName','category'=>'shotgun']; // add entries for the rest of the tables here... // query to populate category table $sql = "INSERT category (name) VALUE (?)"; $cat_stmt = $pdo->prepare($sql); foreach($tables as $table) { // insert the category data $cat_stmt->execute($table['category']); $cat_id = $pdo->lastInsertId(); // query to populate item table $sql = "INSERT item (category_id, name, em, gm) SELECT $cat_id, `{$table['name']}`, em, gm FROM `{$table['table']}`"; $stmt = $pdo->query($sql); }
  11. if you look again, the seconds are not used. the php date format string would be - Y-m-d\TH:i
  12. one of the points was properly organizing the data in the database - which brings up the programming motto - a good database design supports good code design. you can build the category and item tables from your existing tables by using a dynamically built INSERT ... SELECT query and some code to get and loop over all the table names.
  13. php installation was probably updated and turned off the output_buffering php.ini setting, resulting in previously working bad code to stop working.
  14. the code i posted is a data-driven design. it takes the input data that is supplied to it and dynamically produces as many select/option menus as there are categories in the data. the javascript is also general-purpose and will work as is regardless of how many different select/option menus there are. there's no need to touch any of the actual code, unless there's a mistake that needs to be fixed or an actual change is desired. if you comment out the database specific code, and un-comment the fake data code, you can try this by itself to see how it works.
  15. see the following example, using the above points (tested with fake data) - <?php // initialization $servername = "localhost"; $dbport = '3306'; $dbname = 'ehr_tracker'; $dbuser = 'root'; $dbpass = ''; // when you make the connection, also set the default fetch mode to assoc, so that you don't need to specify it in each fetch statement // there's no good reason for you to catch a connection error, just let php catch it. // also, don't output the raw database errors, as these only help hackers. // likewise, a connection error is a fatal problem and code should stop executing in order to prevent follow-on errors. $pdo = new PDO("mysql:host=$servername;dbname=$dbname;charset=utf8;'", $dbuser, $dbpass, array(PDO::ATTR_EMULATE_PREPARES => false,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); // get method business logic - get/produce data needed to display the page // the following assumes you want all category data, // if not add a WHERE clause to get just the categories you want $sql = "SELECT c.name category_name, i.id, i.name, i.em, i.gm FROM items i JOIN category c ON i.category_id = c.id ORDER BY c.name, i.name"; $stmt = $pdo->query($sql); // fetch the data, indexing/pivoting it by the first column selected - category_name $item_data = $stmt->fetchAll(PDO::FETCH_GROUP); /* // fake some data $data = []; $data[] = ['id'=>'1', 'name'=>'r1', 'em'=>'10', 'gm'=>'12', 'category_name'=>'rifle']; $data[] = ['id'=>'2', 'name'=>'b1', 'em'=>'20', 'gm'=>'22', 'category_name'=>'bow']; $data[] = ['id'=>'3', 'name'=>'b2', 'em'=>'25', 'gm'=>'27', 'category_name'=>'bow']; $data[] = ['id'=>'4', 'name'=>'s1', 'em'=>'30', 'gm'=>'32', 'category_name'=>'shotgun']; $data[] = ['id'=>'5', 'name'=>'s2', 'em'=>'33', 'gm'=>'34', 'category_name'=>'shotgun']; $data[] = ['id'=>'6', 'name'=>'s3', 'em'=>'37', 'gm'=>'38', 'category_name'=>'shotgun']; // index/pivot the fake data like the FETCH_GROUP would produce $item_data = []; foreach($data as $row) { $item_data[ $row['category_name'] ][] = $row; } //echo '<pre>'; print_r($item_data); echo '</pre>'; */ // html document starts here... ?> <html> <head> <style> body { background: black; color: white; } input { background: black; color: white; border: 1px solid orange; text-align: center; } select, selection { background: black; color: white; border: 1px solid orange; } table { border: 1px solid gray; border-collapse: collapse; } </style> </head> <body> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $(document).ready(function() { $(".populate_em_gm").change( function() { let em = $(this).find("option:selected").data("em") let gm = $(this).find("option:selected").data("gm") $(this).closest('tr').find('.em').val(em) $(this).closest('tr').find('.gm').val(gm) }) }) </script> <table border="1"> <tr><th>Items</th><th>em</th><th>gm</th><th>+</th><tr> <?php foreach($item_data as $category_name=>$arr) { $cn = ucfirst($category_name); echo "<tr><td colspan='2'>{$cn}s</td><td></td><td><button type='button'>+</button></td></tr>"; echo "<tr><td>"; echo "<select class='populate_em_gm' name='$category_name'>"; echo "<option value=''>Choose a $cn</option>"; foreach($arr as $row) { echo "<option value='{$row['id']}' data-em='{$row['em']}' data-gm='{$row['gm']}'>{$row['name']}</option>"; } ?> </select></td> <td><input type="text" class="em" value="0" disabled size="5"/></td> <td><input type="text" class="gm" value="0" disabled size="5"/></td> <td>+</td> </tr> <?php } ?> </table> </body> </html>
  16. writing out, copy/pasting/overtyping, code for every possible value/category is not programming, that's you being a human-keyboard-macro. you are not using the computer as a tool to accomplish a task, the computer is using you. your database design should have a category table, with id and name columns. this would establish category_ids. you should have an item (or similarly named) table with id, category_id, and name columns. you would then just use one query to get the data that you want and loop over it to produce the output. to add new categories or add items under a category, you would just insert the data into the appropriate table(s), and the code would 'automatically' use the new values without you needing to touch the code. you would take a similar Don't Repeat Yourself (DRY) approach in the html and javascript, where you would dynamically build the output sections by looping over the data, putting each select/option menu and em/gm fields in a 'container', that one instance of general-purpose javascript would operate on to populate the correct em/gm fields when there's a change in the corresponding select/option menu.
  17. that's not the correct format, resulting in different browser/operating system/local system defaulting to what they think they should do. did you read the information at the developer.mozilla.org link that was given?
  18. the format for the value of a datetime-local field is - YYYY-MM-DDThh:mm ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local
  19. why are you using two different names for the same meaning data? besides the existence or absence of the id, what's different about the edit vs create form? can you not just always have a hidden id field that has a value if editing an existing entry or is empty when creating a new entry? your post method form processing logic should be - detect if a post method form was submitted perform common tasks, such as trimming all the input data at once, validating the common inputs between both processes test if the id is empty or not if the id is empty, run the unique code for creating a new entry else, run the unique code for updating an exiting entry
  20. the following is the SELECT query prototype definition, with the elements you will need in bold - SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]] the select_expr would include a COUNT() term to get the number of matching rows per group, along with any other columns you want in the result. the FROM table_references would include a JOIN between the two (or is it three as the title says) tables. the WHERE where_condition would match the column and value for billable items. the GROUP BY col_name would group by the customer id/name column. the ORDER BY col_name would sort the results the way you want, such as by the customer name. give this a try.
  21. here's a correction to the above, move the closed != 1 codition to the sub-query - SELECT q.id as quoteId, q.job_id as jobId, j.name as jobName, j.client_id as clientId, c.name as clientName, q.currency, q.version FROM quote q JOIN job j ON j.id = q.job_id JOIN client c ON c.id = j.client_id WHERE q.id IN(SELECT MAX(id) FROM quote WHERE closed != 1 GROUP BY job_id)
  22. using the IN(sub-query) method. untested, should work - SELECT q.id as quoteId, q.job_id as jobId, j.name as jobName, j.client_id as clientId, c.name as clientName, q.currency, q.version FROM quote q JOIN job j ON j.id = q.job_id JOIN client c ON c.id = j.client_id WHERE q.closed != 1 AND q.id IN(SELECT MAX(id) FROM quote GROUP BY job_id) in writing the above, i realize that your quote table contains redundant data in that it has the client_id in it. the reason you are joining the client table to the job table is because the client is related to the job, not to the quote. if you post your table definitions, just post an .sql dump of your database so that someone could help by actually testing the query
  23. i/we would assume that's the id, auto-increment primary index for an existing record in the database table, passed in a hidden form field, not one of the user entered fields. you would then use the existence or absence of the id to control if you are editing/updating existing data or inserting new data.
  24. yes. just name it $item, because that is what it is in the code that's calling that function. then reference elements in item, e.g. $item['quantity'] inside the function code. this actually would have prevented the initial error at the top of this thread, because there would be no need to match up all the different parameters. it will also allow you to add more values, such as the lineNotes, simply by selecting that data where you are querying for it, then using that data inside the function. you won't have to edit the list of call-time parameters every time you change the data being passed.
  25. another issue with the posted code. when you are building the 'selected' option choices, in both the quantity and the item menus, you are outputting the option with the selected attribute when the existing value is the same as the value being output AND you are repeating the same option choice without the selected attribute. e.g. if the selected quantity is 3, you are outputting an option choice for 3 that is selected, followed by another option choice for 3 that is not selected. i doubt this is the intended result. the only conditional logic should be to determine what the selected attribute should be, the option markup should only be output once per value, that is either selected or not. note: you can simply put the 'selected' attribute in or leave it out. you don't have to put it in AND set it to a (true, i.e. any non-empty string) value to cause the option to be selected. if by some chance this is the intended result, in the case of the item select/option menu, the data-... attribute(s) are used in the lineTotal/line-total calculation, so they must be output in every option choice. the current code is not outputting them in the 'selected' option choice, which will prevent the calculation code from producing the total.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.