Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
I am brand new at php, so I know I'm doing something stupid, but I figured asking here would clear it right up. (This is a school assignment) I have a form, it has several fields and button to click to submit, which then it is supposed to render a small table in html. I know how to render the table, and I know that I need to use isset to check that the form has been submitted. The issue is that when I put the if( isset($_POST['submit'])){} block in, the form no longer displays at all. Which means I cant ever click the button. I don't understand why, in general, errors in the php block prevent any of the html from rendering on the page.

Any general pointers you guys can give me?

edit: fixed the main problem.

Adbot
ADBOT LOVES YOU

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
I'm not an authority on this, but the general gist of PHP execution is:
1. Compile the script files. If there is a parse error (you wrote crap, or missed a semi-colon) then compiling will not complete. This will result in a single error.
2. Execute the compiled script. The script runs top-to-bottom, and if you encounter a fatal error at run-time, the remainder of the script will not execute.

Parse error example:
http://codepad.viper-7.com/MYnJgE
Note that the html before the PHP tag is never displayed because the script never gets to the execution stage.

Runtime execution error:
http://codepad.viper-7.com/w29Z90
Notice how the script starts to run, but when it encounters a fatal error the rest is abandoned.

If you're not getting anything on the page when you encounter an error (white screen of death) then try viewing the source of the page, in case your error is getting encpsulated in partial HTML.
If there's no errors (or no source at all), then you probably don't have error reporting turned on correctly. If this is the case, Turn on PHP error reporting.

Other things that can help you mess up less frequently is a good IDE. Anything that can at least syntax highlight PHP is a start, but a lot of people here prefer using PhpStorm, NetBeans or similar.
Try out the PhpStorm EAP for free, for a limited time. It's pretty easy to get up and running, and gives you some professional-level hand-holding. Don't feel you need to configure all the bells and whistles, simply use it as a replacement for notepad or whatever it is you might be using.

substitute
Aug 30, 2003

you for my mum

Snak posted:

I am brand new at php, so I know I'm doing something stupid, but I figured asking here would clear it right up. (This is a school assignment) I have a form, it has several fields and button to click to submit, which then it is supposed to render a small table in html. I know how to render the table, and I know that I need to use isset to check that the form has been submitted. The issue is that when I put the if( isset($_POST['submit'])){} block in, the form no longer displays at all. Which means I cant ever click the button. I don't understand why, in general, errors in the php block prevent any of the html from rendering on the page.

Any general pointers you guys can give me?

edit: fixed the main problem.

Here's a general tip, code linting.

Example:
https://www.sublimelinter.com/

Use Sublime Text as your editor, and the plugin/extension above for real-time, in-editor linting. You'll hopefully never (rarely) miss a semi-colon, or whatever-the-hell might kill your script's execution, again.

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
I'm trying to get Doctrine to do something it wasn't designed to do; UNION queries.

Due to architecture, our system fires an event off which collects a bunch of Doctrine\ORM\Query objects from various parts of the system. Each of these has uniquely named parameters and the same column names, so there's no conflicts or anything like that.

I want to convert all of these Doctrine\ORM\Query objects to SQL, so I can join them together with the word UNION and then stuff them inside a really simple Doctrine\ORM\NativeQuery object. I want to then just attached the named parameters to the NativeQuery and run the thing. Simple, right?

My problem is that Doctrine\ORM\Query->getSql() converts the named parameters into position-based parameters (eg. ":derp" becomes "?"), and this is true for re-used parameters like :user, which appear multiple times in one DQL query.
There's absolutely no way I can see to get the parameter mapping out of Doctrine's parser so I can convert my named parameters into a numeric array that matches that's in the SQL returned. There's also no way to have my parameters mapped to those of the SQL query, outside of actually executing the query.

As a result I'm forced to use non-named parameters in my DQL, and hope that the order of params to queries doesn't get screwed up.

Does anyone have any thoughts on this? It's driving me mad that Doctrine doesn't have a reliable mechanism to go from DQL+params to SQL+params, ideally persisting the named parameters, whileit's designed to go from SQL to DQL without a problem, and execute native SQL using NativeQuery. It feels like a massive oversight that it can't do this.

musclecoder
Oct 23, 2006

I'm all about meeting girls. I'm all about meeting guys.
Can you write your raw SQL using the UNION and then use Doctrine's ResultSetMapping to map the results to an entity? For example, I use PostgreSQL's full-text search which doesn't work great with Doctrine, so I'll write the SQL natively and then map the results to the entity I am searching:

php:
<?php

use Doctrine\ORM\Query\ResultSetMapping;

$sql "
    SELECT i.* FROM item i
    WHERE i.organization_id = :organizationId
        AND ((plainto_tsquery(:query) @@ i.description_search = 't')
            OR LOWER(i.part_number) = LOWER(:query))
";

$rsm = new ResultSetMapping;
$rsm->addEntityResult('ExampleAppBundle:Item''i');
$rsm->addFieldResult('i''id''id');
$rsm->addFieldResult('i''job_type''jobType');
// ...
$rsm->addFieldResult('i''part_number''partNumber');
$rsm->addFieldResult('i''description''description');
$rsm->addFieldResult('i''price''price');
// ...

$items $this->getEntityManager()
    ->createNativeQuery($sql$rsm)
    ->setParameter('organizationId'$this->organization->getId())
    ->setParameter('query'$query)
    ->getResult();

If that doesn't work, can you get rid of the UNION, execute two queries, and just join the ArrayCollection (or array) results?

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
That's actually really helpful because handing the ResultSetMapping was my next step in all this, so thanks for that :)

Unfortunately I can't run separate queries and then merge the results because this data is huge and requires pagination, filtering and sorting. This is an aggregate of several different kinds of records which have some common fields. Think about it like JIRA issues across projects, but each project uses a different entity entirely. Not my architecture.

In effect the structure of the query has to be:
code:
SELECT * FROM (
    SELECT a,b,c FROM ThingOne WHERE d = 1
    UNION
    SELECT x,y,z FROM ThingTwo WHERE w = 1
) myquery
ORDER BY x
LIMIT 10, 10
Because of the way the system works, I'm using an Event which expects interested parties to return a query which becomes part of the Union. The Event supplies the list of fields that must be returned, so it's pretty robust in terms of authoring the individual queries. I wanted to make this as flexible as possible for everyone else who might need to add to it in the future, so I wanted to standardise the query type my Union code is expecting as the Doctrine\ORM\Query object. I figured this way people could build the queries however they wanted (NativeQuery or ideally DQL, which is our system standard) and then I could use getSql() and Union them..

But no, Doctrine's output from getSql() rewrites the parameters and doesn't supply any usable mapping, or a way to access the mapping generated in the parser.
php:
<?
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('u AS user')->from('User', 'u')->where('u.id = :user or u.manager = :user')->setParameter('user', $user);
$query = $qb->getQuery(); // this is what I want to pass to my Union

echo $query->getSql();
// Output is similar to:
// SELECT e0_.* FROM User e0_ WHERE e0_.id = ? OR e0_.manager_id = ?
?>
In the above, $query doesn't allow me access to it's internal parseResult in order to use the new mappings of it's parameters, and the parameters from $query are obviously still named parameters. Don't even get me started on the way the SELECT column alias works.
I don't think this is wrong of the Query object in itself - these things should be private and I shouldn't care about them, but using getSql() i'm only able to get back half the recipe for my cake.

Now I can work around this by forcing everyone to use non-named parameters when building their queries, but the ordering becomes so loose I'm no longer confident in it. Perhaps this is just me being too cautious.
The other alternative is to force the use of NativeQuery, where getSql() doesn't perform any parsing, but seeing as everyone will want to author using DQL anyway, they'll only encounter the exact same problem I did every time they go to use it, so I don't feel that's a viable way to go.

Now I'm done complaining about it, what's the opinion on a function that, rather than the obviously-only-for-debug Doctrine\ORM\Query::getSql(), was instead something like Doctrine\ORM\Query::getNativeQuery which returned a NativeQuery object containing the appropriately mapped parameters and column aliases (where supplied)? I'm not adverse to adding this to Doctrine myself, but I was just confused and astounded that this kind of facility didn't exist already, seeing as pumping out native queries is its number one job.

Sepist
Dec 26, 2005

FUCK BITCHES, ROUTE PACKETS

Gravy Boat 2k
Am I missing something obvious here? I'm getting an undefined offset error when trying to store the first result in a variable:

code:
<?php
$playerprofile = simplexml_load_file("http://developer.sportsdatallc.com/files/nba_v3_player_profile_example.xml");
$playername2 = $playerprofile->xpath("//player/@full_name")[0];
$avgpoints = $playerprofile->xpath("//average/@points")[0];
				?>

revmoo
May 25, 2006

#basta
Because your xpath selectors don't match the content being returned from the remote server.

lunar detritus
May 6, 2009


KARMA! posted:

Biggest problem here is not so much the logic, but the messy layout. I reduced some redundancy and am judicous with whitespace to make it less cluttered:

php:
<?
Code
?>
It's never going to be perfect (forms have a way of doing that) but at least it's a bit easier to read.

Thanks! That helped a lot for refactoring how the controller displays the form.

Now I'm trying to refactor the saving process. Each form saves to /orders/save/FORM/ORDER_ID so every action is processed inside a method called 'save' and an if decides what post info to recover and what actions to take. There's about 15 stages, and each has from 5 to 50 values, so the controller is huge. And depending of what was sent emails are sent, stages are changed, etc. Everything in one file. And the thing doesn't even validate server-side.

I wouldn't care if it worked but it has bugs and it has lost some information when saving (once it overwrote the entire database) so I need to a) fix those bugs and b) make it maintainable. Any ideas?

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
The obvious answer is "split that poo poo up". You didn't provide too much info about the structure, but this can usually be applied one way or another to anything over 100 lines of code.
Providing you can compartmentalise each "type" of request, and there's not too much spaghetti code that reaches into god-knows-what part of a condition elsewhere in same code, you could create a series of "handler" classes to process each of your requests.

php:
<?
abstract class AbstractMyHandler
{
    const TYPE = '';
    
    public function getType()
    {
        return static::TYPE;
    }

    public abstract function handleRequest($request);
}

class MyHandlerFood extends AbstractMyHandler
{
    const TYPE = 'food';
    
    public function handleRequest($request)
    {
        $id = $request->get('food_id');
        // TODO: crappy logic
       return new JsonResponse();
    }
}

class MyController 
{
    protected $types = [];

    public __construct() 
    {
        $types[] = new MyHandlerFood();
        $types[] = new MyHandlerPlanes();
    }

    protected function findHandlerByType($type) 
    {
        foreach($this->types as $type) {
            if($type->getType() == $type) {
                return $type;
            }
        }

        throw new \InvalidArgumentException('Type specified does not exist');
    }

    public function saveAction($request)
    {
        $type = $request->get('type');
        $handler = $this->findHandlerByType($type);
        return $handler->handleRequest($request);
    }
}

?>
That's a really basic key-lookup on a series of classes. You can easily add a new one by just throwing it into the array and following the same AbstractMyClass setup, and no other parts of the code need to change.
If you need more complicated logic, you could run tests on your incoming $request data, and call a function on each class like "canHandleRequest()". These functions could run some basic pattern-matching on the inbound data and return true/false, and you execute whichever handler returns true.
If your data is really weakly structured, you could set a priority on each handler, or return a "matched weight" from each canHandleRequest call, and you pick whichever is most suitable.

Separate your code. Use common interfaces. Don't be afraid to make a bunch of new classes.

I haven't mentioned anything about dependency injection in the above, I'm just instantiating classes is a really lame manner. You could easily apply DI to the above, and if your current curmudgeon uses a lot of common services (email, db, whatever) they should be services, and you should be including them by DI into each MyHandler class you use.
If you're doing it right, you can also inject only what each MyHandler class needs.

lunar detritus
May 6, 2009


v1nce posted:

The obvious answer is "split that poo poo up". You didn't provide too much info about the structure, but this can usually be applied one way or another to anything over 100 lines of code. [...]
Separate your code. Use common interfaces. Don't be afraid to make a bunch of new classes.

Thanks, your example helps a lot.

Here's an example of the current structure for saving:

php:
<?php
        if ($form == 'measurement'):
            $suborder['in_charge'] = explode('|'$suborder['in_charge']);
            foreach ($suborder['in_charge'] as $key => $value) {
                if ($value == $this->ion_auth->user()->row()->id || $value == $suborder['analyst']):
                    unset($suborder['in_charge'][$key]);
                endif;
            }
            $suborder['in_charge'][] = $suborder['analyst'];
            $data['in_charge'] = implode('|'$suborder['in_charge']);

            $data['measurement_resolution'] = $this->input->post('measurement_resolution');
            $data['measurement_terrain_instalation'] = ($this->input->post('measurement_terrain_instalation_hidden')) ? date('Y-m-d H:i'strtotime($this->input->post('measurement_terrain_instalation_hidden'))) : '';
            $data['measurement_costs'] = preg_replace("#[[:punct:]]#"""$this->input->post('measurement_costs'));

            $docs_measurement_indoor $this->input->post('docs_measurement_indoor');
            $docs_measurement_outdoor $this->input->post('docs_measurement_outdoor');
            if ($docs_measurement_indoor$this->documentos_model->save($docs_measurement_indoor$order_id'docs_measurement_indoor');
            if ($docs_measurement_outdoor$this->documentos_model->save($docs_measurement_outdoor$order_id'docs_measurement_outdoor');
            if(!$this->ion_auth->in_group(1)):
                $data['stage'] = $this->orders_model->set_stage($order_id'analysis-wait');
                $this->messages->send(['id' => $order_id'template' => 'respuesta-analysis''cargo' => 'Quality Measurement']);
            endif;
        endif;

        if ($form == 'factibility_transmission'):
            $suborder['in_charge'] = explode('|'$suborder['in_charge']);
            foreach ($suborder['in_charge'] as $key => $value) {
                if ($value == $this->ion_auth->user()->row()->id || $value == $suborder['analyst']):
                    unset($suborder['in_charge'][$key]);
                endif;
            }
            $suborder['in_charge'][] = $suborder['analyst'];
            $data['factibility_topology'] = $this->input->post('factibility_topology');
            $data['factibility_costs'] = preg_replace("#[[:punct:]]#"""$this->input->post('factibility_costs'));
            $data['in_charge'] = implode('|'$suborder['in_charge']);
            $proposal_engineering_indoor $this->input->post('proposal_engineering_indoor');
            $proposal_engineering_outdoor $this->input->post('proposal_engineering_outdoor');
            if ($proposal_engineering_indoor$this->documentos_model->save($proposal_engineering_indoor$order_id'proposal_engineering_indoor');
            if ($proposal_engineering_outdoor$this->documentos_model->save($proposal_engineering_outdoor$order_id'proposal_engineering_outdoor');
            if(!$this->ion_auth->in_group(1)):
                $data['stage'] = $this->orders_model->set_stage($order_id'analysis-wait');
                $this->messages->send(['id' => $order_id'template' => 'respuesta-analysis''cargo' => 'Ingenieria de Conectividad de Tx']);
            endif;
        endif;

      

        if ($data):
            if ($this->suborders_model->actualizar(['id' => $id'data' => $data])):
                $this->session->set_flashdata('message''Event has been successfully saved.');
                if (@$noredirect):
                    redirect($_SERVER['HTTP_REFERER'], 'refresh');
                else:
                    redirect(base_url('orders'), 'refresh');
                endif;
                return true;
            endif;
            $this->session->set_flashdata('message''There has been a problem while saving, please try again.');
            redirect($_SERVER['HTTP_REFERER'], 'refresh');
        endif;
        return false;

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
Well, I absolutely hate the layout of that code, lack of comments, use of if/endif, reliance on arrays, etc, etc.. but you could basically do what I said above, with something like this.
Note: completely un-tested.

AbstractMyHandler
Defines a common class/interface everything is based on.
php:
<?
abstract class AbstractMyHandler
{
    /** @const string */
    const ID = null;

    /** @var IonAuth */ 
    protected $ion_auth;

    /** @var OrdersModel */
    protected $orders_model;

    /** @var Messages */
    protected $messages;

    /** @var input */
    protected $input;

    /** @var DocumentosModel */
    protected $documentos_model;

    /**
     * Dependency Injection
     * @param IonAuth $ionAuth
     * @param OrdersModel $ordersModel
     * @param DocumentosModel $documentosModel
     * @param Messages $messages
     * @param Input $input
     */
    public function __construct(IonAuth $ionAuth, OrdersModel $ordersModel, Messages $messages, Input $input, DocumentosModel $documentosModel)
    {
        $this->ionAuth = $ionAuth;
        $this->ordersModel = $ordersModel;
        $this->messages = $messages;
        $this->input = $input;
        $this->documentosModel = $documentosModel;
    }

    /**
     * Get the ID of this handler
     * @return string
     */
    public static function getId()
    {
        return static::ID;
    }

    /**
     * Handle the request
     * @param int $orderId
     * @param array $data
     * @return array
     */
    public abstract function handleRequest($orderId, array $data);
}
?>
MyHandlerMeasurement
This is the actual handler for the request and does the unique legwork for each payload.
php:
<?
// This is the class you make copies of and modify for each payload type
class MyHandlerMeasurement extends AbstractMyHandler
{
    const ID = 'measurement';

    /**
     * Handle the request
     * @param int $orderId
     * @param array $data
     * @return array
     */    
    public function handleRequest($orderId, array $suborder) 
    {
        // Explode serialised suborder
        $suborder['in_charge'] = explode('|', $suborder['in_charge']);

        // Remove in_charge if current user or analyst?
        foreach ($suborder['in_charge'] as $key => $value) {
            if ($value == $this->ion_auth->user()->row()->id || $value == $suborder['analyst']) {
                unset($suborder['in_charge'][$key]);
            }
        }

        //Add analyst and re-serialise data
        $suborder['in_charge'][] = $suborder['analyst'];
        $data['in_charge'] = implode('|', $suborder['in_charge']);

        // Fetch measurement data from input
        $data['measurement_resolution'] = $this->input->post('measurement_resolution');
        $data['measurement_terrain_instalation'] = ($this->input->post('measurement_terrain_instalation_hidden')) ? date('Y-m-d H:i', strtotime($this->input->post('measurement_terrain_instalation_hidden'))) : '';
        $data['measurement_costs'] = preg_replace("#[[:punct:]]#", "", $this->input->post('measurement_costs'));

        // Save if indoor
        $docs_measurement_indoor = $this->input->post('docs_measurement_indoor');
        if ($docs_measurement_indoor) {
            $this->documentos_model->save($docs_measurement_indoor, $order_id, 'docs_measurement_indoor');
        }

        // Save if outdoor
        $docs_measurement_outdoor = $this->input->post('docs_measurement_outdoor');
        if ($docs_measurement_outdoor) {
            $this->documentos_model->save($docs_measurement_outdoor, $order_id, 'docs_measurement_outdoor');
        }

        // If not group 1(?)
        if(!$this->ion_auth->in_group(1)) {

            // Set to awaiting analysis
            $data['stage'] = $this->orders_model->set_stage($order_id, 'analysis-wait');

            // Dispatch notification
            $this->messages->send([
                'id' => $orderId, 
                'template' => 'respuesta-analysis', 
                'cargo' => 'Quality Measurement'
            ]);
        }

        return $data;
    }
}
?>
MyHandlerService
This is a special service which looks for and instantiates each handler type, depending on what you're looking for.
This is intended for re-use, so you can use it in multiple controllers if appropriate.
php:
<?
class MyHandlerService
{
    // This is where you add the names of each class that is a handler
    protected $handlers = [
        'MyHandlerMeasurement',
        'MyHandlerFactibilityTransmission',
    ];

    /** @var IonAuth */ 
    protected $ion_auth;

    /** @var OrdersModel */
    protected $orders_model;

    /** @var Messages */
    protected $messages;

    /** @var input */
    protected $input;

    /** @var DocumentosModel */
    protected $documentos_model;

    /**
     * Dependency Injection
     * @param IonAuth $ionAuth
     * @param OrdersModel $ordersModel
     * @param Messages $messages
     * @param Input $input
     */
    public function __construct(IonAuth $ionAuth, OrdersModel $ordersModel, DocumentosModel $documentosModel, Messages $messages, Input $input)
    {
        $this->ionAuth = $ionAuth;
        $this->ordersModel = $ordersModel;
        $this->documentosModel = $documentosModel;
        $this->messages = $messages;
        $this->input = $input;
    }

    /**
     * Find an appropriate handler by ID
     * @param int $id
     */
    public function getHandlerById($id)
    {
        // Locate handler
        forEach($this->handlers as $handler) {
            if($handler::getId() == $id) {
                // Create instance and pass dependencies
                $instance = new $handler($ionAuth, $ordersModel, $messages, $input);
                return $instance;
            }
        }
        throw new \InvalidArgumentException('Handler could not be found.');
    }
}

?>
Your Controller
php:
<?
class YourController
{
    public function OurCrappyApiAction()
    {
        // Determine redirect target
        $redirectTarget = base_url('orders');
        if (isset($noredirect) && $noredirect) {
            $redirectTarget = $_SERVER['HTTP_REFERER'];
        }

        // TODO: Missing poo poo
        $id = $this->MagicCodeYouDidntInclude->getId();
        $order_id = $this->MagicCodeYouDidntInclude->getOrder();
        $suborder = $this->MagicCodeYouDidntInclude->getSubOrder();
        $form = $this->MagicCodeYouDidntInclude->getSubOrder();
 
        // Create service instance
        $handlerService = new MyHandlerService($this->ion_auth, $this->orders_model, $this->documentos_model, $this->messages, $this->input);
 
        // Locate appropriate handler
        try {
            $requestHandler = $handerService->getHandlerById($form);
        } catch(\InvalidArgumentException $e) {
            // Graceful failure on bad datatype
            $this->session->set_flashdata('message', 'Invalid form type provided. Please try again.');
            redirect($redirectTarget, 'refresh');
        }
     
        // Delegate request to handler
        $data = $requestHandler->handleRequest($order_id, $suborder);

        // Data returned expected type
        if (isset($data) && is_array($data)) {
            // Save data
            if ($this->suborders_model->actualizar(['id' => $id, 'data' => $data])) {

                // Success message
                $this->session->set_flashdata('message', 'Event has been successfully saved.');

                // Redirect
                redirect($redirectTarget, 'refresh');
                return true;
            }
        }

        // Failure case
        $this->session->set_flashdata('message', 'There has been a problem while saving, please try again.');
        redirect($redirectTarget, 'refresh');
        return false;
    }
}
?>
This is the least amount of code I could write that lets you copy+paste your current controller methods into individual classes.

I've assumed that ALL your methods use, and only use, those select few services I've pushed through the constructor dependency injection. This code is very rigid in that the dependencies are explicitly passed, first from the Controller to MyHandlerService, and then from MyHandlerService to the instance of MyHandler which processes the request. It doesn't allow your individual MyHandler classes to have their own custom dependencies, which is probably going to be a problem further down the line.

The only reason I've written such a lovely DI example, is because I know nothing about your architecture and how you could make DI work in your system. If your system doesn't have DI, take a minute to look at some DI systems like PHP-DI.
This would then make your controller look more like:
php:
<?
$handlerService = $this->container->get('MyHandlerService');
$requestHandler = $handerService->getHandlerById($form);
?>
And your service could be more like:
php:
<?
if($handler::getId() == $id) {
    // Create instance and pass dependencies
    $instance = $this->container->get('YourControllerHandlers.'.$handler);
    return $instance;
}
?>
And that way you just define your handlers like this in PHP-DI, giving them their own dependency fulfillment:
php:
<?
return [

    // MyHandlerService
    'MyHandlerService' => DI\factory(function (Container $c) {
        // Just inject the Container itself to your service, so it can instantiate the handlers specified below:
        return new MyHandlerService($c); 
    }),

    // MyHandlerMeasurement
    'YourControllerHandlers.MyHandlerMeasurement ' => DI\object()
        ->constructor(DI\link('IonAuth'), DI\link('OrdersModel'), DI\link('Messages'), DI\link('Input'), DI\link('DocumentosModel')),

    // MyHandlerWhateverTheHell
    'YourControllerHandlers.MyHandlerWhateverTheHell ' => DI\object()
        ->constructor(DI\link('IonAuth'), DI\link('OrdersModel'), DI\link('Messages'), DI\link('Input'), DI\link('DocumentosModel'), DI\link('SomeOtherCrappyCode')),

    // MyHandlerEtc...
];
?>
There's always a chance you can't make DI links to "messages" or "ordersModel" or "IonAuth", if for instance they're instantiated by Controller and rely on some rear end-backwards linkage that you can't get into the DI.
To get around that, you can always use post-constructor DI. This is less recommanded, as it's only supposed to be used for serivces which are optional (and yours are not optional), and every class will need to have this item injected, as they're fulfilled in the Controller, and the controller isn't supposed to know what handler it's using (you could do Instanceof checks on the class, but that's no better than the way the old code worked).

php:
<?
abstract class AbstractMyHandler
{
    protected $messages;
    public function setMessages($messages)
    {
        $this->messages = $messages;
    }
}

class YourController
{
    public function theAction()
    {
        $handler = $handlerService->getHandlerById($id);
        $handler->setMessages($this->messages);
    }
}
?>

v1nce fucked around with this message at 03:20 on Feb 14, 2015

lunar detritus
May 6, 2009


v1nce posted:

Well, I absolutely hate the layout of that code, lack of comments, use of if/endif, reliance on arrays, etc, etc.. but you could basically do what I said above, with something like this.
Note: completely un-tested.

drat, you're awesome. You have no idea how much that helps, I've been completely overwhelmed by this sea of ifs.

I'm not sure what info I could tell you about the form's architecture besides that it's made with CodeIgniter.

Sepist
Dec 26, 2005

FUCK BITCHES, ROUTE PACKETS

Gravy Boat 2k
Hey goons, I have a SA-Mart post up to buy a php/sql script - check it out if any of you are interested in a quick $75 bux : http://forums.somethingawful.com/showthread.php?threadid=3703043

revmoo
May 25, 2006

#basta
I'm updating our site to php 5.5 and $_SERVER['HTTP_CLIENT_IP'] is null now. I don't see anything in the docs about this being removed, any ideas on what happened?

EDIT: Doh! Nevermind, it just has a different error reporting level and it's exposing bugs that I didn't know about.

revmoo fucked around with this message at 16:33 on Feb 27, 2015

Count Thrashula
Jun 1, 2003

Death is nothing compared to vindication.
Buglord
I've been out of the PHP loop for years, and I'm curious what the current "darling" of the framework community is.

Based on lists written last year, Laravel seems head and shoulders above the rest, and the "what a lot of us currently use: CodeIgniter" is from 2008.

Is Laravel the current go-to? Or are there different flavors for different uses?

Impotence
Nov 8, 2010
Lipstick Apathy
Well, what are you making?

Laravel is a great catchall, but many things don't absolutely require a framework or would be better served with some microframework.
While I dislike the enterpriseness of using Symfony2 for example, I rather enjoy http://silex.sensiolabs.org

Some things don't even need frameworks, and would be less complicated and better served with a composer autoload alone.

McGlockenshire
Dec 16, 2005

GOLLOCKS!
Laravel is indeed the current trendy one, but Symfony2 really is pretty much the best one out there, despite how complicated it can get. Thankfully, through the magic of composer and company, you can choose to only pull in the component or two that you need. The "HTTP kernel" Symfony uses is easy to build on top of, and the Friends of Symfony bundles can make throwing together trivial applications pretty easy.

I'll also vote for Silex, though if you just need a small front controller, consider klein or building your own with FastRoute.

McGlockenshire fucked around with this message at 08:24 on Mar 1, 2015

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
The guys above are pretty on target with "what are you making".

If you want to make an enterprise-y massive-huge application then I'd be recommending Symfony2, but the problem with that - speaking as someone who uses it daily - is it required quite a bit of internal knowledge and a willingness to dig real hard into the guts when things don't work correctly. This is rare, but it does mean the difference between a day of progress and a day wasted.
Silex looks super-sweet for tiny applications where you don't want to gently caress about too much or spend weeks getting the base application setup perfect. Throw poo poo together without too much concern, dump a tiny website.
Laravel is most definitely a good middle ground - good tutorials, very fast to get up and running, not too complex and easy to get clarity when you have problems.

You didn't state too much about what you've missed or where you're coming from, but most definitely try to use all the new tools to your advantage; stuff like git, composer, a good IDE, vagrant, etc.
As tempting as it is to download a zip file and just start butchering code, if you use the correct tools then your experience will be a lot less like trying to do wood carvings with your bare hands, and more like.. well, you know, using tools.

Count Thrashula
Jun 1, 2003

Death is nothing compared to vindication.
Buglord
Good point. It'll be a small project, with just a handful of pages, basic authentication, and probably a MySQL backend for some basic data. Laravel has good documentation on getting a Vagrant box up and running, but so far Vagrant seems very "black box"ish to me. I don't know how it does stuff, it just does. If it's easy enough to build a Vagrant box for Silex or something like that, I might go that route.

Thanks for the pointers!

spacebard
Jan 1, 2007

Football~

COOL CORN posted:

Good point. It'll be a small project, with just a handful of pages, basic authentication, and probably a MySQL backend for some basic data. Laravel has good documentation on getting a Vagrant box up and running, but so far Vagrant seems very "black box"ish to me. I don't know how it does stuff, it just does. If it's easy enough to build a Vagrant box for Silex or something like that, I might go that route.

Thanks for the pointers!

You can also try out PuPHPet which is a web site to configure a Vagrant VM specifically for PHP applications.

Count Thrashula
Jun 1, 2003

Death is nothing compared to vindication.
Buglord

spacebard posted:

You can also try out PuPHPet which is a web site to configure a Vagrant VM specifically for PHP applications.

WHOA, that's perfect. Thank you!

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
PHP newbie here (again?)

I have a PHP script that queries an SQL database and displays the results in an html table on the same page. By default, when the page refreshes, the search field will be blank again. I wanted it to be automatically filled with the last search parameter.

I implemented that like this:
code:
Search: <input type="text" name="query_string"
	<? if(isset($_POST['submit'])){
		$query = $_POST['query_string'];
	echo "value=$query";
	?>
	/>
And this seemed to work fine, so I thought I had figured it out and done it an acceptable way. As I was continuing with my project, I noticed some strange behavior. At some point I accidentally entered a '/' character as the only input to the field. This of course returned no results, so I deleted it and clicked submit again. It correctly entered nothing as the query string, but then the / reappeared in the field. At first I thought this was some behavior as a result of the most recent string being empty, so I entered several other query strings, all of which functioned correctly. But any time I enter an empty string, the / reappears, no matter how many others values I've entered. Can anyone explain to me what is going on? And how can I fix it?

Impotence
Nov 8, 2010
Lipstick Apathy
php:
<?
echo "value='" . htmlspecialchars($query) . "'";
?>
1) you're not quoting your value, which is not really going to work for anything more than a one-word alphabetical, and since you're using />, it effectively becomes value= />, since the _POST is actually sent, you're not checking whether it's !empty()
2) try entering ><script>alert('lol')

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer

Biowarfare posted:

php:
<?
echo "value='" . htmlspecialchars($query) . "'";
?>
1) you're not quoting your value, which is not really going to work for anything more than a one-word alphabetical, and since you're using />, it effectively becomes value= />, since the _POST is actually sent, you're not checking whether it's !empty()
2) try entering ><script>alert('lol')

That makes perfect sense. I'm basically learning html, php, and sql all at once, so there's a lot of syntactical details i'm still getting the hang of. This is not the first time I have mistakenly thought that a string variable would be interpreted the same way "foo" would be. But this doesn't really work that way, does it, because the value of $query just gets pasted right in there. I used htmlspecialchars before I put the string in the actually sql statement, I just didn't think I would need it here, because I didn't think it was "doing" anything besides putting the same values back in the field, but again, that's not the way this code is actually interpreted.

Thanks.

Impotence
Nov 8, 2010
Lipstick Apathy

quote:

I used htmlspecialchars before I put the string in the actually sql statement

Can you paste this part? Also, make sure you are not using any functions that start with mysql.

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
Sure:
code:
$result = pg_prepare($conn, "country_lookup", "SELECT * FROM lab5.$type WHERE $name ILIKE $1");
$param = $_POST['query_string'];
$clean_param = htmlspecialchars($param) . '%';
$result = pg_execute($conn, "country_lookup", array($clean_param));

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
I hate to doublepost, but I have a new problem:

For this assignment (same as above), we have a php page where we query the database and display the result as a table. Each row of the table has a set of buttons displayed with it that are supposed to allow the user to alter entries in the table. This button links to anothe php page, and sets three variables, storing the primary key, the table, and the action to be taken ("edit" in this case).

On the page that this links to, all the data for the row defined by the primary key is supposed to be displayed. But I don't have it, since I'm on a new page. But that's okay, because I have the primary key for that row. So I thought, "easy peasy, I will just do another query" wrong. Nothing happens at all. All of the php seems to execute, but $result is never populated. I have checked that the variable are imported correctly, you can see above my pg_prepare statement that I have an echo that spits out the SELECT operation I will be using. It prints correctly, and I have checked that it works correcly via commandline in psql. No lines manipulating $result seem to do anything at all. For example, $temp = pg_num_fields($result); echo "$temp"; produces nothing. I'm really lost here guys. Any help with what is going on would be appreciated.

Here is my code for the whole page:
code:
<html>
<?php
	include("../secure/database.php");
	$conn = pg_connect(HOST." ".DBNAME." ".USERNAME." ".PASSWORD)
		or die('Could not connect: ' . pg_last_error());
	$pk = $_POST['pk'];
	$tbl = $_POST['tbl'];
	$action = $_POST['action'];
	switch($tbl){ //this sets the appropriate search parameters based on the primary key
		case 'country':
			$params = "country_code = '$pk'";
			break;
		case 'city':
			$params = "id = '$pk'";
			break;
		case 'country_language':
			$key = explode(':', $pk);
			$params = "country_code ='$key[0]' AND language = '$key[1]'";
			break;
	}
	echo "$params";
	echo "<table border='1'>";
	switch($action){ //this switch determines which page to display
		case 'edit':
			echo "THis is the edit page";
			echo "SELECT * FROM lab5.$tbl WHERE $params";
			$result = pg_prepare($conn, "entry_lookup", "SELECT * FROM lab5.$tbl WHERE $1");
			$result = pg_execute($conn, "entry_lookup", array($params));
			echo "result";
			$i = 0;
			$temp = pg_num_fields($result);
			echo "$temp";
			/*while($i < pg_num_fields($result)){
				$column_name = pg_field_name($result, $i++);
				echo "<td> $column_name </td>";
			}*/
			while($line = pg_fetch_array($result, null, PGSQL_ASSOC)){
				foreach($line as $col_value){
					echo "$col_value\n";
				}
			}
			foreach($line as $col_value){
				echo "\t\t<td>$col_value</td>\n";
			}
			break;
		case 'remove':
			echo "DELETE THIS THING!!!";
			break;
	}
	echo "</table>";
	pg_free_result($result);
	pg_close($conn);
?>
</html>
edit: I'm going to post this in the sql thread as well, since the problem may live on that side of things.

Snak fucked around with this message at 02:37 on Mar 5, 2015

Mister Chief
Jun 6, 2011

Have you checked that all the post variables are being set?

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer

Mister Chief posted:

Have you checked that all the post variables are being set?

yeah. If they weren't being set, then

echo "SELECT * FROM lab5.$tbl WHERE $params";

wouldn't output the correct query string.

edit: and in case it's not clear, I connected to the same database on the previous php page, using the same code. This is the sort of thing where I have no idea if it would cause a problem, but I assumed not because as far as I know, separate pages are discrete and don't share anything. If they did, I wouldn't have had to use the hidden forms on the last page and get them from post here.

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
I think the problem lies in your WHERE construction.
php:
<?
result = pg_prepare($conn, "entry_lookup", "SELECT * FROM lab5.$tbl WHERE $1");
$result = pg_execute($conn, "entry_lookup", array($params));
?>
You've mislead yourself by using echo "SELECT * FROM lab5.$tbl WHERE $params";. You've fallen into the trap of thinking that a statement + params = a full SQL statement on the other end, and that's simply not the case. With a prepared statement (pg_parepare) you need to realise that the $params should be an array of values, not conditions. These will be appropriately escaped and passed into the WHERE clause.

Effectively what's happening is you're passing this query:
SELECT * FROM lab5.table_name WHERE $1
this parameter:
"country_code ='A' AND language = 'B'"
Which actually makes this query:
SELECT * FROM lab5.table_name WHERE "country_code ='A' AND language = 'B'"
Which I don't think is even valid.

You'd probably see that if you modified your code to have error reporting on the query:
php:
<?
$result = pg_prepare($conn, "entry_lookup", "SELECT * FROM lab5.$tbl WHERE $1");
if ($result === false) { die(pg_last_error()); }
$result = pg_execute($conn, "entry_lookup", array($params));
if ($result === false) { die(pg_last_error()); }
?>
What you want to do, is prepare the WHERE clause portion, and then pass the appropriate values.

php:
<?
    $where = '';
    $params = array();

    switch($tbl){ //this sets the appropriate search parameters based on the primary key
        case 'country':
            $where = "country_code = $1";
            $params[] = $pk;
            break;
        case 'city':
            $where = "id = $1";
            $params[] = "$pk";
            break;
        case 'country_language':
            $key = explode(':', $pk);
            $where = "country_code = $1 AND language = $2";
            $params[] = $key[0];
            $params[] = $key[1];
            break;
    }

    echo "<table border='1'>";
    switch($action){ //this switch determines which page to display
        case 'edit':
            echo "THis is the edit page";
            $sql = "SELECT * FROM lab5.$tbl WHERE $where";
            echo $sql;
            var_dump($params);
            $result = pg_prepare($conn, "entry_lookup", $sql);
            $result = pg_execute($conn, "entry_lookup", $params);
?>
In the above, the WHERE portion of the query is created into the $where value, with params populated into the $params array.
The SQL is also constructed into the variable $sql, so we echo exactly what's going to be fed to pg_prepare (not a copy), and var_dump $params so we can see exactly what each element is.

Also, if you're debugging something like $result, don't use echo or print_r, but instead use var_dump(). var_dump will show you the type of whatever you're inspecting (bool, string, Object, Resource, etc), and gives you a lot more detail that the others can't.

Edit: Can I also wave you off using switch statements for stuff that's the equivalent of "if x == y"? It's more prone to in-obvious failure (forgetting a break;), harder to add additional conditions to, and makes modifying the flow a lot more effort.

v1nce fucked around with this message at 04:01 on Mar 5, 2015

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
Ahh, this makes sense, thank you. Also thanks for the var_dump tip. That should help. This class is about database ?theory? and we're expected to learn all of how to apply it on our own.

Confused about your comment on switch statements though. How is a switch statement harder to add additional conditions to? I will try to make some of these changes, but really I just can't give a gently caress about this class any more. The whole CS program at my school thinks that it's REALLY important to have weekly assignments, but it takes 3-4 weeks to grade them, so you never get a chance to learn from your mistakes and you end up submitting assignment 6, and then getting back the grades for assignment 3 and finding out you've been doing something wrong for four assignments.

edit: also, this is so confusing. why is the prepare putting my value in quotes, when earlier I had a bunch of problems because string variables needed to be in quotes and they weren't parsed that way? Coming from C and Java, learning html, php, and sql all at once is a nightmare.

Snak fucked around with this message at 04:20 on Mar 5, 2015

Impotence
Nov 8, 2010
Lipstick Apathy

Snak posted:


Confused about your comment on switch statements though. How is a switch statement harder to add additional conditions to?

switch() has a break;, if you forget the break, it starts falling throlugh
switch() only does loose ==, this means that
php:
<?
$k = (string)"0xFF";
switch($k) {
    case (int)255:
        echo "lol";
        break;
}
?>
prints 'lol', while
php:
<?
if ($k === (int)255) { echo "lol"; }?>
doesn't

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer

Biowarfare posted:

switch() has a break;, if you forget the break, it starts falling throlugh
switch() only does loose ==, this means that
php:
<?
$k = (string)"0xFF";
switch($k) {
    case (int)255:
        echo "lol";
        break;
}
?>
prints 'lol', while
php:
<?
if ($k === (int)255) { echo "lol"; }?>
doesn't

Oh I gotcha. Doesn't matter for this application. Or maybe it does. Who knows. Maybe I'll have one of my projects graded in a few months. Thanks so much, you've been very helpful. I'm just so fed up with school right now it's hard to have a good attitude about anything.

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.

Snak posted:

I will try to make some of these changes, but really I just can't give a gently caress about this class any more.
I'll take that. Don't bother refactoring what you've got if it's working, but just don't do it in future unless switch is super appropriate, or it'll form a bad habit.

Snak posted:

edit: also, this is so confusing. why is the prepare putting my value in quotes, when earlier I had a bunch of problems because string variables needed to be in quotes and they weren't parsed that way? Coming from C and Java, learning html, php, and sql all at once is a nightmare.
I can't say for sure, but I'm going to bet those statements you had problems with were similarly buggy. There's a whole ton of reasons why that could be, and without seeing the statement, code and DB I can't diagnose any further.

It could be something silly like your INSERT statement wrapped the variables in quotes, so when you go to SELECT them you get no results because all the data in the database has quotes around them.
That's a common problem with people who're just starting to use unicode formatting - they set everything to UTF8 except the DB, and while they can push/pull data fine, when they look at the data itself in the DB browser all the unicode looks hosed up.

revmoo
May 25, 2006

#basta
I've never seen a use case of switch() where I thought it made sense. At best you're abbreviating what should be a function or class, depending on complexity, and at worst you've written a bunch of lovely if statements that could have been done a smarter way.

wolffenstein
Aug 2, 2002
 
Pork Pro
I used switch($_SERVER['SERVER_NAME']) to determine if the code is running on production, test, or dev and set variables accordingly. Yes, I know that poo poo should not be in files checked into version control, but I have to pick my battles.

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer

revmoo posted:

I've never seen a use case of switch() where I thought it made sense. At best you're abbreviating what should be a function or class, depending on complexity, and at worst you've written a bunch of lovely if statements that could have been done a smarter way.

Are you talking about just in php, or in general? I use them a lot both in C and in Java, but we don't really get any feedback on our code if it works, so if it's generally bad logic to use, I had no idea.

I do agree that the switch statement in my code here is horrible. My only defense is that I was working against a deadline and I've never written functions in php so I was trying to just use what I knew.

revmoo
May 25, 2006

#basta
In general.

I'm waiting for someone to come along and tell me why I'm wrong. Are there any good use cases for switch()?

Adbot
ADBOT LOVES YOU

spacebard
Jan 1, 2007

Football~

revmoo posted:

In general.

I'm waiting for someone to come along and tell me why I'm wrong. Are there any good use cases for switch()?

I don't think its necessarily good or bad, but I liked a recursive function I wrote that traversed a DomDocument object. The switch statement was easier than a large number of if/elseif. The switch had case statements equal to an element name.

I think the better approach might have been implementing a sub class of DomDocument and other classes with custom methods for iterations. That could have broken the complexity down.

Either way complexity was going to be high because it was a complex XML file from an external system that needed to be transformed into HTML.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply