Jump to content

DeX

Members
  • Posts

    258
  • Joined

  • Last visited

Everything posted by DeX

  1. I took a closer look at how the constructor is building the array of information and it doesn't appear to be the database calls, there are actually very few here. Here is the flow of how the array is built: - a database call is made to get all product prices and stored for future use (see farther down) - a database call is made to get all the product names and ID - a foreach loop is run on each product ID and inside the loop..... -- the product ID is passed to a function which has a large switch statement with a quantity calculation for each product ID. It finds the matching product ID, runs through the code to get the quantity (based on what the DOM element inputs are) and returns the quantity in an array (see why below) -- the same for the product widths (separate function) -- the same for lengths -- the same for heights -- then it gets the total quantity of the product. This is because the user could have entered 2 10x12 doors and 5 10x10 doors. It will get the 2 quantities individually in the previous step and the total quantity will be 7. -- then it gets the price of the product from the price array above -- then it gets the total price for the product, based on the other attributes and a multiplier by the unit price That's it, I've run the SQL queries individually and they all return instantly, but since it's running all of this individually on 360 products, it takes 4 seconds to complete. I have put an echo statement with a timer after each cycle and it gradually gets up to 4 seconds after running for all 360 products in the database. If you're asking why I can't get all of this information with a single call from the database, it's because the information isn't in the database. The user is entering data on the page to generate the quote and the quote is built entirely from the inputs the user has entered, with minimum database calls to get things like the unit prices of each product. I plan on using a rules system to build the quantity calculations for the products as some of you have helped me with in another thread but that change is being saved for after I complete this object oriented conversion I have going here.
  2. Moneris would have taken 3 weeks and a credit check to set up. Went with PayPal to meet the project deadline.
  3. Yes, the quote object is needed in entirety only on the Ajax call when the quote is being generated, which happens any time an input field is modified on the quote page. So reading through the answers is it correct to say that I can keep the large object creation in the constructor and I need to look into maybe indexing more tables in the database to speed up the query? I do need all the object variables somewhere on the quote page.
  4. Got it working by saving the listing prior to payment and activating the payment using PayPal's notify_url to pass back the property ID to be activated. Thanks for helping me out with the logic flow.
  5. You should be using opposing quotes when nesting, try switching to an apostrophe ( ' ) around all your $content data instead of double quotes ( " ). That might be part of your problem. Also these PDF generators don't like malformed HTML code do any mistake at all will corrupt the output. I can see where it's doing the PDF generation here: require_once(dirname(__FILE__).'/html2pdf/html2pdf.class.php'); $html2pdf = new HTML2PDF('P','A4','fr'); $html2pdf->WriteHTML($content); $html2pdf->Output('exemple.pdf'); You're passing in your HTML code through your $content variable and then attempting to save it to example.pdf inside the current directory. Does your webserver have permissions to save into that directory? Should you be trying to save into a different directory? If it still doesn't work, try passing in the most basic HTML you can think of and see if that works, then keep working up your $content variable by continuously adding pieces to it until you get to either: a) a working code sample using your entire $content piece. ----or----- b) the specific line that breaks your PDF generator. Try this to see if it works: require_once(dirname(__FILE__).'/html2pdf/html2pdf.class.php'); $html2pdf = new HTML2PDF('P','A4','fr'); $html2pdf->WriteHTML("<html><body>Hello</body></html>"); $html2pdf->Output('exemple.pdf'); If that doesn't work then your issue is somewhere further back in the code. Or if by "doesn't work" you mean that it doesn't save the PDF,, then you likely don't have write permissions in the directory where you're trying to save the example.pdf which here is your current directory and I can tell you now that would be an enormous security risk. I cringe at the thought of it.
  6. Thank you, I will switch it to store the information prior to payment and set the flag on payment success. If the session can't be edited in any way then I won't worry about it. I can even pass the database row ID to Paypal and get it back from them after payment so it doesn't have to go into the session. I think I can do that.
  7. My application is completely working, I'm simply wondering about how the flow should work. I have a PHP site where: 1. The user chooses 1 of 2 possible listing types to list their property for rent. Whichever they choose is stored in a session variable and they're redirected to page 2. 2. Here they fill out their rental property information, click a submit button and all entered information (once validated) is entered into a session variable with the listing type from page 1. They are now redirected to page 3. 3. Page 3 only has a button to click to be redirected to PayPal for payment. The only reason I don't have this button on page 2 is because I first had to get all the entered information into the session variable and I needed an action trigger in order to accomplish this, like them clicking the submit button. I don't know if I should combine the 2 or keep this third page with just the payment button, however it does give the opportunity for the user to view their entry and confirm it is all correct prior to paying. 4. They get redirected to PayPal, pay, then are redirected back to my site with either a success or failure message. If success, a PHP function runs (triggered by function passed through URL) and saves all listing information into the database as a successful purchase and pushes the listing live. Is this a proper use of session variables and should I instead be accomplishing this some other way? Should I be saving all the listing information after page 2 and instead just be putting the database row ID into the session variable, and then setting the row's PAID flag to 1 if the payment is successful? Then it's live once the flag is set? What if someone tries to use session injection in order to bypass the PayPal payment and just manuall put their information into the database? Is this possible?
  8. This might be an issue with semantics but PHP only runs on the server and you want a PDF of data available on the client. The idea of PHP is it is capable of generating and outputting HTML to the client, or handing it off to any number of PDF generators in HTML format. PHP itself doesn't display anything, it generates HTML in order to accomplish this. So once you have the HTML generated with PHP (all those echo statements and table elements you have there), then you pass it into FPDF and FPDF will then generate your required PDF document which you can save somewhere on the server. I use DOMPDF but it's based on the same base code as MPDF and FPDF are. They're all essentially the same. When I was first learning PHP, this took me over 6 months from start to finish to accomplish but now it's used every day.
  9. They are not stored in the session. Their scope is the page they're created on and that's it. Is this a good thing or bad thing?
  10. I seem to have slowed down my system dramatically here by attempting to move everything into objects. Previously I had a setup where the view would create the quote layout and would request any data it needed from the model. So any time it needed a quantity or cost of an item to show on the quote, it would go to the model and the model would actively go to the database and fetch it whenever asked. I have attempted to move away from this on-the-fly requesting from the database and figured it would be better to have the model fetch all of that information in the constructor and make it available whenever a "quote" object is created. I would then create the "quote" object at the beginning of the quote generation process in the view and any time I needed information relating to the quote, I would simply access it by: $this->quoteDetails = $this->quoteModel->getDetails(); // gets large array which was built in constructor echo $this->quoteDetails[$productId]['quantity']; ----- or ----- echo $this->quoteDetails[$productId]['unit_price']; From there I can access any of the product attributes (price, quantity, length....) or I can access any of the information the salesman entered when doing the quote: echo $this->quoteDetails['inputs']['customer-email']; The quote is refreshed through Ajax any time a field is changed and it used to take 1 second to fetch the new quote, now it's taking about 6 seconds for obvious reasons. Is this the wrong way to go about this?
  11. case (self::whiteCaulking) : $unit_rules = array(); // note: this example is for categories, not individual items, though you could mix them easily by adding an indicator to the defining array if the $key it a category or an item and call the appropriate method to get the correct quantity $unit_rules['ManDoors'] = array('mult'=>.75,'offset'=>0); $unit_rules['Windows'] = array('mult'=>.75,'offset'=>0); $group_rules = array(); $group_rules[] = array('operation'=>'function','name'=>'ceil'); $quantity = 0; // apply any unit rules foreach($unit_rules as $key->$rule) { $quanity += ($this->getTotalQuantityByCategory($key) * $rule['mult']) + $rule['offset']; } // apply any group rules foreach($group_rules as $rule) { switch($rule['operation']) { case 'function': $quantity = $rule['name']($quantity); break; } } $quantities[] = $quantity; break; Now that I have a chance to go through this very slowly and understand it I have a few questions about the flow of the logic. 1. The switch statement checks if we're looking for caulking and then enters into this logic to get the quantity. 2. What do you mean about this example being for categories and not for items? It seems like it would work for white caulking as it is. 3. I see you've added a multiplier and an offset for 2 other items (doors / windows), I understand that. 4. I see you add a group rule of rounding up on the screws to be used later, I get that. 5. Then you execute the unit rules, this part I kind of understand. You're passing in 'ManDoors' as the key for the calculation, would it be correct to assume I should pass in the database ID of the product instead? Is that better practice? 6. In the same section, you're adding the offset, should you be multiplying by it instead? Is this a typo? 7. If I want to apply the calculation only if the door is insulated, would I just use a second offset? Would I just keep adding offsets for any additional attributes I wanted to check for like this? For example, a height labour charge is added if the building is over 16 feet high because the crew has to rent a scissor lift to do the work and that cost has to get passed to the customer. So I'm assuming I would have an offset for whether or not the building is over 16 feet. 8. Do I hard code what these offsets are or can the client add an additional offset for a new attribute when adding items? This is great, thank you. If I can allow customers to add their own products I can set this up as a portal where clients can sign themselves up without any involvement from me and I can charge them a monthly fee for access so if you would prefer to speak on the phone and I pay you for an hour of your time, that would be fine by me. It would be nice to have it here for others to see too though.
  12. Just to clarify, I needed an image uploader tool so I decided to use this GitHub project I found. It works great with image uploads on my server except for this error I'm getting because of the .htaccess file. The error happens when I try and view the image uploaded through the tool. Commenting out the lines in the file makes everything work perfectly but I want to leave them in if they're a security measure.
  13. I need a file upload tool so I checked out the Blue Imp project on GitHub and everything works fine if I comment out all the lines in the .htaccess file. If I leave the lines in, I get an error when trying to view the file on my server. Commenting them out allows me to view the file no problem. Here is the error I get when I leave the .htaccess file alone: Here is the .htaccess file, the default file that came with the project: # The following directives prevent the execution of script files # in the context of the website. # They also force the content-type application/octet-stream and # force browsers to display a download dialog for non-image files. SetHandler default-handler ForceType application/octet-stream Header set Content-Disposition attachment # The following unsets the forced type and Content-Disposition headers # for known image files: <FilesMatch "(?i)\.(gif|jpe?g|png)$"> ForceType none Header unset Content-Disposition </FilesMatch> # The following directive prevents browsers from MIME-sniffing the content-type. # This is an important complement to the ForceType directive above: Header set X-Content-Type-Options nosniff # Uncomment the following lines to prevent unauthorized download of files: #AuthName "Authorization required" #AuthType Basic #require valid-user I first tried it with a file named 035.JPG and I thought maybe it had a problem with the file extension so I tried it again with uploading 035.jpg. That didn't work so I tried again with a different image named studio.png (Android Studio logo) and they all act the same. All files are very small thumbnails. My goal here is to keep the security of the file but allow my users to view the images they upload.
  14. The quantity of screws is based on the width of the sliding doors though, because there is a screw every so many square feet I believe. And then another set around the edge, something along those lines, I know the calculation I posted is the calculation we're using in production right now.
  15. Very cool, thank you! When the user is adding the new item and trying to input how the quantity calculation will work, how could the interface work for that? How could the specify that 3/4 of a tube of this new product needs to be added any time another product (doors / windows) is added? And to make it more complicated, what about all the confusion for how the user would enter the calculation for the Sliding Tec Screws? Would I just ask them for the multiplier, offset and rules for each product?
  16. I currently have a rather large PHP system where salesmen enter building details into a form and it builds a bill of materials (BOM) based on their inputs. Currently if they want to add any new materials into the system I have to do it because the calculations for getting the quantities of each item often depend on the attributes of other items in the system and I don't know how to give this control to the user. For example, when the quote is generated to calculate the BOM, it iterates over each material in the database and fetches the quantity calculation based on the ID. The quantity calculation is hard coded into the PHP and could be something like this: case (self::slidingTecScrews) : $quantity = 0; $buffer = 1.03; $screwsPerBox = 500; for ($i = 0; $i < count(json_decode($this->slidingQuantities, true)); $i++) $quantity += ($this->getSlidingDoorWidths($i) / 2 + 1) * $this->getSlidingDoorQuantities($i) * 5 * ceil($this->getSlidingDoorWidths($i) / 3) * $this->getSlidingDoorQuantities($i); // for all doors $quantity *= $buffer; // add buffer for extra screws if ($quantity > 0) $quantity += $screwsPerBox - ($quantity % $screwsPerBox); // round up to nearest full box $quantities[] = floor($quantity); break; In this example I get the quantity of Sliding Door Tec Screws and I run a calculation of how many I need per sliding door, then multiply it by the quantity of sliding doors to get the total. Then I add in a buffer because the crew is always dropping some on the ground, then I round it up to a full box. I have absolutely no idea how I would build an interface to allow one of the users to add in a product and assign this calculation for the quantity. For good measure here's another random quantity calculation: case (self::whiteCaulking) : $quantity = ceil(( $this->getTotalQuantityManDoors(true) + $this->getTotalQuantityWindows(true)) * .75 ); $quantities[] = $quantity; break; This one passes a variable into the quantity of doors / windows to specify whether or not it should include customer supplied doors into the calculation. Sometimes the door is added to the quote but the customer may want to supply it themselves and therefore we need to order the extra trims (and white caulk) but don't want to factor the door into the total material pricing. Here we use 3/4 of a tube of caulking per door / window. Sometimes it will use the quantity of doors in the calculation but only if they are insulated, or only if they're more than 12 feet high. Sometimes it'll add a product based on every 10 square feet of wall light in a building, it could be based on almost anything. Getting the quantity and per-item cost of everything in the BOM allows me to show the actual build cost for the structure and then apply a markup to get the selling price. Thanks a lot.
  17. I don't even know where to start, I see each one has its own pricing but what else do I look for? If I choose Paypal, am I able to have a custom payment layout without Paypal branding on it? The site I'm building is a completely custom site where people can list their homes for rent and there will be two types of rental list options. Here are the requirements for my gateway: - website only, no local point of sale transactions - only 2 different items for sale (2 types of rentals) - need to accept VISA and Master Card - until we expand into other countries, all customers will be from Canada - need to be able to use a completely custom interface that I'm building myself I think that's it. Thanks a lot, I've been looking at lots of solutions and can't figure out which one I should use. Paypal looks easy but the price is high.
  18. Oh wow, that was it! I didn't know what a table index was so I did some research yesterday and applied indexes to 2 of the tables based on the quote_id. Loading the quote details dropped from 104 seconds to 4 seconds and loading a quote to edit dropped from 28 seconds to 0 seconds. This is amazing, thanks a lot! I haven't tested inserting the records, I hope that hasn't increased much as a result.
  19. I'm back from vacation and hoping to get this resolved now, thanks for being patient while I was away. Height, width, length and quantity are attributes of doors and windows being added to the building. Because the use is able to continuously add as many doors and windows as they like, I store each set of attributes in a JSON string, that's why they're varchar. For example, if the user enters a 3x4 window and a 3x5 window, the heights column will get the following data: ["4","5"] and width will get: ["#","3"] I may be doing this wrong but it's the best way I've found so far. The reason I have a purchase_order_id for each product is because the administrators control which products show up on which purchase orders in the system. I need to store which purchase order the item was on when the quote was made in case it changes later on. I want the item to be put on its original purchase order, now the one it was changed to, if that makes sense. I'm already aware there is a better way for this, I plan on storing all edits in the main purchase order table and then just referencing back to the purchase order that item appeared on at the time period the quote was done. It's on the to do list. I very much appreciate you supplying me with the new SQL, thanks a lot, however it didn't quite work. I made some edits to yours and got the following: SELECT mqp.product_id, mqp.price_per_k, mqp.board_feet, mqp.location, mqp.power, mqp.locking_handle_side, mqp.unit_price, mqp.total_price_calculation_id, mqp.quantity, width, length, height, c.name, total_price FROM match_quote_product mqp JOIN building_products bp ON mqp.product_id = bp.id JOIN match_quote_colour mqc ON mqp.colour_type_id = mqc.colour_type_id AND mqp.quote_id = mqc.quote_id JOIN colours c ON mqc.colour_id = c.id WHERE mqp.quote_id = 50000 AND bp.purchase_order_id = 5 ORDER BY purchase_order_order ASC I had to: - add a comma at the end of line 1 - change building_products to bp in the where clause - change colours to c in the select statement - change match_quote_product to mqp in the where clause The query now works but returns 0 rows, I'm not sure why. I have to go through it and try to understand what it's doing but something must not match another column in the JOIN.
  20. | match_quote_product | CREATE TABLE `match_quote_product` ( `id` int(11) NOT NULL AUTO_INCREMENT, `quote_id` int(11) NOT NULL, `product_id` int(11) NOT NULL, `width` varchar(255) NOT NULL, `length` varchar(255) NOT NULL, `height` varchar(255) NOT NULL, `location` varchar(100) NOT NULL, `quantity` varchar(255) NOT NULL, `locking_handle_side` varchar(100) NOT NULL, `power` varchar(100) NOT NULL, `insulated` tinyint(4) NOT NULL, `customer_supplied` tinyint(4) NOT NULL, `storey` varchar(100) NOT NULL, `window_inserts` int(11) NOT NULL, `board_feet` double NOT NULL, `price_per_k` double NOT NULL, `unit_price` double NOT NULL, `total_price_calculation_id` int(11) NOT NULL, `purchase_order_id` int(11) NOT NULL, `colour_type_id` int(11) NOT NULL, `total_price` varchar(100) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3248453 DEFAULT CHARSET=latin1 | mysql> explain select product_id, match_quote_product.price_per_k, match_quote_product.board_feet, match_quote_product.location, match_quote_product.power, match_quote_product.locking_handle_side, match_quote_product.quantity, width, length, height, colours.name, match_quote_product.unit_price, total_price, match_quote_product.total_price_calculation_id from building_products, match_quote_product, match_quote_colour, colours where building_products.id = product_id && match_quote_product.colour_type_id = match_quote_colour.colour_type_id && match_quote_colour.colour_id = colours.id && match_quote_product.quote_id = 50000 && match_quote_product.quote_id = match_quote_colour.quote_id && building_products.purchase_order_id = 5 order by purchase_order_order asc; +----+-------------+---------------------+------------+--------+---------------+---------+---------+------------------------------------------------------+---------+----------+----------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------------+------------+--------+---------------+---------+---------+------------------------------------------------------+---------+----------+----------------------------------------------------+ | 1 | SIMPLE | match_quote_product | NULL | ALL | NULL | NULL | NULL | NULL | 2846461 | 10.00 | Using where; Using temporary; Using filesort | | 1 | SIMPLE | building_products | NULL | eq_ref | PRIMARY | PRIMARY | 4 | integrity_development.match_quote_product.product_id | 1 | 10.00 | Using where | | 1 | SIMPLE | match_quote_colour | NULL | ALL | NULL | NULL | NULL | NULL | 573276 | 1.00 | Using where; Using join buffer (Block Nested Loop) | | 1 | SIMPLE | colours | NULL | eq_ref | PRIMARY | PRIMARY | 4 | integrity_development.match_quote_colour.colour_id | 1 | 100.00 | NULL | +----+-------------+---------------------+------------+--------+---------------+---------+---------+------------------------------------------------------+---------+----------+----------------------------------------------------+ 4 rows in set, 1 warning (0.03 sec)
  21. It's a simple table with an ID, a quote_id (to match up to the quote), a product_id (to match up to the product) and then each other column is an attribute like length, width, height, quantity and price. When loading a purchase order to view or edit, I need to pull out each material of a certain type (lumber, metal, screws) and display the relevant materials on that purchase order with their attributes. The attributes are also building specific because the lumber and metal lengths / quantities will change per building.
  22. I have a quoting system which calculates the quantity and other attributes of 360 different building products every time a quote is generated in order to calculate a final cost. When the quote is performed, I'm saving each individual product as a row in a database table with each attribute (length, width, quantity, price) as columns in that table. Right now I'm just about to cross over 3,000,000 records in the table and it takes quite a while to perform queries each time a quote retrieval is requested by a user. I'm wondering if there would be any performance increase if I were to start storing all products in the table in a single JSON string taking up only one row and then parsing the string once it is retrieved.
  23. Thank you. One more question, if I'm getting the price of the quote, how do I know if that's already in the model object or if I need to get it from the database? For example, the first time I need to fetch the price, I would go to the database, get it, then set it in the quote model. The next 10 times I need to get that price while displaying the same page (in various places), I don't want to keep going back to the database for the price, how do I know if I can retrieve it from the model object using the getter? Do I have a piece of code in the getter that checks to see if the local variable is set and return if so?
  24. No not at all, I very much appreciate the guidance. If using an ORM library is the proper way to go for medium scaled PHP implementations, then that's what I will use. Just as long as it's better long term and not just short term. I want the best long term solution.
×
×
  • 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.