Jump to content
Larry Ullman's Book Forums

Antonio Conte

Members
  • Posts

    1084
  • Joined

  • Last visited

  • Days Won

    126

Posts posted by Antonio Conte

  1. Jon or Larry might give you some feedback on the regular expression. If you only want to solve the problem, you could consider using a function like strpos() instead. Something like this should work excellent:

    $subject = "AStringWithA spaceInIt";
    $pattern = " ";
    
    if ( strpos($subject, $pattern) === true )
    {
       echo "Pattern found in subject";
    }
    else
    {
       echo "No pattern found in subject";
    }
    

    The function is not binary safe, that's the reasoning behind checking for === true.

     

    Hope that helps.

  2. You HTML output is incorrect. Look at this:

    <td>First Name</td>
                <td><input type="text" name="first_name" id="first_name" size="45"/></td>
              </tr>
              value=<?php if (isset($_POST['first_name'])) echo $_POST ['first_name'];?>
    

    The code should probably be:

    <tr>
        <td>
            <input type="text" name="first_name" id="first_name" size="45" value="<?= (isset($_POST['first_name'])) ? $_POST ['first_name'] : ''; ?>"/>
        </td>
    </tr>
              
    
  3. There's no definite answer here. It pretty much depends on what you need to do with the class. There's a principle called the "Single responsibility principle" I really like. It says that a class and each method should only have one responsibility. This can often be a bit tricky to define, but "representing a User instance" and "creating a User instance" is so different they should probably be handled by different classes... So, how can do we do that?

     

    1. Create a model:

    Create a new class that takes the PDO object in the constructor and add methods for operations such a CRUD. On Select-type operations, build a User object and return it. The class will resemble the typical "Model" classes you find in frameworks. This is (often) my preferred way to handle this.

    class User
    {
        // As normal
    }
    
    class UserModel
    {
    
        private $pdo;
    
        public function __constructor ( PDO $pdo )
        {
            $this->pdo = $pdo;
        }
    
        public function fetchById( $userId )
        {
            $result = // Perform PDO query and fetch to result:
          
            return new User( $result->username, .... ); // Create object
        }
    
    }
    

    2. Use a Factory:

    Create a factory method or a class. If all you need to do with an object is creating it (as is often the case) a factory method can be suitable:

    class User 
    {
    
        // vars
    
        private function __construct( $username, $realName, $accessLevel )
        {
            $this->username = $username;
            ....
        }
        
        public static function createById( PDO $pdo, $userId )
        {
            // use PDO to fetch user into $row....
            return new self($row->userName, $row->realName, $row->accessLevel);
        }
    }
    
    • Upvote 1
  4. 
    if ( validateEmployees ( $_POST['employees'] )
    {
       echo "All values are Integers greater than zero.";
    }
    else 
    {
       echo "Invalid data";
    } 
    
    function validateEmployees( array $employees )
    {
        if ( empty($eployees) ) { return false; }
        $filtered = array_filter($employees, 'isPositiveInteger');
        return $count($employees) === $count($filtered);
    }
    
    function isPositiveInteger($value)
    {
        return is_int((int)$value) and 0 < intval($value, 10);
    }
    

    Something like this could work. Play around with something similar until you get it right. Hope it helps.

  5. Jon: Very interesting. I've started using a scratch-card when I program, and any thoughts that pop up in my mind is written there instead of switching focus. I think our approach is much more similar than anyone of us could guess from the get go. I think you are correct in your assessment of TDD in general. Nothing is magic, and everything requires dedication and work, no matter which route you go.

     

    My conclusion when it comes to programming, is that simplicity is often the most important aspect. You should understand your code after two months away from it and be able to add functionality to it with ease. I have found that a really solid understanding of OOP have helped me understand better where parts of logic should belong.

     

    Let me know if you want any input on your session solution. I actually need one myself shortly, and would greatly consider using your solution.

     

    Matt: Thanks for the nice words, Matt. There's no denying you have become a good coders over the years. I have seen your progression here. A direct comparison of skill-sets rarely gives you the full picture, and you are definitely stronger than me and Jon in some regards.

     

    Regarding frameworks and MVC, I've kind of switched approach recently. I have found out that I have to make too many compromises in a framework, and my solutions don't always manifest themselves in the best way possible. This is especially true for the Models in MVC. I find they restrict me in the ways I write SQL normally. I have therefor started to create two layers of models in my code. One for database interaction and one for Domain specific logic. To give you an example, I prefer to create a Coupon class that encapsulates the logic for that real-world entity, and then create a simple Database models for returning those objects and make CRUD operations for me. I find too much logic gets placed in the wrong parts or that my logic gets too abstract if I rely 100% on a Framework.

     

    That very reason is also why I like Laravel. I can use their Auth system, Routing and Session implementation and rely on my own code elsewhere. I think that better encapsulates what I really want to do in my system. That's why I generally recommend composer too.

  6. I agree with you on almost every point. I also think you are a great coder, and there's no mistake you produce few bugs. The tests in questions are unit tests, yes. I don't really perform functional testing unless you count confirming behavior be looking at the output result.

     

    The statement regarding test quality versus code quality is spot on. Testing can absolutely give you a false sense of security, and that is why I focus more on the process of TDD than the actual unit tests themselves in my post. TDD helps me keep focused on a single class at a time, where I normally get scattered-brained and want to implement everything at once. I'm also a "feature-creaper", and produce way to much "nice-to-have"-functionality unless kept in a straight line. Because of the process, I can't really refactor large pieces of code at once, (and introduce errors in the process) but must walk the line on a tight rope. I've seen this so much in fellow programmers, that I believe TDD as process can help them out a lot. I'm really more of an artistic person than a highly logical one.

     

    Good tests are the core of TDD. I don't really write good test, or many tests for that matter. The point is never to produce a large amount of tests for me, but to write those tests that matter in real life. I want to make sure that vital parts of a class works as expected, and I want it to keep working the same way after I've been on a refactoring frenzy. The rules in TDD are also generally "one-assertion-per-method", but I prefer my highly expressive style of testing to other peoples preferences. As stated, TDD is a process for me. My deduction class should really assert on a valid percentage value and test for exceptions on illegal values, but I couldn't be bothered at the time...

     

    I've especially fallen in love with clear, expressive methods that is highly readable. When a piece of code makes sense even in queens English, I'm starting to become really happy with my code. This is also why I wanted to share the following piece of code. What started out as an ugly algorithm in a checkout class, magically transformed itself into a beautiful, reusable piece. It's used several places in my current project.

     

    I found you point about one-liners really interesting. I've read a lot about coding principles recently, and the SOLID principles really stuck with me. I especially find the single-responsibility principle extremely valuable. Due to that, my methods rarely does more than one thing neither. The next things that stuck with me are a lot of so called "coding smells". Especially "Large class", "Long method", and "long parameter list" stuck with me. All combined, have resulted in a lot simpler code split up into smaller classes, that are usually more geared towards their actual intention. My largest revelation was though when I read about primitive obsession. That connected a lot of dots between my Java background and my PHP experience. I've mainly gathered knowledge from books during the last year, but I recently stumbled upon a resource that provides short introductions to most of the earlier stated smells. I think you'll like it: http://sourcemaking.com/

     

    I too must apologize for a long post full of rambling. Your post opened the flood gates, I guess. Anyway. I really appreciate your long post and respect all your views to the fullest. As "nerds", we are often way to opinionated and religious about the "one, true way" to everything, and therefor I try to underline the subjectiveness of my statements clearly. Looking forward to reading any of your thoughts.

    • Upvote 1
  7. It's mostly related to test stubs and the nature most static methods are written. Static code is procedural by nature, and while that is not bad in itself, you cannot (easily, with a few exceptions) mock that. The point of OOP is to create modular classes with few hard dependencies, for re-usability and easy refactoring.

     

    A mock is basically a replica of object functionality. If your class expects an object implementing a Deductable interface, you can make a mock with the methods required. While that may seem illogical, you wouldn't be able to delete the class Deductor if your tests relies on it, but with a mock, the dependency is dissolved. I don't really think I explain that anywhere near good, but I hope I drove the point trough.  

     

    If those dependencies can't be mocked due to static methods, you'll have real problems testing what you really want to test. That will prevent you from easily introducing new functionality without affecting the classes AND tests tied to it. Static is therefor not bad in itself, but it will make things seriously harder if you want to use the process test-driven development. As a general rule, everything static is therefor advised against. Everything static is possible to write object-oriented, so that is why some programmers will disregard static methods or classes with a few exceptions.

     

    1. Factory methods. These are generally helper methods inside a class that builds the object for you.

    2. Facades and IOC-containers. (used by YII and Laravel) The facade class simply wraps object calls in a static programming interface for you and add any needed dependencies set in the constructor. This is for easy usage and prettier code than writen large setup instantiations with lots of object params. Behind the scenes of a YII call for Product::findById(1), the call is made using an object.

    3. Helper methods. Your typical Math class and helpers for sorting, filtering, etc.

     

    Most of the views might be a bit extreme, but they are issued by experienced programmers. The statements especially holds true in larger software and collaborating settings or where you need proof of correctly functioning programs. (Bugs in the medical section might be bad for example) While I don't tend to follow advice religiously, these are mostly established practices in the work sector here. I therefor try to stick to it for the sake of training.

     

    The counter-point to make is that all code might not need testing. That argument falls short if others depend on your software, which again gets me to composer. Due to small packages being tested, I don't need to write my own Money pattern object and risk bugs in sensitive areas of my code. The same level of security isn't needed for session management, but it frees my time to focus on what makes my project unique.

     

    You should also keep in mind that packages aren't necessarily a small framework in of itself. If you prefer small, focused classes - as I do too - you should consider publishing your session implementation on Packagist.com when you are done. ;)

     

    Sorry for the long post. Hope I drove some points home at least. There's plenty of resources on the web if you want a better explanation.

     

    Edit: To illustrate why I like testing a bit better, I will show you the test and domain code from my implementation of a deductor class. The tests both works as documentation, as you can easily follow what is done, and ensures I never break the behavior I expect here. This is vital as other parts of my system, such as my Coupon implementation, uses this class to deduct a coupon value for the checkout total.

    <?php namespace SpeedJumpers\Cart\Tests\Pricing;
    
    require dirname(__DIR__) . '../../vendor/autoload.php';
    
    /**
     * Description of DiscountTest
     *
     * @author Thomas Maurstad Larsson <thomas.m.larsson@gmail.com>
     * @version 0.1
     */
    
    use Money\Money;
    use SpeedJumpers\Cart\Pricing\Discount;
    
    class DiscountTest extends \PHPUnit_Framework_TestCase
    {
    
        /** @test **/
        public function discount()
        {
            $discount = new Discount(Money::USD(1000));
    
            $this->assertEquals(Money::USD(900), $discount->reduceByPercent(10), "Should return new amount with 10% deduction");
            $this->assertEquals(Money::USD(500), $discount->reduceByPercent(50), "Should return new amount with 50% deduction");
            $this->assertEquals(Money::USD(950), $discount->reduceByAmount(50), "Should return new amount with 50 cents in deduction");
        }
    
    }
    

    Here's the actual class:

    <?php namespace SpeedJumpers\Cart\Pricing;
    
    /**
     * Description of Discount
     *
     * @author Thomas Maurstad Larsson <thomas.m.larsson@gmail.com>
     * @version 0.1
     */
    
    use Money\Money;
    
    class Discount
    {
    
        private $base;
        
        /**
         * Public constructor
         * 
         * @param \Money\Money $money
         */
        
        public function __construct( Money $money )
        {
            $this->base = $money;
        }
        
        /**
         * Deduct the price by percentage
         * 
         * @param int $deductionPercent             The percent to deduct from the price
         * @return Money                            A Money object with new amount
         */
        
        public function reduceByPercent( $deductionPercent )
        {
            $this->assertPositiveInteger($deductionPercent);
            return Money::USD( $this->amount() - (( $this->amount() * (int) $deductionPercent) / 100) );
        }
        
        /**
         * Deduct the price by amount
         * 
         * @param int $amount                       The amount to deduct from price
         * @return Money                            A Money object with new amount
         */
        
        public function reduceByAmount( $deductionAmount )
        {
            $this->assertPositiveInteger($deductionAmount);
            return Money::USD($this->amount() - (int)$deductionAmount);
        }
    
        /**
         * Returns the amount as units from base
         * 
         * @return int              The amount
         */
        
        private function amount()
        {
            return $this->base->getAmount();
        }
        
        /**
         * Assert positive integer
         * 
         * @param type $int
         * @throws \InvalidArgumentException
         */
        
        private function assertPositiveInteger( $int )
        {
            if ( ! is_int( (int) $int) || intval($int, 10) === 0)
                throw new \InvalidArgumentException("Must be a positive integer over zero");
        }
    
    }
    

    And here the checkout expect the deductor to work on the total:

    class Checkout
    {
        ...
    
        /**
         * Apply a discount using a Coupon
         *
         * @param \SpeedJumpers\Cart\Pricing\Coupon $coupon
         */
    
        public function applyDiscountUsing( Coupon $voucher )
        {
            $deduction = new Discount($this->totalAmount);
    
            if ( $voucher->isAmountDeduction() )
                $deduction->reduceByAmount($voucher->value());
            else if ( $voucher->isPercentageDeduction() )
                $deduction->reduceByPercent($voucher->value());
            else if ( $voucher->isFreeShipping() )
                $deduction->reduceByAmount($this->shippingDestinationAmount());
    
            $this->subtractFromTotal($deduction);
        }
    
       ... 
    
    }
    

    I hope that kind of shows why testing can be very good.

  8. Jon: The general nature of a framework means it will most likely have more features than you need. You must also keep in mind that due to the composer based nature of the package, you will dynamically only load what you need. Laravel provides you with session management from anything from a database to memcache, but won't utilize the whole package in each go. I just think I should clarify that.

     

    Matt: Static is generally bad, unless you deal with pure helper classes or helper methods. Laravel and YII both lies a little bit to you in code appearance, as you are actually talking to a Facade class. While you seemingly call static methods all the way, everything are objects behind the scene. The main reason to not do static classes is testability. Code you can't test is often badly written by design.

  9. I think that a session class is an excellent candidate for using objects as it will encapsulate all the session handling in a convenient place.  We could all write one here in the forum.  Anyone who wants to contribute would be welcome and we all could use it!

     

    Any thoughts?

     

    I would recommend you to use something that already exists. Laravel is component based, and you can find components under the Illuminate namespace. Illuminate\Session will abstract and secure Session handling for you. You can find it on packagist.com and install it using composer. :)

    • Upvote 1
  10. Edit: Looks like I posted too soon.

     

    Seems like "Canada/Atlantic" is depricated [link]. The timezone might not be available. I'm pretty sure you should be able to find another one that fits you in the America section of the timezones: http://no2.php.net/manual/en/timezones.america.php

     

    As a general suggestion, you should also look out for exception:

    try {
        $dateTime = new DateTime("INVALID");
        echo $dateTime;
    }
    catch ( Exception $e ) // Error handling
    {
        echo "Invalid time";
    }

    You can solve this a couple of ways.

     

    1. Edit your php.ini file: (location depends on operating system, so search the web for common locations for you)

    - Find "date.timezone", (around line 1045 for me, but search for it) make sure it's set to "America/Anguilla" (or what your default may be) and make sure the line is not commented out. (";" - semi-colons creates a comment)

     

    2. Use date_default_timezone_set()

    - Has be called before you create a datetime object

    date_default_timezone_set("America/Anguilla")
    
  11. I know you didn't ask me, but I use Windows at my stationary at my dorm and a Mac for Travel/at home. The Windows machine runs Windows 8, and is a custom built beast of a gaming machine, while my Mac is a normal Air. I find it easy to switch between the two, but it has required some configuration. Especially the command line required a lot of aliasing, but I've set up a .bashrc on my windows machine to have Linux commands for whatever I do. That's really the biggest difference.

     

    As work tools, I've switched to NetBeans and Sublime from Eclipse recently. All are available for both Windows and Mac, as are Git tools for code repositories. I don't really think about it when I switch environment at all anymore. Normal every use differentiate the two very little. A little setup is required, but so would switching between two machines with identical operating system do. Keyboard layouts are of course different, but you won't really every think about what buttons to press after a week.

     

    My two cents.

  12. Are you getting error messages here? If so, please share them. By the looks of it, you should replace "INTO" with "AS" in your subquery, but I don't I don't know if that's your problem. It's most likely a syntax error though.

     

    You must obviously have data in both orders and order_contents for this to work.

    $query = "UPDATE orders SET 
       total = (SELECT SUM(quantity*price_per) AS subtotal FROM order_contents WHERE order_id = {$oid} + $shipping) 
       WHERE id = {$oid}
    ";

    Hope that helps you out. If not, we need some more info from you. :)

  13. Are you sure your Live server PHP version supports password_hash()? It ships with PHP 5.0.0, but won't be available in lower versions of PHP. You can check this by adding phpinfo(). If it doesn't exists, you'll need to upgrade PHP or switch hashing function.

     

    Edit: You can also check for errors by adding these lines to the top of your script:

    ini_set('display_errors', 1);
    ini_set('error_reporting', -1);
  14. Glad you take it that way Jon and Matt. As a non-native to English, the sublities in communication is harder for me textually. No need for an apology to me. :)

     

    It looks like we still have a communication breakdown though. I'm not talking about coding in reference to interfaces, but to the graphical UI that drives the data flow around. Does that make more sense?

  15. That's why I pointed out it might be an interface issue rather than a programming issue at that. I also don't know Matt's programming skills and how you guys split the work-load. I'll just underline I'm not trying to insult anyone. Dismiss my advice if it's not appropriate/needed.

     

    Nice to hear it's going fine programming-wise though!

     

    To explain further, have you thought about separate interfaces and/or forms for managing stations? Instead of both adding and deleting stations in one fell-swoop, you might benefit from dividing the two operations. That might also be a easier mental model to understand for your users, and would be simpler to program.

     

    I don't try to insult you, or step on any toes, by giving very basic advice. However, without any specific details to work with, I get the feeling you might have overlooked some UI design and data flow that may simplify your application code. This is why I pointed to Interaction Design as a process that will help you in that regard. Non of us are really designers when push comes to show. (Hope I use that correctly)

  16. I think that too sounds like a design issue, either in the user interface form designs or in the database. Could you possibly explain your problems a little more in detail?

     

    The best thing you can do is to make sure your related inserts/updated/deletes are done as a single operation. You can do this by concatenating Strings into a single query or imploding an array and combining inserts and select queries. (Look at WHERE key IN (a, b, c)

     

    To make sure everything works as expected, you should go with transactions. With the right level of modularity and high-level abstractions, the code should be very easy to follow. The key here is to go down the model route in MVC, even if you don't actually apply the pattern elsewhere. Calling bool updateUserStations( $userId, array $keys ) that wraps transaction handling, calls deleteRemovedStationsFromUser( $id, $keys['delete']), insertNewUserStations( $userId, $keys['insert'] ) and makeShiftCleanup() will make sure you can develop things in small steps and make sure it all works. Even if I don't go down the MVC route, I always write query functions instead of mixing DB and logic in the scrips themselves.

  17. Make sure you don't feature-creep your project. "Nice-to-have"s easily becomes "might-be-useful-some-day"s. Start out by gathering good requirements and make a solid plan with good milestones for development. Start out bare-bones and add the basic functionality first so you can quickly view some result, then refactor your code and add nice-to-haves later. It's very easy to become distracted and hung-up in specifics along the way.

     

    Besides that, I don't really feel I can contribute in a meaningful way. :)

  18. Matt: I think you should read a little bit about interaction design. It will give you some tools and a process for finding the best possible UI design. I've very successfully used human-computer interaction to design interfaces for a car retailer system before. If you have the money, you could of course hire someone to do the job for you. Bad cognitive models in a UI is often a reason system don't get used, no matter how good they are.

     

    As for my suggestion, I was actually thinking of a adding a single, toggle-able button on each station and sorting the rows into groups of "selected" and "not selected" stations. A click on the button would insert/remove that specific station with AJAX immediately. Think of the "Like"-button on Facebok as an example.

    The fallback for non-JS here is sing GET with the user_id, train_line_id and station_id on the buttons. (which are really links)

     

    If this is a problem with things taking too long, I would look at implementing a job queue with workers running in the background.

  19. I think most of the complexity here is related specifically to the checkbox design. If you changed the approach to something like toggled buttons with "Would work at" / "Not interested" and updating the list using AJAX, the design would be dead simple. While DB performance is important, this is not really expensive operations to perform. A series of small inserts/deletes might also work faster than a larger transaction. Due to a much simpler design, I would prefer this solution myself. (And have done in the past)

     

    The array solution should also be viable. Unless we are talking tens of thousands of stations, you'll most likely not experience any huge problems. Try to develop a small test to see how long the computation takes. My bet is that it'll not really be a bottleneck.

×
×
  • Create New...