Как вы встраиваете свои sql-запросы в php-скрипты (стиль кодирования)? - PullRequest
10 голосов
/ 14 января 2009

как вы встраиваете свои сценарии sql в php? Вы просто пишете их в виде строки или heredoc или передаете их в файл sql? Есть ли лучшие практики, когда их аутсорсинг? Есть ли элегантный способ организовать это?

Ответы [ 10 ]

5 голосов
/ 14 января 2009

Используйте каркас со слоем ORM (Object-Relational Mapping). Таким образом, вам не нужно никуда вставлять прямой SQL. Встроенный SQL - отстой для удобства чтения, обслуживания и всего остального.

4 голосов
/ 14 января 2009

Всегда помните, чтобы избежать ввода. Не делайте этого вручную, используйте подготовленные заявления. Вот пример метода из моего класса отчетности.

public function getTasksReport($rmId, $stage, $mmcName) {
    $rmCondition = $rmId ? 'mud.manager_id = :rmId' : 'TRUE';
    $stageCondition = $stage ? 't.stage_id = :stageId' : 'TRUE';
    $mmcCondition = $mmcName ? 'mmcs.username = :mmcName' : 'TRUE';
    $sql = "
            SELECT
                    mmcs.id AS mmc_id,
                    mmcs.username AS mmcname,
                    mud.band_name AS mmc_name,
                    t.id AS task_id,
                    t.name AS task, 
                    t.stage_id AS stage,
                    t.role_id,
                    tl.id AS task_log_id,
                    mr.role,
                    u.id AS user_id,
                    u.username AS username,
                    COALESCE(cud.full_name, bud.band_name) AS user_name,
                    DATE_FORMAT(tl.completed_on, '%d-%m-%Y %T') AS completed_on,
                    tl.url AS url,
                    mud.manager_id AS rm_id
            FROM users AS mmcs
            INNER JOIN banduserdetails AS mud ON mud.user_id = mmcs.id
            LEFT JOIN tasks AS t ON 1
            LEFT JOIN task_log AS tl ON tl.task_id = t.id AND tl.mmc_id = mmcs.id
            LEFT JOIN mmc_roles AS mr ON mr.id = t.role_id
            LEFT JOIN users AS u ON u.id = tl.user_id
            LEFT JOIN communityuserdetails AS cud ON cud.user_id = u.id
            LEFT JOIN banduserdetails AS bud ON bud.user_id = u.id
            WHERE mmcs.user_type = 'mmc'
                    AND $rmCondition
                    AND $stageCondition
                    AND $mmcCondition
            ORDER BY mmcs.id, t.stage_id, t.role_id, t.task_order
    ";
    $pdo = new PDO(.....);
    $stmt = $pdo->prepare($sql);
    $rmId and $stmt->bindValue('rmId', $rmId); // (1)
    $stage and $stmt->bindValue('stageId', $stage); // (2)
    $mmcName and $stmt->bindValue('mmcName', $mmcName); // (3)
    $stmt->execute();
    return $stmt->fetchAll();
}

В строках, отмеченных (1), (2) и (3), вы найдете способ условного связывания.

Для простых запросов я использую ORM Framework, чтобы уменьшить необходимость создания SQL вручную.

2 голосов
/ 11 февраля 2009

Я предпочитаю как таковой:

$sql = "SELECT tbl1.col1, tbl1.col2, tbl2.col1, tbl2.col2"
        . " FROM Table1 tbl1"
        . " INNER JOIN Table2 tbl2 ON tbl1.id = tbl2.other_id"
        . " WHERE tbl2.id = ?"
        . " ORDER BY tbl2.col1, tbl2.col2"
        . " LIMIT 10, 0";

Для объединения всех строк PHP может потребоваться немного больше времени, но я думаю, что он выглядит намного лучше и его легче редактировать.

Конечно, для очень длинных и специализированных запросов имеет смысл прочитать файл .sql или использовать хранимую процедуру. В зависимости от вашей структуры это может быть так просто:

$sql = (string) View::factory('sql/myfile');

(при необходимости вы можете назначить переменные в представлении / шаблоне). Без помощи шаблонизатора или фреймворка вы бы использовали:

$sql = file_get_contents("myfile.sql");

Надеюсь, это поможет.

2 голосов
/ 14 января 2009

Вы всегда должны действительно ВСЕГДА использовать операторы подготовки с заполнителями для ваших переменных.

Это немного больше кода, но он работает более эффективно на большинстве БД и защищает вас от атак SQL-инъекций.

2 голосов
/ 14 января 2009

Это зависит от размера и сложности запроса.

Лично мне нравятся heredocs. Но я не использую его для простых запросов. Это не важно. Главное «Никогда не забывать избегать ценностей»

1 голос
/ 14 января 2009

Я обычно пишу их как аргумент функции:

db_exec ("SELECT ...");

За исключением случаев, когда sql будет очень большим, я передаю его как переменную:

$SQL = "SELECT ...";
$result = db_exec ($SQL);

(я использую функции-оболочки или объекты для операций с базой данных)

0 голосов
/ 11 февраля 2009

Мне нравится этот формат. Это было упомянуто в предыдущем комментарии, но мне показалось, что это не так.

$query = "SELECT "
       . " foo, "
       . " bar "
       . "FROM "
       . " mytable "
       . "WHERE "
       . " id = $userid";

Достаточно легко читать и понимать. Точки совпадают со знаком равенства, сохраняя все в чистой линии.

Мне также нравится идея хранить ваш SQL в отдельном файле, хотя я не уверен, как это будет работать с переменными, такими как $ userid, в моем примере выше.

0 голосов
/ 14 января 2009

Как только вы достигнете определенного уровня, вы поймете, что 99% написанного вами SQL может быть автоматизировано. Если вы пишете так много запросов, что думаете о файле свойств, вы, вероятно, делаете что-то, что может быть проще:

Большинство вещей, которые делают программисты, это CRUD: Create Read Update Delete

В качестве инструмента для себя я создал Pork.dbObject. Mapper Object Relation Mapper + Active Record в 2 простых классах (абстракция базы данных + класс dbObject)

Несколько примеров с моего сайта:

Создать блог:

    $weblog = new Weblog(); // create an empty object to work with. 
    $weblog->Author = 'SchizoDuckie'; // mapped internally to strAuthor. 
    $weblog->Title = 'A test weblog';  
    $weblog->Story = 'This is a test weblog!'; 
    $weblog->Posted = date("Y-m-d H:i:s"); 
    $weblog->Save(); // Checks for any changed values and inserts or updates into DB. 
    echo ($weblog->ID) // outputs: 1 

И один ответ на это:

    $reply = new Reply(); 
    $reply->Author = 'Some random guy'; 
    $reply->Reply = 'w000t'; 
    $reply->Posted = date("Y-m-d H:i:s"); 
    $reply->IP = '127.0.0.1'; 
    $reply->Connect($weblog); // auto-saves $reply and connects it to $weblog->ID 

А также получить и отобразить блог + все ответы:

    $weblog = new Weblog(1); //Fetches the row with primary key 1 from table weblogs and hooks it's values into $weblog;

    echo("<h1>{$weblog->Title}</h1> 
    <h3>Posted by {$weblog->Author} @ {$weblog->Posted}</h3> 
    <div class='weblogpost'>{$weblog->Story}</div>"); 

    // now fetch the connected posts. this is the real magic: 
    $replies = $weblog->Find("Reply"); // fetches a pre-filled array of Reply objects. 
    if ($replies != false) 
    { 
        foreach($replies as $reply) 
        { 
            echo("<div class='weblogreply'><h4>By {$reply->Author} @ {$reply->Posted}</h4> {$reply->Reply}</div>"); 
        } 
    } 

Объект weblog будет выглядеть так:

class Weblog extends dbObject 
{ 
    function __construct($ID=false) 
    { 
        $this->__setupDatabase('blogs', // database table 
        array('ID_Blog' => 'ID',    // database field => mapped object property 
            'strPost' => 'Story',    // as you can see, database field strPost is mapped to $this->Story 
            'datPosted' => 'Posted', 
            'strPoster' => 'Author', 
            'strTitle'  => 'Title',
            'ipAddress'  => 'IpAddress', 
            'ID_Blog',    // primary table key  
            $ID);    // value of primary key to init with (can be false for new empty object / row) 
        $this->addRelation('Reaction'); // define a 1:many relation to Reaction 

    }
}

Видите, нет написания SQL вручную :) Ссылка + больше примеров: Pork.dbObject

О, да, я также создал элементарный GUI для моего инструмента:

0 голосов
/ 14 января 2009

Вы можете использовать ORM или построитель строк SQL, но некоторые сложные запросы требуют написания SQL. При написании sql, как иллюстрирует Михал Слаби, используйте привязки запросов. Привязки запросов предотвращают внедрение SQL и поддерживают читабельность. Что касается того, где можно разместить ваши запросы: используйте классы моделей.

0 голосов
/ 14 января 2009
$sql = sprintf("SELECT * FROM users WHERE id = %d", mysql_real_escape_string($_GET["id"]));

Сейф от инъекции MySQL

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...