`, etc
532 |
533 | - Will sit next to one another on the same line
534 | - Don't always automatically receive all CSS styles (padding/margin/width/height etc) - this can be confusing!
535 | - Putting block-level elements within an inline element (such as a link) can lead to unexpected results
536 |
537 | Easy to alter with CSS - `display: block` or `display: inline`
538 |
539 | See:
540 |
541 | - [http://www.quirksmode.org/css/display.html](http://www.quirksmode.org/css/display.html)
542 | - [http://learnlayout.com/inline-block.html](http://learnlayout.com/inline-block.html)
543 |
544 |
545 | ### Layout
546 |
547 | The main CSS properties we use for layout are `display`, `float` and `position`
548 |
549 | A great tutorial:
550 |
551 | - [http://learnlayout.com/](http://learnlayout.com/)
552 |
553 |
554 | ### Positioning
555 |
556 | By default, all HTML elements have a CSS position attribute of `static`
557 |
558 | ```
559 | ...
560 |
561 |
562 | ```
563 |
564 | ```
565 | #main,
566 | #sidebar,
567 | #footer {
568 | position: static; /* this is the default value */
569 | }
570 | ```
571 |
572 | These block HTML elements will be on their own line
573 |
574 | Changing the CSS position attribute allows you to set top/bottom/left/right values - relative to the ``, or a parent container that has `position: relative` applied:
575 |
576 | ```
577 | #main {
578 | position: absolute;
579 | left: 10px;
580 | width: 75%;
581 | background: #eee;
582 | }
583 |
584 | #sidebar {
585 | position: absolute;
586 | right: 10px;
587 | width: 20%;
588 | background: #ffd;
589 | }
590 | ```
591 |
592 | A page laid out using `position: absolute` has its limits
593 |
594 | - 'fixed' heights of content
595 | - layout doesn't adapt to the content
596 |
597 | `position` is useful, but not for main page layout
598 |
599 |
600 | ### Floats
601 |
602 | HTML elements can have a float set with CSS - `float: left;` or `float: right;`
603 |
604 | ```
605 | #main {
606 | background: #eee;
607 | float: left;
608 | width: 80%;
609 | }
610 |
611 | #sidebar {
612 | background: #ffd;
613 | float: right;
614 | width: 15%;
615 | }
616 | ```
617 |
618 | A floated element is shifted to the left or right of its container element as far as possible
619 |
620 | If we float another element in the same direction, it will be shifted until its edge reaches the edge of the first floating element
621 |
622 | Unfloated content flows and wraps around floated elements
623 |
624 | Floats are better that positioning for layout - unlike absolutely positioned elements, floated elements remain in the document flow, so can expand with content
625 |
626 | You should (almost) always set widths on floated elements, although elements with inherent widths (e.g. images) don't need a width set
627 |
628 |
629 | #### Controlling floats
630 |
631 | If we want to control how many floated elements appear on a line, we can wrap a div element around the floated content, and set a width:
632 |
633 | ```
634 |
635 |
block 1
636 | ...
637 |
block 10
638 |
639 | ```
640 |
641 | ```
642 | #block-container {
643 | width: 500px;
644 | }
645 | .block {
646 | float: left;
647 | width: 100px;
648 | margin-right: 20px;
649 | }
650 | ```
651 |
652 | #### Two main uses for floats:
653 |
654 | - page layout
655 | - layout of elements within a block
656 |
657 |
658 | #### float: centre?
659 |
660 | You can't float an element to the centre - there are other techniques for that
661 |
662 | ```
663 | body {
664 | width: 600px;
665 | margin: 0 auto;
666 | }
667 | ```
668 |
669 |
670 | ## Responsive websites
671 |
672 | We can no longer assume that most people primarily use a desktop or laptop computer to browse the internet
673 |
674 | People use a variety of internet browsers and operating systems
675 |
676 | Nowadays most people have at least one other device that they use to browse the internet
677 |
678 | These devices are increasingly being used in place of 'traditional' browsers
679 |
680 | We should ensure that our websites work across all commonly used desktop browsers
681 |
682 | We should take non-desktop browsers/devices into consideration when building a website
683 |
684 | These devices have different display resolutions (or browser dimensions)
685 |
686 | These devices also have different methods of interaction
687 |
688 |
689 | ### Media queries
690 |
691 | You can specify CSS for different browser resolutions (or dimensions) using CSS `@media` queries.
692 |
693 | For a typical website you might create three sets of styles:
694 |
695 | - one set of generic page styles, used on every device/browser
696 | - another set of styles just for low-resolution (mobile) browsers
697 | - a third set just for higher-resolution (desktop/tablet) browsers
698 |
699 | The point at which the design 'snaps' from one layout to the next is commonly known as the 'break point'
700 |
701 | These media queries can appear inline in the CSS:
702 |
703 | ```
704 | @media (max-width: 480px) {
705 | #main-content,
706 | #aside {
707 | width: 100%;
708 | float: none;
709 | }
710 | }
711 | ```
712 |
713 | Styles put within the `@media` query will only be used if the specified conditions are true.
714 |
715 | Using `@media` queries to create different layouts for different resolutions (or browser dimensions) is generally known as responsive web design
716 |
717 | Content layout should adapt to fit different browser sizes
718 |
719 |
720 | ### Meta viewport
721 |
722 | You can control how a page renders in a (modern) mobile browser using a ` ` viewport declaration:
723 |
724 | ```
725 |
726 | ```
727 |
728 |
729 | ### Mobile first
730 |
731 | It is possible to make an existing site more responsive by adding additional styles (within an `@media` query) for mobile devices
732 |
733 | Bandwidth issues for desktop browsers are less relevant nowadays with broadband, but is still a concern for mobile browsers
734 |
735 | Using `@media` queries means a mobile must download an entire desktop site, and then extra styles
736 |
737 | It may make more sense to first create a basic design for mobile, and then add extra layout styles for desktop browsers
738 |
739 | This approach has become known as mobile-first
740 |
741 | This approach is device-inclusive
742 |
743 | The default set of styles sent to every browser/device should be for the most basic page layout
744 |
745 | In this capacity, a lack of `@media` query support should be seen as your first `@media` query
746 |
747 | i.e. old browsers or devices don't support `@media` queries, so these devices receive the default mobile version
748 |
749 |
750 | ***Further information:***
751 |
752 | - [http://blog.cloudfour.com/responsive-design-for-apps-part-1/](http://blog.cloudfour.com/responsive-design-for-apps-part-1/)
753 | - [http://www.webdesignerdepot.com/2011/09/the-ultimate-responsive-web-design-roundup/](http://www.webdesignerdepot.com/2011/09/the-ultimate-responsive-web-design-roundup/)
754 | - [http://www.designbyfront.com/demo/goldilocks-approach/](http://www.designbyfront.com/demo/goldilocks-approach/)
755 | - [http://coding.smashingmagazine.com/2010/07/19/how-to-use-css3-media-queries-to-create-a-mobile-version-of-your-website/](http://coding.smashingmagazine.com/2010/07/19/how-to-use-css3-media-queries-to-create-a-mobile-version-of-your-website/)
756 | - [http://marcdrummond.com/web-standards/2011/06/20/hell-bad-devices-responsive-web-design-and-web-standards](http://marcdrummond.com/web-standards/2011/06/20/hell-bad-devices-responsive-web-design-and-web-standards)
757 | - [http://stefangirard.com/2012/01/responsive-design-is-bad/](http://stefangirard.com/2012/01/responsive-design-is-bad/)
758 | - [http://www.webdesignshock.com/responsive-design-problems/](http://www.webdesignshock.com/responsive-design-problems/)
759 |
760 |
761 |
762 | ## Web Standards
763 |
764 | ### What are web standards?
765 |
766 | An 'agreed' specification for HTML, CSS and JavaScript
767 |
768 | - How we should write code
769 | - How web browsers should read and render code
770 |
771 | Web standards allow web developers to focus on their code
772 |
773 | If the code is valid, the page should render in a web browser as expected
774 |
775 | A good example comes from the history of the ` ` element:
776 |
777 | - [A long digression into how standards are made](http://diveintohtml5.info/past.html#history-of-the-img-element)
778 |
779 |
780 | #### A short summary of web standards
781 |
782 | - Use valid, semantic HTML for content
783 | - Use CSS for layout
784 | - Use JavaScript for behaviour
785 |
786 |
787 | ### Web standards and accessibility
788 |
789 | Web standards define rules for accessibility
790 |
791 | > "The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect."
792 | >
793 | > — [W3C Web Content Accessibility Guidelines](http://www.w3.org/TR/WCAG20/)
794 |
795 |
796 | ### Why are web standards important?
797 |
798 | Tim Berners-Lee created HTML as a language to help represent information in a consistent manner
799 |
800 | If everyone can agree on a shared vocabulary, then a web browser should be able to interpret what I have created and display it to you in a predictable way
801 |
802 | This was overseen by the W3C, who defined standards that should be followed by all
803 |
804 | This was a good plan in theory - until the web became more popular than anyone could have imagined
805 |
806 | In the early days of the web, competing web browsers were created, and in an attempt to win market share, numerous new features were introduced that weren't available in rival browsers. New elements, new ways to lay out and interact with web pages
807 |
808 | On the one hand, this led to a great deal of innovation. Which, in theory, is a good thing. But in practice... it led to fragmentation in how browsers rendered HTML
809 |
810 | This fragmentation caused a great deal of problems for developers, and web users alike
811 |
812 | To create a website that worked everywhere often meant creating the same thing twice, in two different ways. Or, more commonly, building a website and optimising it just for a single browser
813 |
814 | Browser manufacturers wanted to implement new functionality, web developers wanted to be able to do that weren't possible in a browser, because of a lack of agreement for how to implement them
815 |
816 | Groups of developers formed collectives such as the Web Standards Project (WaSP) to convince rival browser manufacturers to embrace the common standards set out by the W3C, for the benefit of all
817 |
818 | It took a number of years for their message to be heard, but eventually the major browser manufacturers realised the approach would benefit them too
819 |
820 |
821 | ### Web standards today
822 |
823 | Web standards are still relevant today - we have a range of desktop and mobile browsers
824 |
825 | To ensure these browsers operate in a consistent manner they must continue to follow a mutually agreed set of design principles and rules
826 |
827 | To get anything built efficiently, developers need consensus. We need to know that what we build will work
828 |
829 | The difference today is, with web standards, we have some reassurance that this is indeed the case
830 |
831 | The browser manufacturers themselves are now actively involved in the process of defining the new standards for HTML, CSS and JavaScript
832 |
833 | They (mostly) follow agreed standards and conventions when creating these innovations, meaning innovative features can be reliably implemented to create an experience that works in any browser
834 |
--------------------------------------------------------------------------------
/databases.md:
--------------------------------------------------------------------------------
1 | # Database notes
2 |
3 | A few notes prepared while writing training courses...
4 |
5 | Note that the following examples assume *MySQL* as the chosen database. Other relational databases will tend to use a similar logic, although with slightly different syntax.
6 |
7 |
8 | ## Why use a database?
9 |
10 | When building web applications, we often use a database to store information
11 |
12 | We want to store our application *data* separately from:
13 |
14 | - application *logic* (e.g. Ruby, Python)
15 | - *presentation* (e.g. HTML templates)
16 |
17 |
18 | ### Advantages
19 |
20 | There are a number of advantages for separating information from presentation:
21 |
22 | - Easier to manage content without changing logic
23 | - Data can be re-used elsewhere
24 | - Data can be managed via an administrative tool (such as a *content management system*), with little or no technical knowledge required
25 | - Databases are optimised to store and retrieve data quickly
26 |
27 |
28 | ## Database essentials
29 |
30 | A database is just a collection of one or more tables of data
31 |
32 | - Each table has a number of **columns** (or fields, attributes)
33 | - Each column has a specific **name**
34 | - Each column also has a data **type** (e.g. text, number, date/time, etc)
35 | - Data is stored in a table in **rows**
36 | - Each individual column within a row is called a **cell**
37 |
38 | Database field names don't usually contain spaces. Conventions usually suggest making them all lower-case, using underscores to separate words
39 |
40 | | id | column_1 | column_2 |
41 | | ---|-------------|----------|
42 | | 1 | row 1 | cell |
43 | | 2 | row 2 | lorem |
44 | | 3 | cell | ipsum |
45 |
46 |
47 | ## An example scenario
48 |
49 | The following notes will be based around designing a database to meet an example scenario:
50 |
51 | *Design a database for a web application that tweets a daily question and aggregates __@replies__. These tweets will be categorised into one or more categories*
52 |
53 |
54 | ## Database design process
55 |
56 | We can design our database by following a few simple steps:
57 |
58 | 1. Decide on what data you want to store
59 | 2. Choose data types for each of these items of information
60 | 3. Normalise the data
61 |
62 | These notes will then explain how to:
63 |
64 | 1. Create your database
65 | 2. Populate your database
66 | 3. Query your database
67 |
68 |
69 | ## Storing data
70 |
71 | When designing a database, it is important to first decide what data we want to store.
72 |
73 | If we were to imagine our example data in tabular form, we might have something like this:
74 |
75 | | id | name | handle | question | answer | categories | date_added |
76 | |----|------|----------------|------------------|---------------|----------------|---------------------|
77 | | 1 | Pete | blah | Favourite Cheese | Edam | serious | 2013-03-21 18:34:23 |
78 | | 2 | Rich | rich_xyz | Favourite Prince | Fresh | funny, winner | 2013-03-21 19:25:16 |
79 | | 3 | Nick | something | Favourite Prince | TAFKAP | serious, funny | 2013-03-21 20:12:01 |
80 | | 4 | Mike | dangerous | Favourite Cheese | Melted cheese | funny, winner | 2013-03-21 19:25:16 |
81 |
82 |
83 |
84 | ## Choosing data types
85 |
86 | This step identifies the possible values for the data
87 |
88 | Data types control the way the data is stored in the database - to make it as efficient as possible
89 |
90 | A few example data types:
91 |
92 | * String (text):
93 | - Fixed length (up to 255 characters)
94 | - Variable length (up to 255 characters)
95 | - Text (over 255 characters)
96 |
97 | * Numeric:
98 | - Integers - whole numbers
99 | - Decimal - not whole numbers
100 | - Date and time
101 |
102 | (Exact data types can vary depending on the database used)
103 |
104 | In our example scenario we might use the following data types:
105 |
106 | - **ID**: integer
107 | - **name**: variable length text
108 | - **handle**: variable length text
109 | - **question**: variable length text
110 | - **answer**: variable length text
111 | - **categories**: text
112 | - **date_added**: date and time
113 |
114 |
115 | ## Data normalisation
116 |
117 | To normalise data is to remove the duplication of information, so each piece of information should be stored only once
118 |
119 | Once we have removed repetition of data we have removed the possibility of inconsistencies
120 |
121 | This ensures that the 'integrity' of the data is maintained.
122 |
123 | *What this means:*
124 |
125 | Any repetitive data should be stored in a separate database table
126 |
127 | To normalise data also means to ungroup items of data, to separate them so each cell contains only a single item of data
128 |
129 | *What this means:*
130 |
131 | Any cells containing multiple items of data should be stored in a separate database table
132 |
133 |
134 | ***Further reading:***
135 |
136 | - [http://phlonx.com/resources/nf3/](http://phlonx.com/resources/nf3/)
137 | - [http://en.wikipedia.org/wiki/Database_normalization](http://en.wikipedia.org/wiki/Database_normalization)
138 | - [http://www.devshed.com/c/a/MySQL/An-Introduction-to-Database-Normalization/](http://www.devshed.com/c/a/MySQL/An-Introduction-to-Database-Normalization/)
139 | - [http://support.microsoft.com/kb/100139](http://support.microsoft.com/kb/100139)
140 |
141 |
142 | ### Limiting normalisation
143 |
144 | In a fully normalised database, there should be no duplication of information.
145 |
146 | However this can sometimes fragment or over-complicate the data, and unnecessarily separate items of information which then need to be brought together in order to answer queries.
147 |
148 | The database designer may sometimes prefer to have a database which is not strictly normalised so as to simplify the system and/or improve query performance.
149 |
150 | ***Further reading:***
151 |
152 | - [http://www.keithjbrown.co.uk/vworks/mysql/mysql_p7.php](http://www.keithjbrown.co.uk/vworks/mysql/mysql_p7.php)
153 | - [http://www.codinghorror.com/blog/2008/07/maybe-normalizing-isnt-normal.html](http://www.codinghorror.com/blog/2008/07/maybe-normalizing-isnt-normal.html)
154 |
155 |
156 | ### Primary keys
157 |
158 | In every table, we must identify (or create) a unique ID (known as a primary key)
159 |
160 | A primary key has three requirements:
161 |
162 | 1. It must always have a value (it cannot be left blank)
163 | 2. Its value must never change
164 | 3. It must be unique
165 |
166 | A primary key must be a unique value which enables us to identify a single row of data, and so access all other data related to it
167 |
168 | If none of the items of data are unique, they cannot act as a primary key
169 |
170 | The simplest primary key is an integer that gets incremented for each new row
171 |
172 | Sometimes we will want to reference the primary key from one table in another table in order to identify a relationship between the two. If we do this, in the second table it is known as a *foreign key*
173 |
174 |
175 | ### Entities and Attributes
176 |
177 | For any scenario where you want to use a database, you need to identify the Entities and Attributes
178 |
179 | #### Entities
180 |
181 | Should be representations of real-world objects - events, persons, places, things
182 |
183 | e.g. projects, tasks, books, authors, publishers, products, ingredients...
184 |
185 | Each entity should have its own table in the database
186 |
187 | Not an easy science to correctly identify entities, it is dependant on the scenario and often subjective
188 |
189 | Once we have identified the entities, we can create a database table for each
190 |
191 |
192 | #### Attributes
193 |
194 | Pieces of information which characterise and describe these entities
195 |
196 | These become the fields/columns for each entity table in the database
197 |
198 | Need to identify the name of the attribute - e.g. 'name', 'answer', 'category'
199 |
200 | Need to identify the attribute 'type' - e.g. text, integer, date, etc
201 |
202 | Need to decide whether the attribute is optional - can it be empty?
203 |
204 | Can the attribute uniquely identify the entity?
205 |
206 |
207 | ### Example database tables
208 |
209 | Here are three of our example tables:
210 |
211 | ***Questions table***
212 |
213 | | id | question | date_added |
214 | |----|-------------------|---------------------|
215 | | 1 | Favourite Cheese? | 2013-03-21 18:34:23 |
216 | | 2 | Favourite Prince? | 2013-03-21 18:34:23 |
217 |
218 | ***Users table***
219 |
220 | | id | handle | name |
221 | |----|----------------|------|
222 | | 1 | blah | Pete |
223 |
224 |
225 | ***Categories table***
226 |
227 | | id | category |
228 | |----|----------|
229 | | 1 | Funny |
230 |
231 |
232 | ### Relationships
233 |
234 | It is important to identify the relationships between tables
235 |
236 | There are three types of relationship:
237 |
238 | 1. One-to-one (1:1)
239 | 2. One-to-many (1:N)
240 | 3. Many-to-many (N:M)
241 |
242 |
243 | #### One-to-many (1:N) relationships
244 |
245 | To identify a one-to-many (1:N) relationship, we use primary key to foreign key matching.
246 |
247 | We store the primary key of the 'one' as a foreign key in each of the 'many' items, establishing the relationship between them.
248 |
249 | Matching keys in this way allows related information to be brought together from different tables when the database is queried.
250 |
251 | In our example, questions:answers is a one-to-many relationship, for each question there are multiple answers, but each answer is only for one question
252 |
253 | Instead of adding the question for each answer, we'll store question details in the *questions* table
254 |
255 | We'll add a new field to the answers table called question_id - here we'll put in the unique primary key from the question table as a foreign key in the answer table
256 |
257 | Now the question details need only be stored once. If the question details were to change, we only need to update a single record in the question table and it would apply for all answers
258 |
259 | In a similar manner, users:answers is also a one-to-many relationship. Each user can submit many answers, yet each answer can only be from a single user.
260 |
261 | Here is our example *answers* table, including the use of foreign keys to tie our one-to-many relationships
262 |
263 | ***Answers table***
264 |
265 | | id | question_id | user_id | answer | tweet_id | date_added |
266 | |----|-------------|---------|--------|-------------|---------------------|
267 | | 1 | 1 | 1 | Edam | 23741876128 | 2013-03-21 18:34:23 |
268 |
269 |
270 | #### Many-to-many (N:M) relationships
271 |
272 | For a many-to-many (M:N) relationship, on both sides of the relationship there can be multiple entities in each table that are inter-related
273 |
274 | For example, one answer may have several categories; one category may be applied to several answers.
275 |
276 | To record this relationship we need to create a separate database table containing two foreign keys, which relate to the primary keys for each of the two relevant entities.
277 |
278 | Here is our *answers to categories* join table
279 |
280 | ***Answers to Categories (join) table***
281 |
282 | | id | answer_id | category_id |
283 | |----|-----------|-------------|
284 | | 1 | 1 | 5 |
285 |
286 |
287 |
288 | ## SQL
289 |
290 | We have designed our database
291 |
292 | We need to know how to create it, populate it and access this data
293 |
294 | This is where we need SQL
295 |
296 | Structured Query Language (SQL) is the language used by most databases to perform queries and manipulate data
297 |
298 |
299 | ### SQL rules
300 |
301 | A few SQL rules to bear in mind:
302 |
303 | SQL is generally case insensitive...
304 |
305 | ...except for table and column names, which are usually case sensitive
306 |
307 | By convention, SQL commands (e.g. `SELECT`, `UPDATE`) should be written in UPPERCASE
308 |
309 | Like in most programming languages, string (text) values should be surrounded by quotes ('single' or "double")
310 |
311 | Table and column names can optionally be surrounded by \` backticks - note that these are not the same as 'single quotes'
312 |
313 | All commands should terminate with a semi-colon;
314 |
315 |
316 | ### Creating a database
317 |
318 | If you were to have to create a new database yourself, you'd use the following command:
319 |
320 | ```
321 | CREATE DATABASE `dbname`;
322 | ```
323 |
324 | To see a list of all available databases you would enter:
325 |
326 | ```
327 | SHOW databases;
328 | ```
329 |
330 | To select a database you would enter:
331 |
332 | ```
333 | USE `dbname`;
334 | ```
335 |
336 | To delete a database you would enter:
337 |
338 | ```
339 | DROP `dbname`;
340 | ```
341 |
342 | ***THERE IS NO UNDO***
343 |
344 |
345 | ### Creating database tables
346 |
347 | We have already planned the structure for our database tables, now we need to turn these into SQL
348 |
349 | To create a table, use the CREATE TABLE command using the following syntax:
350 |
351 | ```
352 | CREATE TABLE `table_name` (
353 | `column_name` column_type column_attributes
354 | );
355 | ```
356 |
357 | Example syntax for our answers table:
358 |
359 | ```
360 | CREATE TABLE `answers` (
361 | `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
362 | `question_id` INT NOT NULL,
363 | `user_id` INT NOT NULL,
364 | `tweet_id` VARCHAR(20) NOT NULL,
365 | `answer` VARCHAR(255) NOT NULL,
366 | `date_added` DATETIME NOT NULL
367 | );
368 | ```
369 |
370 | Taking the example of the column called `id`:
371 |
372 | ```
373 | `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY
374 | ```
375 |
376 | - It will contain an integer (INT)
377 | - This column is not allowed to be left blank (NOT NULL)
378 | - This column is to act as a unique identifier for entries in this table, so all values in this column must be unique (PRIMARY KEY).
379 | - If we don't specify a value when adding a new entry, pick a value that is one more than the highest value in the table so far (AUTO_INCREMENT)
380 |
381 | Within a database, you can request to see what tables exist:
382 |
383 | ```
384 | SHOW TABLES;
385 | ```
386 |
387 | You can also request to see the structure of a specific table:
388 |
389 | ```
390 | DESCRIBE `tablename`;
391 | ```
392 |
393 | It is possible to update the structure of an existing database table using the ALTER command
394 |
395 | To add a column:
396 |
397 | ```
398 | ALTER TABLE `tablename` ADD `columnname` TEXT NOT NULL;
399 | ```
400 |
401 | To update the name or attributes of a column:
402 |
403 | ```
404 | ALTER TABLE `tablename` CHANGE `oldcolumnname` `newcolumnname`
405 | VARCHAR(255);
406 | ```
407 |
408 | To remove a column:
409 |
410 | ```
411 | ALTER TABLE `tablename` DROP `columnname`;
412 | ```
413 |
414 | To empty a table use the TRUNCATE command:
415 |
416 | ```
417 | TRUNCATE TABLE `tablename`;
418 | ```
419 |
420 | To delete a table use the DROP command:
421 |
422 | ```
423 | DROP TABLE `tablename`;
424 | ```
425 |
426 | ***THERE IS NO UNDO***
427 |
428 |
429 | ### Example database tables
430 |
431 | The following commands will create our example database tables:
432 |
433 | ```
434 | CREATE TABLE `questions` (
435 | `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
436 | `question` VARCHAR(255) NOT NULL,
437 | `date_added` DATETIME NOT NULL
438 | );
439 |
440 | CREATE TABLE `users` (
441 | `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
442 | `handle` VARCHAR(20) NOT NULL,
443 | `name` VARCHAR(255) NOT NULL
444 | );
445 |
446 | CREATE TABLE `categories` (
447 | `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
448 | `category` VARCHAR(255) NOT NULL
449 | );
450 |
451 | CREATE TABLE `answers` (
452 | `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
453 | `user_id` INT NOT NULL,
454 | `question_id` INT NOT NULL,
455 | `tweet_id` VARCHAR(20) NOT NULL,
456 | `answer` VARCHAR(255) NOT NULL,
457 | `date_added` DATETIME NOT NULL
458 | );
459 |
460 | CREATE TABLE `categories_answers` (
461 | `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
462 | `category_id` INT NOT NULL,
463 | `answer_id` INT NOT NULL
464 | );
465 | ```
466 |
467 |
468 | ### Populating a database
469 |
470 | Our database and tables are now ready to go
471 |
472 | We need to know how to populate them with data, and then retrieve this data
473 |
474 | #### CRUD
475 |
476 | Data-related tasks broadly fall into one of four categories:
477 |
478 | - Create (new data in a database)
479 | - Request/Read (data from a database)
480 | - Update (update existing data in a database)
481 | - Delete (data from a database)
482 |
483 | SQL allows us to do just that:
484 |
485 | - Create = INSERT
486 | - Request =SELECT
487 | - Update = UPDATE
488 | - Delete = DELETE
489 |
490 |
491 | #### INSERT
492 |
493 | To add data to the tables we've just created, we use an INSERT command:
494 |
495 | ```
496 | INSERT INTO `table_name` SET `columnName1` = 'value1', `columnName2` = 'value2';
497 | ```
498 |
499 | (or)
500 |
501 | ```
502 | INSERT INTO `table_name` (`columnName1`, `columnName2`) VALUES ('value1', 'value2');
503 | ```
504 |
505 | The second version allows us to insert multiple rows (separated by commas) in a single SQL statement
506 |
507 | ```
508 | INSERT INTO
509 | `table_name` (`columnName1`, `columnName2`)
510 | VALUES
511 | ('value1', 'value2'),
512 | ('value1', 'value2'),
513 | ('value1', 'value2'),
514 | ('value1', 'value2'),
515 | ('value1', 'value2');
516 | ```
517 |
518 |
519 | #### UPDATE
520 |
521 | To update data in a table we use an UPDATE command:
522 |
523 | ```
524 | UPDATE `table_name` SET `columnName1` = 'value1' WHERE `columnName2` = 'value2';
525 | ```
526 |
527 | Note the use of the WHERE clause - without this all items in the table would be updated!
528 |
529 |
530 | #### DELETE
531 |
532 | To delete data from a table we use a DELETE command:
533 |
534 | ```
535 | DELETE FROM `table_name` WHERE `columnName` = 'value';
536 | ```
537 |
538 | Note the use of the WHERE clause - without this all items in the table would be deleted!
539 |
540 | ***THERE IS NO UNDO***
541 |
542 |
543 | #### Populating our example database tables
544 |
545 | ```
546 | INSERT INTO `categories` (`id`, `category`) VALUES
547 | (1, 'Funny'),
548 | (2, 'Serious'),
549 | (3, 'Awkward'),
550 | (4, 'Joke'),
551 | (5, 'Winner');
552 |
553 | INSERT INTO `categories_answers` (`id`, `category_id`, `answer_id`) VALUES
554 | (1, 1, 1),
555 | (2, 2, 2),
556 | (3, 3, 2),
557 | (4, 4, 1),
558 | (5, 4, 3),
559 | (6, 5, 3),
560 | (7, 1, 4),
561 | (8, 2, 4),
562 | (9, 5, 5),
563 | (10, 3, 6),
564 | (11, 4, 6),
565 | (12, 1, 7),
566 | (13, 2, 8);
567 |
568 | INSERT INTO `answers` (`id`, `user_id`, `question_id`, `tweet_id`, `answer`, `date_added`) VALUES
569 | (1, 1, 1, '1347651374', 'Stilton', '2013-03-08 17:29:41'),
570 | (2, 2, 1, '2374234', 'Melted', '2013-03-21 07:13:00'),
571 | (3, 3, 2, '2378461216', 'Michael Fish', '2013-03-05 00:00:00'),
572 | (4, 1, 2, '23746182376', 'humahumanukanukaapuaa', '2013-03-19 00:00:00'),
573 | (5, 1, 3, '982736482764', 'Banned from the petting zoo', '2013-03-15 00:00:00'),
574 | (6, 4, 3, '167312763512', 'Nothing', '2013-03-04 00:00:00'),
575 | (7, 3, 4, '283746821364', 'Queen Latifah', '2013-03-20 00:00:00'),
576 | (8, 4, 4, '71823182763', 'Rich', '2013-03-10 00:00:00');
577 |
578 | INSERT INTO `questions` (`id`, `question`, `date_added`) VALUES
579 | (1, 'What''s your favourite cheese?', '2013-03-03 15:30:23'),
580 | (2, 'What''s your favourite fish?', '2013-03-20 15:29:38'),
581 | (3, 'What''s the punchline to your favourite joke?', '2013-03-01 17:36:57'),
582 | (4, 'Who''s your favourite queen?', '2013-03-09 19:45:42');
583 |
584 | INSERT INTO `users` (`id`, `handle`, `name`) VALUES
585 | (1, 'blah', 'Pete'),
586 | (2, 'rich_xyz', 'Rich'),
587 | (3, 'something', 'Nick'),
588 | (4, 'dangerous', 'Mike');
589 | ```
590 |
591 |
592 | ### Querying a database
593 |
594 | To read data from a table (or multiple tables) we use a SELECT command
595 |
596 | The simplest SELECT command will return everything in a database table:
597 |
598 | ```
599 | SELECT * FROM `table`;
600 | ```
601 |
602 | Rather than returning everything, it is possible to specify just the field names (columns) you want:
603 |
604 | ```
605 | SELECT `field` FROM `table`;
606 | ```
607 |
608 | Multiple fieldnames are separated by commas:
609 |
610 | ```
611 | SELECT `field1`, `field2`, `field3` FROM `table`;
612 | ```
613 |
614 | Rather than returning all results, we can add optional parameters to filter our request using WHERE:
615 |
616 | ```
617 | SELECT * FROM `table` WHERE `field` = 'value';
618 | ```
619 |
620 | ```
621 | SELECT `field1`, `field2`, `field3` FROM `table` WHERE `field1` > value;
622 | ```
623 |
624 | We can order our results using ORDER BY:
625 |
626 | ```
627 | SELECT * FROM `table` ORDER BY `id`;
628 | ```
629 |
630 | We can change the order using ASC or DESC:
631 |
632 | ```
633 | SELECT * FROM `table` WHERE `field` > 100 ORDER BY `time` ASC;
634 | ```
635 |
636 | We can limit the number of results returned using LIMIT:
637 |
638 | ```
639 | SELECT * FROM `table` ORDER BY `time` LIMIT 2;
640 | ```
641 |
642 | This will return the latest two records in the specified table
643 |
644 | We can specify an offset to start the LIMIT from:
645 |
646 | ```
647 | SELECT * FROM `table` ORDER BY `time` LIMIT 2, 2;
648 | ```
649 |
650 | This will return two records, starting from record 3
651 | (This is useful for pagination of results)
652 |
653 | We can combine conditions using AND and/or OR:
654 |
655 | ```
656 | SELECT
657 | `field1`, `field2`
658 | FROM
659 | `table`
660 | WHERE
661 | `field1` = 'lorem'
662 | AND
663 | `field2` > 12
664 | ORDER BY
665 | `time` ASC
666 | ```
667 |
668 | #### Joining multiple tables
669 |
670 | All of the SELECT examples so far have been on only a single table
671 |
672 | When we normalised the data, we specifically moved content into separate tables
673 |
674 | Now we need to know how to recombine it
675 |
676 | We need to add clauses to match the primary keys and foreign keys
677 |
678 | ***Answers table***
679 |
680 | | id | user_id | answer | date_added |
681 | |----|---------|---------------------------------------------- |---------------------|
682 | | 1 | 1 | lorem ipsum | 2013-03-21 18:34:23 |
683 | | 2 | 1 | quidquid Latine dictum sit altum videtur | 2013-03-21 19:32:17 |
684 | | 3 | 2 | Lorem ipsum dolor sit amet | 2013-03-21 20:31:25 |
685 | | 4 | 3 | quidquid Latine | 2013-03-21 21:32:17 |
686 | | 5 | 2 | ullamco laboris nisi ut aliquip ex ea commodo | 2013-03-21 22:31:25 |
687 |
688 |
689 | ***Users table***
690 |
691 | | id | handle | name |
692 | |----|----------------|------|
693 | | 1 | blah | Pete |
694 | | 2 | something | Nick |
695 | | 3 | dangerous | Mike |
696 |
697 |
698 | **SELECT with a join**
699 |
700 | ```
701 | SELECT
702 | *
703 | FROM
704 | `answers`
705 | JOIN
706 | `users`
707 | ON
708 | `answers`.`user_id` = `users`.`id`
709 | ```
710 |
711 | | id | user_id | answer | date_added | handle | name |
712 | |----|---------|-------------------------------------------------|---------------------|-----------------|------|
713 | | 1 | 1 | lorem ipsum | 2013-03-21 18:34:23 | blah | Pete |
714 | | 2 | 1 | quidquid Latine dictum sit altum videtur | 2013-03-21 19:32:17 | blah | Pete |
715 | | 3 | 2 | Lorem ipsum dolor sit amet | 2013-03-21 20:31:25 | something | Nick |
716 | | 4 | 3 | quidquid Latine | 2013-03-21 21:32:17 | dangerous | Mike |
717 | | 5 | 2 | ullamco laboris nisi ut aliquip ex ea commodo | 2013-03-21 22:31:25 | something | Nick |
718 |
719 |
720 | We can then add clauses, as before:
721 |
722 | ```
723 | SELECT
724 | *
725 | FROM
726 | `answers`
727 | JOIN
728 | `users`
729 | ON
730 | `answers`.`user_id` = `users`.`id`
731 | WHERE
732 | `users`.`id` = 1
733 | ```
734 |
735 | | id | user_id | answer | date_added | handle | name |
736 | |----|---------|-------------------------------------------------|---------------------|-----------------|------|
737 | | 1 | 1 | lorem ipsum | 2013-03-21 18:34:23 | blah | Pete |
738 | | 2 | 1 | quidquid Latine dictum sit altum videtur | 2013-03-21 19:32:17 | blah | Pete |
739 |
740 |
741 | #### SELECT without joins
742 |
743 | We could also recombine our data without explicitly using a JOIN
744 |
745 | Technically this is the same as an inner join, but the syntax is slightly different...
746 |
747 | ```
748 | SELECT
749 | *
750 | FROM
751 | `answers`, `users`
752 | WHERE
753 | `answers`.`user_id` = `users`.`id`
754 | ```
755 |
756 | #### Multiple tables in a query
757 |
758 | We have learnt how to query across multiple tables, by matching primary and foreign keys
759 |
760 | When we query across multiple tables, the attributes from each table are flattened into a single table
761 |
762 | There may be times when there are fields that we want to retrieve that have identical column names in more than one table (for example 'id')
763 |
764 | If we try to do this, it will only retrieve one of the named columns - the other won't be present in the results
765 |
766 | ```
767 | SELECT
768 | `questions`.`question`,
769 | `questions`.`id`,
770 | `answers`.`answer`,
771 | `answers`.`id`
772 | FROM
773 | `questions`,
774 | `answers`
775 | WHERE
776 | `questions`.`id` = `answers`.`question_id`
777 | ```
778 |
779 | To resolve this we use AS in our SQL to alias the field names to something else, to make them unique
780 |
781 | ```
782 | SELECT
783 | `questions`.`question`,
784 | `questions`.`id` AS `question_id`,
785 | `answers`.`answer`,
786 | `answers`.`id` AS `answer_id`
787 | FROM
788 | `questions`,
789 | `answers`
790 | WHERE
791 | `questions`.`id` = `answers`.`question_id`
792 | ```
793 |
794 | ***Further reading:***
795 |
796 | - [http://codular.com/sql-introduction](http://codular.com/sql-introduction)
797 | - [http://codular.com/mysql-joins](http://codular.com/mysql-joins)
798 | - [http://en.wikipedia.org/wiki/Join_(SQL)](http://en.wikipedia.org/wiki/Join_(SQL))
799 | - [http://www.keithjbrown.co.uk/vworks/mysql/mysql_p5.php](http://www.keithjbrown.co.uk/vworks/mysql/mysql_p5.php)
800 | - [http://www.coderecipes.net/sql-join-inner-join-left-join.aspx](http://www.coderecipes.net/sql-join-inner-join-left-join.aspx)
801 |
802 |
803 | #### Retrieving Random Results With MySQL
804 |
805 | You can select a random entry from a MySQL table using the SQL `RAND()` command
806 |
807 | Add `ORDER BY RAND() LIMIT 0,1` to the end of a query:
808 |
809 | ```
810 | SELECT * FROM `questions` ORDER BY RAND() LIMIT 0,1
811 | ```
812 |
813 | Could be useful for selecting a random question to feature on a page
814 |
815 |
816 | #### Grouping results
817 |
818 | If you wanted to select a list of all answers for each question, you could perform the following query:
819 |
820 | ```
821 | SELECT
822 | `questions`.`question` ,
823 | `answers`.`answer`
824 | FROM
825 | `questions` ,
826 | `answers`
827 | WHERE
828 | `questions`.`id` = `answers`.`question_id`
829 | ```
830 |
831 | This will produce the following results:
832 |
833 | | question | answer |
834 | |------------------|---------------|
835 | | Favourite Cheese | Edam |
836 | | Favourite Prince | Fresh |
837 | | Favourite Prince | TAFKAP |
838 | | Favourite Cheese | Melted cheese |
839 |
840 | This will repeat the question each time for each answer
841 |
842 | To group the answers together in a single column:
843 |
844 | ```
845 | SELECT
846 | `questions`.`question ,
847 | GROUP_CONCAT(`answers`.`answer` SEPARATOR ', ') AS `answer_list`
848 | FROM
849 | `questions` ,
850 | `answers`
851 | WHERE
852 | `questions`.`id` = `answers`.`question_id`
853 | GROUP BY `questions`.`id`
854 | ```
855 |
856 | This will produce the following results:
857 |
858 | | question | answer |
859 | |------------------|---------------------|
860 | | Favourite Cheese | Edam, Melted cheese |
861 | | Favourite Prince | Fresh, TAFKAP |
862 |
863 |
864 | If you want to perform complex queries on your database, it is also worth investigating different types of database joins and sub-queries
865 |
866 |
867 | #### Formatting A Date With MySQL
868 |
869 | We've been storing dates in MySQL using the 'date', 'time' and 'datetime' data types
870 |
871 | When these are retrieved from MySQL:
872 |
873 | ```
874 | SELECT `date_added` FROM `answers`;
875 | ```
876 |
877 | The output is in the format: "2012-02-27 15:20:29"
878 |
879 | If you want to format this you can use DATE_FORMAT
880 |
881 | ```
882 | SELECT DATE_FORMAT(`date_added`, '%e/%c/%y, %k:%i' AS `date_added_formatted` FROM `answers`;
883 | ```
884 |
885 | ***Further information:***
886 |
887 | - [http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_date-format](http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_date-format)
888 |
889 |
890 | ## Practice
891 |
892 | Try to write the SQL queries that would satisfy the following requests:
893 |
894 | - Select all questions
895 | - Select all answers for user 1
896 | - Select all answers ordered by date answered
897 | - Select all answers for question 1, including the username of the person who answered
898 | - Select all answers from category 1
899 | - Select all answers from the category 'funny'
900 | - Select all answers for question 1, including the username of the person who answered and its category
901 |
--------------------------------------------------------------------------------
/ux.md:
--------------------------------------------------------------------------------
1 | # UX notes
2 |
3 | A few notes prepared while writing training courses...
4 |
5 | ## What is UX?
6 |
7 | A typical project can be seen as a collaboration between business owners, users and designers/developers
8 |
9 | Typically in the past users weren't consulted in the process
10 |
11 | UX makes a project's focus user-centric - design for the users, understand the problem from their perspective
12 |
13 | UX's job is to ensure people can accomplish their goals when they come to a product
14 |
15 |
16 | ## Elements of UX
17 |
18 | There are the three key areas of UX:
19 |
20 |
21 | ### User research
22 |
23 | Identify users, carry out product testing
24 |
25 | Can be qualitative (interviews) or quantitative (surveys), behavioural (observations) or attitudinal (interviews)
26 |
27 |
28 | ### Information architecture
29 |
30 | Create and arrange content with the intent to communicate information
31 |
32 | Understand why a user is coming to your product, give the user the information they are looking for, help them make a decision
33 |
34 |
35 | ### Interaction design
36 |
37 | Creating a system's interactivity and functionality
38 |
39 |
40 | ## Usability
41 |
42 | There are five key areas of usability to consider:
43 |
44 | ### Learnability
45 |
46 | - How long does it take to use the product? It should be as easy to use as possible
47 | - People have come to do a specific task, help them to do this
48 | - Test it:
49 | - Set a task, measure how long it takes to complete
50 | - Compare it with competitors' websites...
51 |
52 |
53 | ### Efficiency
54 |
55 | - How well does the product do what it should do?
56 | - Is it consistent?
57 | - Does it use widely accepted standards/conventions?
58 | - Are there shortcuts for experienced users?
59 | - Does it prevent user errors? (e.g. forms, etc)
60 |
61 |
62 | ### Memorability
63 |
64 | - Does the product rely on a user's recognition or recall of how to use it?
65 | - Don't create a product that requires a user to remember things
66 | - Make the product do the work, not the user
67 |
68 |
69 | ### Error management
70 |
71 | - If the user encounters an error, alert them and tell them what to do
72 | - Catch and explain errors in a way that make sense to users
73 |
74 |
75 | ### Satisfaction
76 |
77 | - How satisfied is the user after using the product?
78 | - It may be different in different markets/contexts
79 | - You can only find this out through testing (e.g. A/B testing)
80 | - Test, learn, fix, (repeat)
81 |
82 |
83 | ## A project journey, from scoping to launch
84 |
85 | - Scoping
86 | - Research
87 | - Information Architecture
88 | - Design
89 | - Prototyping
90 | - Build, launch and handover
91 |
92 | ### (A caveat)
93 |
94 | - This is a simplification of the process
95 | - Not every project will go through these exact phases
96 | - Phases can take place concurrently
97 | - Phases many not take place in this order
98 | - Budget and time often dictate process
99 |
100 | It helps to keep a process Lean and Agile:
101 |
102 | - decide what you want to learn
103 | - build (a way of learning what you need to learn) and measure
104 | - iterate
105 |
106 |
107 | ## Scoping
108 |
109 | ### The brief
110 |
111 | Most projects start with a brief
112 |
113 | - "I want to sell my jewellery online..."
114 | - "I am organising an event..."
115 | - "My company needs a new website..."
116 | - "My new company needs a website..."
117 | - "I want to create the new Facebook..."
118 |
119 | No standard format, they come in all shapes and sizes
120 |
121 | - Formal or informal
122 | - Verbal or written
123 | - Technical or otherwise
124 | - etc...
125 |
126 | If the client doesn't supply you with a written brief, it is a good idea to request one
127 |
128 | It helps them to articulate, in their terms, what they require
129 |
130 | Their chosen format can help highlight their priorities
131 |
132 | This is often all the information you have when you decide whether to take a project on
133 |
134 | Even if you are building a website for yourself, and you think you know what you want, write yourself a brief
135 |
136 | It comes down to working out the most important requirements for the site
137 |
138 | To take a lean approach, it helps to decide what can go into your Minimum Viable Product (MVP)
139 |
140 |
141 | ### Requirements gathering
142 |
143 | Once we receive a client brief (and have decided to take it on) we need to create a set of requirements
144 |
145 | We need to understand why someone wants a website in the first place
146 |
147 | > "A requirement is a statement about an intended product that specifies what it should do or how to do it. For requirements to be effectively implemented and measured, they must be specific, unambiguous and clear."
148 | >
149 | > [http://usabilitygeek.com/requirements-gathering-user-experience-pt1/](http://usabilitygeek.com/requirements-gathering-user-experience-pt1/)
150 |
151 | We need to identify the key requirements of the site.
152 |
153 | For example:
154 |
155 | - To provide a service
156 | - To disseminate information
157 | - To sell products
158 | - To make money
159 | - etc...
160 |
161 | We make a list of everything the client wants the site to be able to do
162 |
163 | This helps to identify what functionality the site needs to offer.
164 |
165 | As a **user** I need to be able to:
166 |
167 | - Find the information I came to the site to read
168 | - Register/login
169 | - Personalise content
170 | - Order products
171 | - Share content
172 |
173 | As the **site owner** I need to be able to:
174 |
175 | - Add content
176 | - Review users' submissions
177 | - See statistics on how the site is being used
178 |
179 | Specifying needs in this way makes it possible to test the success of the website
180 |
181 | > "As a user I need to..."
182 |
183 | can be tested by changing the start of the sentence to:
184 |
185 | > "Is it possible to..."
186 |
187 | ***Further reading:***
188 |
189 | - [http://usabilitygeek.com/requirements-gathering-user-experience-pt1/](http://usabilitygeek.com/requirements-gathering-user-experience-pt1/)
190 | - [http://www.boxuk.com/requirements-gathering/](http://www.boxuk.com/requirements-gathering/)
191 |
192 | ### Scope of work
193 |
194 | A useful document to produce:
195 |
196 | - Shared and agreed by both the client and the project team
197 | - Documents the aims of the site - the requirements we discussed earlier
198 | - Describes the work to be done and what the end deliverable will be
199 | - Outlines the time schedule and budget
200 | - Outlines who is responsible for what (should something come from us or the client)
201 | - Lists assumptions and questions
202 |
203 | ***Further reading:***
204 |
205 | - [https://blog.udemy.com/scope-of-work-example/](https://blog.udemy.com/scope-of-work-example/)
206 | - [http://phuse.ca/how-to-write-a-scope-doc-for-a-web-project/](http://phuse.ca/how-to-write-a-scope-doc-for-a-web-project/)
207 |
208 |
209 | ## Research
210 |
211 | By analysing our brief, we have created a set of requirements that outline what our client would like the website to do
212 |
213 | We need to plan how our new website can meet these requirements
214 |
215 | The following steps are especially useful when working on large sites
216 |
217 | But they don't have to be complicated
218 |
219 | Even small simple sites can benefit from time spent on research
220 |
221 | How can we do this?
222 |
223 | - Client and team meetings
224 | - Client research
225 | - Competitor analysis
226 | - Audience research
227 | - Analytics review
228 | - User personas and user stories
229 |
230 |
231 | ### Meetings
232 |
233 | - Regular client meetings are important to demonstrate progress
234 | - Gather further information and feedback
235 | - We probably won't have the perfect solution immediately
236 | - Discuss potential ideas
237 | - Requirements may change over time
238 | - It should be an iterative agile process
239 |
240 | ***Further reading:***
241 |
242 | - [http://alistapart.com/article/kick-ass-kickoff-meetings](http://alistapart.com/article/kick-ass-kickoff-meetings)
243 | - [http://alistapart.com/article/gettingrealaboutagiledesign](http://alistapart.com/article/gettingrealaboutagiledesign)
244 |
245 |
246 | ### Client research
247 |
248 | Research the client, the company, the sector
249 |
250 | Conduct stakeholder interviews to reveal their requirements
251 |
252 | These may be formal or informal, individually or in groups
253 |
254 | Stakeholder questions to cover:
255 |
256 | - The company's focus
257 | - What products they sell or services they provide
258 | - Aims and goals for the new website
259 | - The current website - likes and dislikes
260 | - Target audience
261 | - Branding
262 | - Content
263 | - Similar websites
264 |
265 | ***Further reading:***
266 |
267 | - [http://www.uxmatters.com/mt/archives/2007/09/conducting-successful-interviews-with-project-stakeholders.php](http://www.uxmatters.com/mt/archives/2007/09/conducting-successful-interviews-with-project-stakeholders.php)
268 | - [http://boxesandarrows.com/a-stakeholder-interview-checklist/](http://boxesandarrows.com/a-stakeholder-interview-checklist/)
269 |
270 |
271 | ### Competitor Analysis
272 |
273 | Look at similar websites and services
274 |
275 | - What do they do well
276 | - What can we improve on
277 | - What ideas can we 'borrow'
278 |
279 | We're looking for a USP
280 |
281 | We want to know how to position our website in the market
282 |
283 | ***Further reading:***
284 |
285 | - [http://www.gfk.com/solutions/ux/our-products/ux-strategy/Pages/Benchmarking-Competitive-Analysis.aspx](http://www.gfk.com/solutions/ux/our-products/ux-strategy/Pages/Benchmarking-Competitive-Analysis.aspx)
286 | - [http://www.inc.com/guides/2010/05/conducting-competitive-research.html](http://www.inc.com/guides/2010/05/conducting-competitive-research.html)
287 | - [http://danforthmedia.com/pages/2014/03/01/conducting-a-solid-ux-competitive-analysis/](http://danforthmedia.com/pages/2014/03/01/conducting-a-solid-ux-competitive-analysis/)
288 |
289 |
290 | ### Audience research
291 |
292 | Find out who is the target audience, and what they want
293 |
294 | Speak to potential users
295 |
296 | Find out their desires and requirements
297 |
298 | There are lots of different types of user research you can conduct:
299 |
300 | - Qualitative interviews
301 | - Focus groups
302 | - Quantitative statistics - e.g. surveys, analytics
303 | - Observing users interacting with websites - e.g. [silverbackapp.com](http://silverbackapp.com)
304 | - Card sorting - e.g. [www.optimalworkshop.com/optimalsort.htm](http://www.optimalworkshop.com/optimalsort.htm)
305 |
306 | Each of these techniques has its own pros and cons
307 |
308 | A combination of techniques will help identify requirements for the site
309 |
310 | You can decide which techniques to employ based on budget, timescale, personnel, etc
311 |
312 | ***Further reading:***
313 |
314 | - [http://uxdesign.smashingmagazine.com/2013/09/23/5-step-process-conducting-user-research/](http://uxdesign.smashingmagazine.com/2013/09/23/5-step-process-conducting-user-research/)
315 | - [http://www.usability.gov/what-and-why/user-research.html](http://www.usability.gov/what-and-why/user-research.html)
316 | - [http://uxmastery.com/better-user-research-through-surveys/](http://uxmastery.com/better-user-research-through-surveys/)
317 | - [http://www.smashingmagazine.com/2012/08/29/beyond-wireframing-real-life-ux-design-process/](http://www.smashingmagazine.com/2012/08/29/beyond-wireframing-real-life-ux-design-process/)
318 |
319 |
320 | ### Analytics review
321 |
322 | If the client has an existing website, reviewing its analytics can be revealing
323 |
324 | It can help to identify where they are meeting (or failing to meet) the requirements you have identified
325 |
326 | Many different areas to review:
327 |
328 | - Page views
329 | - Browsing time
330 | - Journeys through the site
331 | - Traffic sources
332 | - Bounce rates and page exit rates
333 | - Browser/Device usage
334 |
335 | ***Further reading:***
336 |
337 | - [http://theuxreview.co.uk/google-analytics-the-beginners-guide/](http://theuxreview.co.uk/google-analytics-the-beginners-guide/)
338 | - [http://www.nngroup.com/articles/analytics-user-experience/](http://www.nngroup.com/articles/analytics-user-experience/)
339 | - [http://www.nngroup.com/articles/analytics-reports-ux-strategists/](http://www.nngroup.com/articles/analytics-reports-ux-strategists/)
340 |
341 |
342 | ### User personas
343 |
344 | User personas are short descriptions of fictional characters who represent the website's potential users
345 |
346 | They should be based on audience research, modelled by grouping results into similar types
347 |
348 | Personas should contain core details
349 |
350 | - The user's goals when using the website
351 | - Aptitude and technical ability (in general, and website-specific)
352 |
353 | Basic persona details are often supplemented with further information:
354 |
355 | - The user's chosen technology/devices
356 | - Demographic information - age/gender/location
357 | - Professional information - career/experience
358 | - A background bio
359 | - etc
360 |
361 | Some example personas:
362 |
363 | - [http://www.steptwo.com.au/papers/kmc_personas](http://www.steptwo.com.au/papers/kmc_personas)
364 | - [http://alistapart.com/article/personality-in-design](http://alistapart.com/article/personality-in-design)
365 |
366 | User personas help to:
367 |
368 | - Focus on the needs of a specific type of user
369 | - Communicate the views of different types of user
370 | - Identify user journeys and user stories
371 |
372 | User personas
373 |
374 | - Naming is hard, so we sometimes use a random persona generator
375 | - Personas are best kept simple unless in-depth detail is required
376 | - Additional personas can be created during a project if requirements change
377 |
378 | ***Further reading:***
379 |
380 | - [http://theuxreview.co.uk/personas-the-beginners-guide/](http://theuxreview.co.uk/personas-the-beginners-guide/)
381 | - [http://www.sitepoint.com/create-data-backed-personas/](http://www.sitepoint.com/create-data-backed-personas/)
382 | - [http://www.smashingmagazine.com/2014/08/06/a-closer-look-at-personas-part-1/](http://www.smashingmagazine.com/2014/08/06/a-closer-look-at-personas-part-1/)
383 |
384 |
385 | ### User stories
386 |
387 | A user story is a sentence that encapsulates a required piece of functionality, in the language of the user
388 |
389 | Earlier, we noted the need to capture all site requirements
390 |
391 | Every site requirement could be restructured into individual user stories
392 |
393 | Each story can be attributed to the most appropriate user persona
394 |
395 | > We need to add an e-commerce solution
396 |
397 | *becomes*
398 |
399 | > As Jack I can buy a ticket so that I can go to the gig
400 |
401 | Creating user stories puts the user at the centre of the experience
402 |
403 | This is a good way to prioritise requirements
404 |
405 | If a requirement doesn't match any persona it may require a new persona, or it may not be as important as first thought
406 |
407 | #### Format
408 |
409 | User stories often follow a standard format:
410 |
411 | > As *[Persona]*
412 | > I can *[Goal]*
413 | > So that *[Benefit]*
414 |
415 | The example we saw earlier follows this pattern:
416 |
417 | > As *Jack*
418 | > I can *buy a ticket*
419 | > So that I can *go to the gig*
420 |
421 | User stories are particularly useful if you are using an agile process
422 |
423 | You create a backlog of stories, and prioritise them
424 |
425 | Each sprint you select a set of stories to work on
426 |
427 | Managing stories is important
428 |
429 | Stories can be written on cards and stuck onto a wall
430 |
431 | To aid collaboration we often use software to manage stories
432 |
433 | Trello is a good simple solution for creating and managing stories
434 |
435 | (More complex solutions exist, but they're less friendly to inexperienced users)
436 |
437 | ***Further reading:***
438 |
439 | - [https://medium.com/@jonatisokon/a-framework-for-user-stories-bc3dc323eca9](https://medium.com/@jonatisokon/a-framework-for-user-stories-bc3dc323eca9)
440 | - [http://trailridgeconsulting.com/files/user-story-primer.pdf](http://trailridgeconsulting.com/files/user-story-primer.pdf)
441 |
442 |
443 | ## Information Architecture
444 |
445 | We have gained a good understanding of the website's requirements
446 |
447 | Now we need to plan how the website can meet these requirements
448 |
449 | As with research, the following steps are especially useful when working on large complex sites
450 |
451 | Small simple sites will still benefit from time spent on Information Architecture prior to design and build
452 |
453 | Complex information architecture documents can take a great deal of time, without leading you closer to producing the product. So don't get stuck on wireframes for a great deal of time. Move into code as soon as possible
454 |
455 | The lower the definition, the better the discussion/feedback
456 |
457 | ***Further reading:***
458 |
459 | - [https://bigmedium.com/ideas/only-one-deliverable-matters.html](https://bigmedium.com/ideas/only-one-deliverable-matters.html)
460 |
461 |
462 | ### Content
463 |
464 | Content should inform decisions about website architecture
465 |
466 | Think about the purpose of the page, and therefore what information people should notice first
467 |
468 | It is difficult to structure a page around lorem ipsum text
469 |
470 | Content can't just be dropped in at the last minute
471 |
472 | Working with a content-first approach ensures the site architecture and design will be fit for purpose
473 |
474 |
475 | #### Content audits
476 |
477 | It may be helpful to carry out of a content audit to assess and categorise existing content
478 |
479 | Review existing content to prioritise and categorise
480 |
481 | This should be cross-referenced with any available analytics and site requirements.
482 |
483 | ***Further reading:***
484 |
485 | - [http://responsivedesign.is/design/content-first-design](http://responsivedesign.is/design/content-first-design)
486 | - [http://www.markboulton.co.uk/journal/structure-first-content-always](http://www.markboulton.co.uk/journal/structure-first-content-always)
487 | - [https://blog.gathercontent.com/designing-content-first-for-a-better-ux](https://blog.gathercontent.com/designing-content-first-for-a-better-ux)
488 | - [http://alistapart.com/article/the-core-model-designing-inside-out-for-better-results](http://alistapart.com/article/the-core-model-designing-inside-out-for-better-results)
489 | - [http://uxmastery.com/how-to-conduct-a-content-audit/](http://uxmastery.com/how-to-conduct-a-content-audit/)
490 | - [http://www.adaptivepath.com/ideas/doing-content-inventory/](http://www.adaptivepath.com/ideas/doing-content-inventory/)
491 |
492 |
493 | ### Sitemaps
494 |
495 | Most clients know what kind of content they want already
496 |
497 | We need to organise content into a logical structure that is easy to navigate
498 |
499 | - A way to document the structure of a website
500 | - Easily see a list of sections/pages of a website
501 | - Hierarchical - shows how pages relate to one another
502 | - Identify the different templates/layouts that will be used
503 | - Doesn't contain visual detail or information on the layouts themselves
504 |
505 | ***Further reading:***
506 |
507 | - [http://theuxreview.co.uk/sitemaps-the-beginners-guide/](http://theuxreview.co.uk/sitemaps-the-beginners-guide/)
508 | - [http://viget.com/inspire/ux-101-the-site-map](http://viget.com/inspire/ux-101-the-site-map)
509 | - [http://www.smashingmagazine.com/2013/12/03/efficiently-simplifying-navigation-information-architecture/](http://www.smashingmagazine.com/2013/12/03/efficiently-simplifying-navigation-information-architecture/)
510 |
511 |
512 | ### Wireframes
513 |
514 | Plan the placement of content on each page
515 |
516 | Organise the importance of each element within a page - the information hierarchy
517 |
518 | Decide what we want the user to experience first, second, third, etc. based on its prominence within the page.
519 |
520 | Create ideas, so it's easy to move things about
521 |
522 | Not looking at the visual layout of the site
523 |
524 | - [http://viget.com/inspire/ux-101-the-wireframe1](http://viget.com/inspire/ux-101-the-wireframe1)
525 | - [http://theuxreview.co.uk/wireframes-beginners-guide/](http://theuxreview.co.uk/wireframes-beginners-guide/)
526 |
527 |
528 | ### User journeys
529 |
530 | User journeys identify how users flow through your website
531 |
532 | They help you to design the structure to ensure users can complete their goal efficiently
533 |
534 | User journeys make use of the user personas and user stories (discussed during the research phase)
535 |
536 | Mapping the user journey of a user story helps to validate your selected site structure
537 |
538 | They also help to identify any potential pain points in the journey
539 |
540 | You could create a user journey for every user story
541 |
542 | This would allow you to test your assumptions and solutions
543 |
544 | There is no standard format for creating user journeys
545 |
546 | They can look more varied than wireframes/sitemaps
547 |
548 | ***Further reading:***
549 |
550 | - [http://theuxreview.co.uk/user-journeys-beginners-guide/](http://theuxreview.co.uk/user-journeys-beginners-guide/)
551 | - [http://cargocollective.com/ameliabauerly/User-Flow-Example](http://cargocollective.com/ameliabauerly/User-Flow-Example)
552 | - [http://www.adaptivepath.com/ideas/the-anatomy-of-an-experience-map/](http://www.adaptivepath.com/ideas/the-anatomy-of-an-experience-map/)
553 | - [http://www.ux-lady.com/experience-maps-user-journey-and-more-exp-map-layout/](http://www.ux-lady.com/experience-maps-user-journey-and-more-exp-map-layout/)
554 |
555 |
556 | ## Design
557 |
558 | At this stage we should now understand our brief, and its key requirements
559 |
560 | We should have come up with a plan for what we want to create
561 |
562 | ### Design fundamentals
563 |
564 | When designing a product - magazine, book, website, etc - there isn't a right or wrong way to do it
565 |
566 | There are considerations to take into account
567 |
568 | And there are definitely things to avoid
569 |
570 | Designing things properly is a difficult, skilled process
571 |
572 | > "I've got a hard afternoon ahead of choosing fonts and colours"
573 |
574 | Good design is about creating a balance between the different elements on a page
575 |
576 | Sticking to a set of recognised design guidelines can help to control the layout of the various components
577 |
578 | It can help to present information in a way that's simple, attractive and appropriate
579 |
580 | When creating any new design, it is important to bear in mind:
581 |
582 | - Usability *(Is it easy to use?)*
583 | - Functionality *(Can I do everything I want to?)*
584 | - Effective *(Is information presented in a useful way?)*
585 | - Efficiency *(Is it quick to navigate and find information?)*
586 | - Aesthetic *(Does it look good?)*
587 | - Cohesive *(Do all pages of the site share common design/layout elements?)*
588 |
589 | *Design is a balance*
590 |
591 | If a website works well but doesn't look good, people won't want to use it
592 |
593 | If a website is beautiful but isn't usable or accessible, people won't want to use it
594 |
595 | > "We stand out by looking to tomorrow instead of simply referencing the design trends of today.
596 | > We strike a balance between cookie-cutter design and beautiful anarchy."
597 | >
598 | > - BBC Gel Guidelines (Global Experience Language)
599 | > [http://www.bbc.co.uk/gel](http://www.bbc.co.uk/gel)
600 |
601 |
602 | ### Branding
603 |
604 | A client's brand can be thought of as their identity
605 |
606 | Usually branding refers to the logo, choice of colours, fonts, etc
607 |
608 | A brand should target the intended audience
609 |
610 | Consistent strong branding helps to increase recognition
611 |
612 | Strong brands help to win and retain users
613 |
614 | People know what to expect with recognisable brands
615 |
616 | They are more than just logos - a brand is a way to represent all of their associations, experiences and characteristics
617 |
618 | The tone of voice of the writing is important
619 |
620 | The choice and use of appropriate imagery also helps to emphasise brand values
621 |
622 | Many large companies and organisations produce their own brand guidelines to describe how designs using their logo should be produced
623 |
624 | > "our logo is the face of our brand and a key element of our brand identity. Consistent use of the logo is essential to maintaining our identity and gaining instant recognition across all marketing channels and media"
625 | >
626 | > Best buy
627 | > [http://bbybrandidentity.com/guidelines-bby/brand-overview/](http://bbybrandidentity.com/guidelines-bby/brand-overview/)
628 |
629 | > "Our logo is a very valuable asset. We must treat it nicely. Never abuse our logo, it doesn't have arms so it can't fight back (our lawyers however, are another story)."
630 | >
631 | > Skype
632 | > [http://issuu.com/bondo/docs/skype_brand_book_-_look](http://issuu.com/bondo/docs/skype_brand_book_-_look)
633 |
634 | > "Do's and don'ts. You wouldn't wear one blue and one orange sock. Take a moment to think about how you apply the Skype logo."
635 | >
636 | > Skype
637 | > [http://issuu.com/bondo/docs/skype_brand_book_-_look](http://issuu.com/bondo/docs/skype_brand_book_-_look)
638 |
639 |
640 | ***Further reading:***
641 |
642 | - [http://www.easy.com/PDFs/easyGroup_Brand_Manual.pdf](http://www.easy.com/PDFs/easyGroup_Brand_Manual.pdf)
643 | - [http://www.penguin.com.au/logo-guidelines](http://www.penguin.com.au/logo-guidelines)
644 | - [http://www.nhsidentity.nhs.uk/all-guidelines/guidelines/national-organisations/websites](http://www.nhsidentity.nhs.uk/all-guidelines/guidelines/national-organisations/websites)
645 | - [http://www.webdesignerdepot.com/2009/05/9-tips-for-brand-building-with-web-design/](http://www.webdesignerdepot.com/2009/05/9-tips-for-brand-building-with-web-design/)
646 | - [http://imjustcreative.com/bulging-sack-of-brand-identity-guideline-resources/2011/10/05](http://imjustcreative.com/bulging-sack-of-brand-identity-guideline-resources/2011/10/05)
647 |
648 |
649 | ### Layout and composition
650 |
651 | People expect consistency in a design
652 |
653 | Consistency and predictability in design allow people to feel safe and confident as they navigate
654 |
655 | It reduces cognitive load for visitors, allowing them to focus on the content of a site
656 |
657 | Having a consistent and predictable layout means that when something does not follow the predefined pattern, it will stand out
658 |
659 | This is particularly useful if there is a specific part of the page you want to highlight
660 |
661 | The best way to create a consistent and predictable layout is with a grid
662 |
663 |
664 | #### Grids
665 |
666 | Grids go a long way towards ensuring that a layout is consistent.
667 |
668 | Grids constrain a design, providing order and structure to information
669 |
670 | There are two parts to any grid:
671 |
672 | - Columns
673 | - Gutters
674 |
675 | ##### Columns
676 |
677 | Columns represent the each major piece of a grid.
678 |
679 | When attaching items to a grid, they are attached to a whole column, or multiple columns (which would then include gutters).
680 |
681 | ##### Gutters
682 |
683 | Gutters are the space between each column
684 |
685 | Content is never aligned to a gutter
686 |
687 | Each gutter is the same width
688 |
689 | ##### Composition
690 |
691 | The most common type of grid is a symmetric grid (where each column is the same size)
692 |
693 | Looking at successful websites, even those with a huge number of pages, often showcases that there are only a few layouts
694 |
695 | It is a good idea to use as few page layouts as possible, and especially few complex layouts
696 |
697 | This makes it easier for people to understand, and easier to maintain
698 |
699 | ([http://www.fabricland.co.uk/](http://www.fabricland.co.uk/))
700 |
701 |
702 | ##### White space
703 |
704 | White space (or "negative space") refers to any area of a page that doesn't contain text or imagery
705 |
706 | It is possible to fill every part of a web page with content, but leaving white space on a page is important
707 |
708 | Without white space, designs can feel crowded
709 |
710 | White space helps people differentiate between different parts of a page
711 |
712 | Less is more is a good design principle
713 |
714 | Don't cram too much content into one page, it can be overwhelming - keep it simple and uncluttered
715 |
716 | ([http://www.lingscars.com/](http://www.lingscars.com/))
717 |
718 |
719 | ##### Components
720 |
721 | As experienced web users, we are used to a number of layout conventions:
722 |
723 | - Header
724 | - Navigation
725 | - Content
726 | - Footer
727 | - (etc)
728 |
729 | We expect specific functionality to be in certain parts of a page:
730 |
731 | - search - top right
732 | - login/register - top right
733 | - about us / contact us / T&Cs - footer link
734 | - store locator - top right / footer link
735 |
736 | > "For generations, humans have used conversation to pass down stories and learn about the world. Leverage this tradition. Instead of providing all information at once, allow a user to explore through the content, inviting conversation with them. This is often referred to as Progressive Disclosure. Respond to users as they ask for more information, don't throw it all at them at once. Focus on one item at a time and push secondary items off to the sides, waiting for user interaction."
737 | >
738 | > [https://github.com/north/north#visual-design](https://github.com/north/north#visual-design)
739 |
740 | ***Further reading:***
741 |
742 | - [http://www.thegridsystem.org/](http://www.thegridsystem.org/)
743 | - [http://www.smashingmagazine.com/2010/04/29/grid-based-web-design-simplified/](http://www.smashingmagazine.com/2010/04/29/grid-based-web-design-simplified/)
744 | - [http://www.smashingmagazine.com/2007/04/14/designing-with-grid-based-approach/](http://www.smashingmagazine.com/2007/04/14/designing-with-grid-based-approach/)
745 | - [http://www.markboulton.co.uk/journal/five-simple-steps-to-designing-grid-systems-part-1](http://www.markboulton.co.uk/journal/five-simple-steps-to-designing-grid-systems-part-1)
746 |
747 |
748 | ### Typography
749 |
750 | Type styling is an important factor in communicating meaning and hierarchy across the design.
751 |
752 | It is an incredibly complex (and engrossing) subject
753 |
754 | We will briefly cover just a few of the essentials...
755 |
756 |
757 | #### Tone
758 |
759 | Different types of font can represent a different tone of voice
760 |
761 | Fonts have characteristics that can portray a range of connotations about a brand
762 |
763 | Select a font that helps to convey the brand values (that we discussed earlier!)
764 |
765 | Use weight, size and colour of type to create a hierarchy
766 |
767 | It is also possible to control how the space around a font is rendered with kerning and leading
768 |
769 |
770 | #### Fonts
771 |
772 | Up until a few years ago we used to be limited to a small set of 'web-safe' fonts
773 |
774 | Thankfully in the last couple of years new browser technology has enabled us to embed almost any font into a website
775 |
776 | Services like Google Fonts allow us to use a huge range of fonts - for free!
777 |
778 | > "Use typography to create a hierarchy of content across the site"
779 | > - BBC GEL
780 |
781 | > "Large bold type should be used to establish a clear information hierarchy"
782 | > - BBC GEL
783 |
784 | > "Typography built around clarity and uniformity, designed to be legible in a range of sizes"
785 | > - Best Buy
786 |
787 |
788 | > "Our font is compatible across all computing platforms and systems"
789 | > - Best Buy
790 |
791 |
792 | > "Words don't just hold meaning; they communicate by their very form. We primarily use the Gotham font family: elegant and direct, stylish but not exclusive. Putting well-designed words in our product enhances the user experience"
793 | > - Twitter
794 | > [https://about.twitter.com/press/brand-assets](https://about.twitter.com/press/brand-assets)
795 |
796 | ***Further reading:***
797 |
798 | - [http://bonfx.com/typography-primer-all-you-need-to-know-in-one-pdf/](http://bonfx.com/typography-primer-all-you-need-to-know-in-one-pdf/)
799 | - [http://coding.smashingmagazine.com/2011/03/14/technical-web-typography-guidelines-and-techniques/](http://coding.smashingmagazine.com/2011/03/14/technical-web-typography-guidelines-and-techniques/)
800 |
801 |
802 | ### Colour
803 |
804 | Choosing a colour-palette for a website is not simple
805 |
806 | Selecting a limited number of recurring colours can give a website cohesion
807 |
808 | There is a lot to consider:
809 |
810 | - Aesthetics
811 | - Identity
812 | - Usability
813 |
814 |
815 | Colour theory:
816 |
817 | - Analogous
818 | - Complimentary
819 | - Shades
820 | - (etc)
821 |
822 | [https://kuler.adobe.com/](https://kuler.adobe.com/)
823 |
824 |
825 | > "Our colour palette contains a range of related tones to add nuance, depth and dimension for a more engaging consumer experience"
826 | > - Best buy
827 |
828 | > "Always ensure that there is enough contrast between the text and the background colour"
829 | > - BBC GEL
830 |
831 | > "Our colours are what give us our personality. We're bright, bold, colourful and confident. They're simply loud and clear"
832 | > - Skype
833 |
834 |
835 | ***Further reading:***
836 |
837 | - [http://webdesign.tutsplus.com/articles/an-introduction-to-color-theory-for-web-designers--webdesign-1437](http://webdesign.tutsplus.com/articles/an-introduction-to-color-theory-for-web-designers--webdesign-1437)
838 | - [http://www.smashingmagazine.com/2010/01/28/color-theory-for-designers-part-1-the-meaning-of-color/](http://www.smashingmagazine.com/2010/01/28/color-theory-for-designers-part-1-the-meaning-of-color/)
839 |
840 |
841 | ### Design inspiration
842 |
843 | Look at other websites for inspiration
844 |
845 | - [http://mediaqueri.es/](http://mediaqueri.es/)
846 | - [http://dribbble.com/](http://dribbble.com/)
847 | - [http://www.siteinspire.com/](http://www.siteinspire.com/)
848 | - [http://www.awwwards.com/](http://www.awwwards.com/)
849 |
850 |
851 | ### Style tiles
852 |
853 | Prior to starting on a site design, consider creating a style tile
854 |
855 | They provide a way to demonstrate fonts, colours and interface/layout ideas
856 |
857 | They're a catalyst for discussion
858 |
859 | ***Further reading:***
860 |
861 | - [http://alistapart.com/article/style-tiles-and-how-they-work](http://alistapart.com/article/style-tiles-and-how-they-work)
862 | - [http://styletil.es/](http://styletil.es/)
863 |
864 |
865 | ### Responsive design
866 |
867 | Designing websites to work across a wide range of devices and browsers
868 |
869 | We can no longer assume that most people primarily use a desktop or laptop computer to browse the internet
870 |
871 | People use a variety of internet browsers and operating systems
872 |
873 | These devices are increasingly being used in place of 'traditional' desktop browsers
874 |
875 | We also can't assume the context of why people use a mobile device rather than a desktop device
876 |
877 | Traditionally it was thought that people browsing the web via their phone were 'on the move', needing quick access to information, and so many mobile websites were optimised for this
878 |
879 | But research shows that people are just as likely to use their mobile phones at home while watching television
880 |
881 | We can't assume people's requirements based purely on the device they use to access our websites
882 |
883 | #### Responsible responsive design
884 |
885 | We should ensure that our websites work across all commonly used desktop browsers
886 |
887 | We should take non-desktop browsers/devices into consideration when building a website
888 |
889 | These devices have different display resolutions (or browser dimensions)
890 |
891 | These devices also have different methods of interaction
892 |
893 | Responsive patterns are important
894 |
895 | Users may expect different behaviour at different viewport dimensions
896 |
897 | ***Further reading:***
898 |
899 | - [http://bradfrost.github.io/this-is-responsive/](http://bradfrost.github.io/this-is-responsive/)
900 | - [http://patternlab.io/](http://patternlab.io/)
901 | - [http://mediaqueri.es/](http://mediaqueri.es/)
902 | - [http://alistapart.com/article/responsive-web-design](http://alistapart.com/article/responsive-web-design)
903 | - [http://www.abookapart.com/products/mobile-first](http://www.abookapart.com/products/mobile-first)
904 |
905 |
906 | ## Prototyping
907 |
908 | ### What is prototyping?
909 |
910 | The creation of experiments
911 | Usability testing
912 | Allow us to test whether our ideas will work
913 |
914 | > It took 5,127 prototypes for James Dyson to get cyclone technology exactly right for his vacuum cleaner
915 |
916 | Prototypes are typically interactive (clickable) wireframes/designs
917 |
918 |
919 | ### When do we prototype?
920 |
921 | Prototyping often take place during the Design and Build phases
922 |
923 | Innovative design ideas need testing with real users to test whether they work
924 |
925 | Increasingly this is happening publicly
926 |
927 |
928 | ### Why do we prototype?
929 |
930 | An anecdote:
931 |
932 | > "I have an idea for a website, now I'm going to spend a year learning to code so that I can build it!"
933 |
934 | A year before you can test your ideas with potential customers?
935 |
936 | Instead, we can create a quick prototype to validate (or change) our ideas
937 |
938 | Building a website is complex, and time-intensive.
939 |
940 | Building the wrong thing is a waste of time and money.
941 |
942 | - Demonstrate ideas
943 | - Test complex interactive solutions
944 | - Receive quick feedback
945 | - Refine ideas iteratively
946 | - Efficiency - quick update process
947 |
948 |
949 | ### How do we prototype?
950 |
951 | We want to create a simple website without any technical knowledge
952 |
953 | There are plenty of tools available - [http://prototypingtools.co/](http://prototypingtools.co/)
954 |
955 | There are two main types of prototyping tools:
956 |
957 | - Build prototypes by dragging and dropping elements from a toolbox
958 | - Use your own sketches or images, link these together with hotspots
959 |
960 |
961 | ***Further reading:***
962 |
963 | - [http://alistapart.com/article/paperprototyping](http://alistapart.com/article/paperprototyping)
964 | - [http://stephenmeszaros.com/posts/getting-started-with-prototyping.html](http://stephenmeszaros.com/posts/getting-started-with-prototyping.html)
965 |
966 |
967 | ## Build
968 |
969 | The site has been designed
970 |
971 | developers have taken over
972 |
973 | Is the UX designer's job done?
974 |
975 | ...not quite
976 |
977 | These aren't discrete stages
978 |
979 | With responsive design, collaboration between designer and developer is vital
980 |
981 | It is an iterative process
982 |
983 | The designer may be needed until the site build is completed
984 |
985 | ***Further reading:***
986 |
987 | - [http://alistapart.com/article/client-education-and-post-launch-success](http://alistapart.com/article/client-education-and-post-launch-success)
988 |
989 |
--------------------------------------------------------------------------------
/php.md:
--------------------------------------------------------------------------------
1 | # PHP notes
2 |
3 | A few notes prepared while writing training courses...
4 |
5 |
6 | ## Overview
7 |
8 | ### Server-side processing
9 |
10 | When you visit (or request) a URL in your browser, there's a lot going on behind the scenes to render the page you see
11 |
12 | There are several steps to the rendering process, before the page you see is generated
13 |
14 | Various different technologies and languages serve specific roles in this process
15 |
16 | The rendering process can be split into two distinct categories, those on the client-side and those on the server-side
17 |
18 | - *Servers* are computers used to store data and host/generate web pages
19 | - *Clients* are computers distributed around the network that use the services provided by servers - typically a user's machine
20 |
21 | For example, a web browser is a program on a user's computer that requests data from a web server.
22 |
23 | - *Server-side processing* - takes place on the server
24 | - *Client-side processing* - takes place on your own machine
25 |
26 |
27 | ### Programming & Markup
28 |
29 | A markup language (e.g. HTML) is static - it is used to dictate the appearance and format of the displayed information
30 |
31 | A programming language (e.g. PHP, JavaScript) is dynamic - it is used to perform specific tasks/actions such as filtering or manipulating data
32 |
33 |
34 | ### PHP
35 |
36 | PHP is just one of many languages that can be used for server-side programming
37 |
38 | It is widely available on web servers
39 |
40 | There are plenty of books and online documentation to aid your learning
41 |
42 | Lots of third-party resources - PHP scripts written by others freely available online
43 |
44 | In use on numerous big websites
45 |
46 |
47 | ### Getting started
48 |
49 | PHP needs to be run (parsed) by a web server
50 |
51 | If you open a PHP file in a web browser directly, you'll see the unprocessed code
52 |
53 | You need to run PHP scripts through a web server (typically Apache), the server will process the code and output the results
54 |
55 | Luckily, installation is easy. These can be installed separately, or together using something like WAMP, MAMP etc
56 |
57 | Apache is a continually running process on the server - think of it as a computer program that you never close
58 |
59 | Most web servers run a version of Linux. There are a number of advantages to Linux servers (over for example Windows-based servers). The most important one is that it's free!
60 |
61 |
62 | ### Advantages of server-side processing
63 |
64 | Imagine having a website made up of static HTML pages
65 |
66 | - To edit any information you need HTML skills
67 | - To update the page structure, you need to do it in every file
68 | - You can't re-use the data anywhere else
69 | - You can't manipulate the data, e.g. To extract just the page titles as a list of links
70 |
71 | It makes sense to separate out data and logic from the presentation
72 |
73 | - Easier to manage any one aspect without having to touch the others
74 | - Separation of concerns
75 | - Data can be re-used elsewhere
76 | - Only have to have one 'template' file that contains how the content will be rendered
77 | - Data can be edited using a simple form - no HTML knowledge required
78 |
79 | A few more reasons why server-side processing is useful:
80 |
81 | - Automate monotonous tasks: e.g. adding a date entry select from 1900 to 201x:
82 |
83 | ```
84 | 1900
85 | 1901
86 | 1902
87 | ```
88 |
89 | - No way to automatically put today's date in to a web page
90 | - No way to automate tasks or generate content
91 | - File includes - the earliest form of server-side scripting (e.g. storing repetitive content in a separate file so you only need to write it once)
92 | - Display specific content only if certain conditions are met
93 | - Process the information entered into an HTML form
94 | - It can send emails
95 | - It can read and write files on the web server
96 | - It can read web pages (sometimes known as screen or data scraping)
97 | - It can interact with other web services through APIs
98 |
99 | etc... hopefully by now you've been convinced by the advantages of using a server-side language
100 |
101 |
102 | ## Fundamentals
103 |
104 | ### Getting started
105 |
106 | PHP code is identified by being placed within specific script tags:
107 |
108 | ```
109 |
114 | ```
115 |
116 | How to start using PHP:
117 |
118 | - Create a new file
119 | - Give it a file extension of .php (e.g. index.php)
120 | - (Or, change an existing file from .html to .php)
121 | - Write some PHP code within the tags
122 | - View the public URL in a browser
123 |
124 | PHP code can be freely interspersed with normal HTML.
125 |
126 | The PHP interpreter on the server reads the instructions and generates HTML that is sent to the browser
127 |
128 | A static HTML file might look like this:
129 |
130 | ```
131 |
132 |
133 |
134 | The day today
135 |
136 |
137 | What day is it today?
138 |
139 |
140 | ```
141 |
142 | Add some PHP:
143 |
144 | ```
145 |
146 |
147 |
148 | The day today
149 |
150 |
151 | What day is it today?
152 |
153 |
156 |
157 |
158 |
159 | ```
160 |
161 | The server will interpret this PHP and generate:
162 |
163 | ```
164 |
165 |
166 |
167 | The day today
168 |
169 |
170 | What day is it today?
171 |
172 | Friday
173 |
174 |
175 |
176 | ```
177 |
178 | Some rules to note immediately:
179 |
180 | - When ending a PHP command, ensure you use a semi-colon to avoid an error (more on this later)
181 | - The `echo` command is used to insert content into the HTML page.
182 | - PHP is case sensitive
183 |
184 |
185 | ### Variables
186 |
187 | ```
188 | $x = 4;
189 | $y = 10;
190 | $z = $x + $y;
191 | echo $z;
192 | // $z === 14
193 | ```
194 |
195 | Using `=` to assign values to a variable
196 |
197 | Using `+` to add two variables together
198 |
199 | Using `===` to check the value of a variable
200 |
201 | ```
202 | $word1 = "hello";
203 | $word2 = "world";
204 | $sentence = $word1 . $word2;
205 | echo $sentence;
206 |
207 | // $sentence === "helloworld"
208 | ```
209 |
210 | ```
211 | $sentence2 = $word1 . " " . $word2;
212 | // $sentence2 === "hello world"
213 | ```
214 | Using `.` to concatenate strings and variables
215 |
216 | ```
217 | $x = 3;
218 | $y = 5;
219 |
220 | $z = $x + $y;
221 | echo $z;
222 | // $z === 8
223 |
224 | $z = $x . $y;
225 | echo $z;
226 | // $z === "35"
227 | ```
228 | Note the difference in using `.` or `+` to concatenate or add variables
229 |
230 |
231 | #### What is a variable?
232 |
233 | A variable is a container, or a reference to something we want the computer to remember (we say to store in memory)
234 |
235 | In the cases we've just seen, it is a number or a string of text
236 |
237 | We can assign a value to a variable, and can change or read its value at any time
238 |
239 | In PHP, all variable names start with the $ symbol.
240 |
241 | What you call the variable isn't important!
242 |
243 | Variable names are case sensitive, and can't contain spaces or hyphens.
244 |
245 | To use mulitple words in a variable name, the convention is either to `$use_underscores_to_seperate`, or `$camelCaseVariableNames`
246 | (try to stick to one convention or the other)
247 |
248 | Be careful when re-using variable names, using the same one twice will overwrite the old value stored in the variable
249 |
250 | PHP will create a new variable (place in its memory) for any name it doesn’t recognize as a previously used variable
251 |
252 | Variables can be used to store different types of data:
253 |
254 | - Integer: `$num = 4;`
255 | - Float: `$number = 3.14;`
256 | - String: `$str = "this is some text!";`
257 | - Boolean: `$something = true;` // or `false`
258 |
259 |
260 | ### Quotes
261 |
262 | Use quotes (single or double) to surround standard text
263 |
264 | Quote marks around strings of text differentiates these strings from program commands like functions - more on this later
265 |
266 | There is a difference between using single-quotes and double-quotes: when a variable name appears in text surrounded by double quotes, its current value is automatically put into the string
267 |
268 | ```
269 | $name = "Pete";
270 | echo "Hello $name";
271 | // "Hello Pete";
272 | ```
273 |
274 |
275 | ### Comments
276 |
277 | Single-line comments which begin with two forward slashes (`//`) or an octothorpe - hash/pound - sign (`#`).
278 |
279 | ```
280 | // one-line comment
281 | # another one-line comment
282 | ```
283 |
284 | Text to the right of these is ignored by the interpreter, until we start a new line.
285 |
286 | Multiline comments use `/*` and `*/` (just like JavaScript and CSS)
287 |
288 | ```
289 | /*
290 | Multi-line
291 | comment
292 | */
293 | ```
294 |
295 |
296 | ### Operators
297 |
298 | These are used in PHP to check or assign a value to variables
299 |
300 | We've seen a few examples already, the rest will come in useful as we continue to learn
301 |
302 | - `=` asign a value to a variable
303 | - `.` concatenate two values
304 | - `+` add two values
305 |
306 |
307 | #### Comparison operators
308 |
309 | - `===` check if something is identical to something else
310 | - `!==` check if something is not identical to something else
311 |
312 | (We tend to use three === more often than two, it also checks the 'type' of the variable and is therefore more precise and so less likely to lead to unexpected errors)
313 |
314 | - `>` check if something is greater than something else
315 | - `<` check if something is less than something else
316 | - `>=` check if something is greater than or equal to something else
317 | - `<=` check if something is less than or equal to something else
318 |
319 |
320 | #### Maths operators
321 |
322 | - `+` add
323 | - `-` subtract
324 | - `*` multiply
325 | - `/` divide
326 |
327 | You can use parentheses to control the order an equation is calculated:
328 |
329 | ```
330 | $total = (($x * $y) + $z) / 3.14
331 | ```
332 |
333 |
334 | ### Arrays
335 |
336 | We use arrays when we want to store a collection of related bits of data
337 |
338 | ```
339 | $planet = "Mercury";
340 | $anotherPlanet = "Venus";
341 | $planet3 = "Earth";
342 | ...
343 | $planetEight = "Neptune";
344 | ```
345 |
346 | This is 'related' information, so we should store it together
347 |
348 | ```
349 | $planets = array(
350 | "Mercury",
351 | "Venus",
352 | "Earth",
353 | "Mars",
354 | "Jupiter",
355 | "Saturn",
356 | "Uranus",
357 | "Neptune"
358 | );
359 | ```
360 |
361 | We can access an item within an array by referring to its 'index'
362 |
363 | ```
364 | echo $planets[2]; // === "Earth"
365 | ```
366 |
367 | Each item within an array behaves like a variable
368 |
369 | Individual array elements are accessed by following the array’s variable name with an index enclosed in square brackets `$stuff[2]`
370 |
371 | Note that indexes start at 0 not 1!
372 |
373 | The function `count()` returns the total number of elements in the array:
374 |
375 | ```
376 | echo count($planets); // === 8
377 | ```
378 |
379 |
380 | #### Associative Arrays
381 |
382 | These are arrays with non-numeric indexes
383 |
384 | ```
385 | $earth = array(
386 | "radius" => 6371,
387 | "distanceFromSun" => 149600000
388 | );
389 | ```
390 |
391 | This means we can refer to an item in the array via its name rather than a numeric index
392 |
393 | ```
394 | echo $earth["radius"]; // === 6371
395 | ```
396 |
397 | Associative arrays are often used when we want to store more complex collections of data
398 |
399 | The value to the left of the `=>` operator is the index, the value to the right is the item's value
400 |
401 |
402 | #### Why we use Arrays
403 |
404 | Arrays are a handy way to store and use information
405 |
406 | When we access data from submitted forms, we often use arrays
407 |
408 | When we access data from databases, we often use arrays
409 |
410 |
411 | ### File includes
412 |
413 | It can be useful to split different parts of a web page up into a number of includable files
414 |
415 | For example, on a typical website the header and footer will be consistent across all pages
416 |
417 | Having these stored in a single importable file means they would only have to be updated in one place in order to update the entire site
418 |
419 | A static HTML file might look like this:
420 |
421 | ```
422 |
423 |
424 |
425 | Lorem ipsum
426 |
427 |
428 |
429 |
430 |
431 | ```
432 |
433 | Our header.php include file might look like this:
434 |
435 | ```
436 |
437 |
438 |
439 | Lorem ipsum
440 |
441 |
442 | ```
443 |
444 | Our footer.php include file might look like this:
445 |
446 | ```
447 |
448 |
449 | ```
450 |
451 | This simplifies all of the pages in the site:
452 |
453 | ```
454 |
455 |
456 | Page content...
457 |
458 |
459 | ```
460 |
461 | To import files into the page, use one of the following PHP functions:
462 |
463 | - `include`
464 | - `include_once`
465 | - `require`
466 | - `require_once`
467 |
468 | `include_once` and `require_once` are used when importing specific functionality you'd only need once in a site, for example database connection details
469 |
470 | `include` and `require` can be used multiple times in a single page, and so are handy when importing repeated functionality (e.g. a 'back-to-top' link) throughout a page
471 |
472 | When trying to import a file with `include` or `include_once`, if the file doesn't exist the server issues a warning and continues.
473 |
474 | When trying to import a file with `require` or `require_once`, if the file doesn't exist the server issues an error and stops.
475 |
476 | (You'll learn to use one of the four options, depending on the requirements of the include)
477 |
478 |
479 | ### Control Structures
480 |
481 | PHP can be used to perform a specific action only when certain conditions are met
482 |
483 | The main types of conditional logic structures are:
484 |
485 | - if/else
486 | - for
487 | - foreach
488 |
489 | (Again, these are common in most programming languages, not just PHP)
490 |
491 |
492 | #### if/else
493 |
494 | Use different logic based on whether a statement is true or false
495 |
496 | ```
497 | $today = date("l");
498 |
499 | if ($today === "Friday") {
500 |
501 | echo "Hooray, it's Friday!";
502 |
503 | } else {
504 |
505 | echo "Is it Friday yet?";
506 |
507 | }
508 | ```
509 |
510 | To use more than one condition you can use:
511 |
512 | - `||` (which means OR)
513 | - `&&` (which means AND)
514 |
515 | We can combine multiple possible if/else with statements "else if"
516 |
517 | ```
518 | $today = date("l");
519 | $hour = date("G");
520 |
521 | if ($today === "Friday" && $hour >= 17) {
522 | echo "Beer o'clock!";
523 | } else if ($today === "Saturday" || $today === "Sunday"
524 | || $hour < 9 || $hour >= 17) {
525 | echo "Time to relax";
526 | } else {
527 | echo "Get back to work!";
528 | }
529 | ```
530 |
531 |
532 | #### for loops
533 |
534 | Allow us to repeat logic until a condition is met:
535 |
536 | ```
537 | for ($counter=1900; $counter <= date("Y"); $counter++) {
538 |
539 | echo " ".$counter." ";
540 |
541 | }
542 | ```
543 |
544 | The result:
545 |
546 | ```
547 | 1900
548 | 1901
549 | ...
550 | 201x
551 | ```
552 |
553 |
554 | #### foreach loops
555 |
556 | Used for iterating (looping) through arrays
557 |
558 | ```
559 | $planets = array("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune");
560 | foreach ($planets as $key => $planet) {
561 | echo " Planet " . $key . " = " . $planet . "
";
562 | }
563 | ```
564 |
565 | The result:
566 |
567 | ```
568 | Planet 0 = Mercury
569 | Planet 1 = Venus
570 | ...
571 | Planet 7 = Neptune
572 | ```
573 |
574 | Starts with the array to iterate through, followed by the keyword `as`, followed by two variables — the first is assigned the index of the element and the second is assigned the value of that index’s element.
575 |
576 | (If only one variable is listed after `as`, it is assigned the value of the array element.)
577 |
578 | In our example, the `foreach` instruction moves through the array `$planets`, assigning each element in turn to the variable `$planet`
579 |
580 |
581 | ### Forms
582 |
583 | Here's a basic HTML form:
584 |
585 | ```
586 |
596 | ```
597 |
598 | There are two important attributes on a form: `action` and `method`:
599 |
600 |
601 | #### Action
602 |
603 | The action attribute for an HTML form element refers to the URL that the form should send its data to when submitted.
604 |
605 | The action attribute can be left blank, in which case the form will send data to the current URL.
606 |
607 | Alternatively, form data can be sent to a different script/URL when the form is submitted.
608 |
609 |
610 | #### Method
611 |
612 | The method attribute has two possible options, GET and POST
613 |
614 | When using a form to GET or POST values, PHP automatically turns the form data into variables, setting it to the value which was entered by the user.
615 |
616 | Depending on whether the form action is set to GET or POST, the values will be available as `$_GET['field-name']` or `$_POST['field-name']`
617 |
618 | Whether you use GET or POST depends on which is more suitable for the current situation.
619 |
620 |
621 | #### GET (appends the values to the URL)
622 |
623 | PROs:
624 |
625 | - useful for URL hacking (the values in the URL are the input names and values separated by ?, & and =)
626 | - useful for bookmarking or adding links
627 |
628 | CONs:
629 |
630 | - Insecure, so shouldn't be used for sensitive data (such as passwords)
631 | - Can only handle a limited amount of data
632 | - Can only be used for simple form data
633 |
634 | #### POST (doesn't append the values to the URL)
635 |
636 | PROs:
637 |
638 | - Can be used to post images
639 | - Can handle more data than a GET request
640 | - Posted content is hidden from the user, so can contain passwords etc
641 |
642 | CONs:
643 |
644 | - Can't be bookmarked or linked to directly
645 | - Can't be updated via the URL
646 |
647 | When the form is submitted, we can access the values that have been entered via PHP
648 |
649 |
650 | ### Errors
651 |
652 | Unlike with HTML, when the server encounters a PHP error it is likely to stop, resulting in no page being generated
653 |
654 | The error messages should be helpful, showing on which line the error occurred, and hopefully a message indicating what went wrong. These messages are often cryptic!
655 |
656 | Errors with PHP are far more common than with HTML/CSS:
657 |
658 | - Syntax errors
659 | - Missing semi-colons at the end of a line
660 | - Not enough (or too many) quotes, parentheses, curly brackets or other punctuation
661 |
662 |
663 | ## Arrays
664 |
665 | ### Working with arrays
666 |
667 | With simple variables like strings and numbers, we can `echo` their value at any point to see what they currently contain:
668 |
669 | ```
670 | $planets = 5;
671 | $planets = $planets + 3;
672 | echo $planets; // 8
673 | ```
674 |
675 | ```
676 | $sentence = "There are " . $planets . " planets";
677 | echo $sentence;
678 | // "There are 8 planets"
679 | ```
680 |
681 | If you try to echo an array, you'll get... `Array`
682 |
683 | ```
684 | $planets = array("Mercury", "Venus", "Earth", "Mars", "Jupiter");
685 | echo $planets; // Array
686 | ```
687 |
688 | We have seen that to loop through every item in an array, you can use `foreach`:
689 |
690 | ```
691 | $planets = array("Mercury", "Venus", "Earth", "Mars", "Jupiter");
692 | foreach ($planets as $planet) {
693 | echo "" . $planet . "
";
694 | }
695 | ```
696 |
697 | Which results in:
698 |
699 | ```
700 | Mercury
701 | Venus
702 | ```
703 |
704 | This is fine when you know the structure of the array, but this isn't always the case
705 |
706 | If you have an array of data that you don't know the structure of, PHP provides an easy way to preview its contents
707 |
708 | To preview the contents of an array, you can use the `print_r()` function
709 |
710 | ```
711 | $planets = array("Mercury", "Venus", "Earth", "Mars", "Jupiter");
712 | print_r($planets);
713 | Array ( [0] => "Mercury" [1] => "Venus" [2] => "Earth" [3] => "Mars" [4] => "Jupiter" )
714 | ```
715 |
716 | This works, but it can be difficult to read
717 |
718 | When using `print_r()` it usually helps to echo this with HTML `` tags surrounding it:
719 |
720 | ```
721 | $planets = array("Mercury", "Venus", "Earth", "Mars", "Jupiter");
722 | echo "";
723 | print_r($planets);
724 | echo " ";
725 | ```
726 |
727 | Which results in:
728 |
729 | ```
730 | Array (
731 | [0] => Mercury
732 | [1] => Venus
733 | [2] => Earth
734 | [3] => Mars
735 | [4] => Jupiter
736 | )
737 | ```
738 |
739 | `print_r()` works well with associative arrays too:
740 |
741 | ```
742 | $earth = array(
743 | "radius" => 6371,
744 | "distanceFromSun" => 149600000
745 | );
746 |
747 | echo "";
748 | print_r($earth);
749 | echo " ";
750 | ```
751 |
752 | Which results in:
753 |
754 | ```
755 | Array (
756 | [radius] => 6371
757 | [distanceFromSun] => 149600000
758 | )
759 | ```
760 |
761 | `print_r()` isn't useful for a final product - you wouldn't want to display information in this way
762 |
763 | But during development it's a handy way to check the current value of an array variable
764 |
765 |
766 | ### Why arrays are useful
767 |
768 | Arrays are a useful way to use/manipulate/filter information
769 |
770 | Later we won't be creating these arrays manually
771 |
772 | Instead we'll be retrieving data from external sources - e.g. from a database
773 |
774 | We won't know what the content of the array is, but we will have an idea of its structure
775 |
776 | When we recieve this data, we need to put it into a format that we can manipulate with PHP
777 |
778 | We will be learning how to extract information from a database and turn it into an array
779 |
780 | If you learn how to use arrays, then you'll know how to use data from various sources, such as a database or an API call from another website
781 |
782 |
783 | ### Multi-dimensional arrays
784 |
785 | Arrays can contain a mixture of different types of content:
786 |
787 | ```
788 | $things = array(1, 5, "hello", 3.14);
789 | foreach ($things as $thing) {
790 | echo "". $thing . " = " . gettype($thing) . "
";
791 | }
792 |
793 | 1 = integer
794 | 5 = integer
795 | hello = string
796 | 3.14 = double
797 | ```
798 |
799 | Using our planetary examples from before, imagine that we would want to store information about each planet as an array
800 |
801 | ```
802 | $mercury => array(
803 | "size" => 0.3,
804 | "distance" => 0.3
805 | );
806 | ```
807 |
808 | ```
809 | $venus => array(
810 | "size" => 0.9,
811 | "distance" => 0.6
812 | );
813 | ```
814 |
815 | The previous example allows us to store information about each planet
816 |
817 | But it doesn't provide an easy way to group together all the planets
818 |
819 | The reason for using arrays is to group together content
820 |
821 | We want to put each of these planetary arrays into a single array
822 |
823 | We can instead contain these in a single array that contains other arrays:
824 |
825 | ```
826 | $planets = array(
827 | "mercury" => array(
828 | "size" => 0.3,
829 | "distance" => 0.3
830 | ),
831 | "venus" => array(
832 | "size" => 0.9,
833 | "distance" => 0.6
834 | ),
835 | "earth" => array(
836 | "size" => 1,
837 | "distance" => 1
838 | )
839 | );
840 | ```
841 |
842 | We call arrays that contain other arrays *multi-dimensional arrays*
843 |
844 | We can access values from within the arrays in the same way as before:
845 |
846 | ```
847 | foreach ($planets as $planetName => $planetData) {
848 | echo "". $planetName . " size = " . $planetData["size"] . "
";
849 | }
850 | ```
851 |
852 | This results in:
853 |
854 | ```
855 | mercury size = 0.3
856 | venus size = 0.9
857 | earth size = 1
858 | ```
859 |
860 | The ability to create multi-dimensional arrays is useful as it allows us to use a more complex information structure
861 |
862 | In most real-world examples, the data you'll be using will be more complex than a simple row of information
863 |
864 | While we're working this out, the `print_r()` function we saw earlier will allow us to preview all of the values in the array
865 |
866 |
867 | #### Nested foreach loops
868 |
869 | One way to access all information within a multi-dimensional array is to use a `foreach` loop within another `foreach` loop
870 |
871 | ```
872 | foreach ($planets as $planetName => $planetData) {
873 | echo "".$planetName." ";
874 |
875 | foreach($planetData as $attribute => $value) {
876 | echo "".$attribute." : ".$value."
";
877 | }
878 | }
879 | ```
880 |
881 | We can manipulate the information in different ways, use different parts in different situations
882 |
883 | For example, we may not want to display all of the detailed information for every item in one long page
884 |
885 | We may just want to summarise each item initially, then if one is selected display the detailed information only for this item
886 |
887 | Let's just output the name of each planet for now:
888 |
889 | ```
890 | foreach($planets as $planetName => $planetData) {
891 | echo ' '.$planetName.' ';
892 | }
893 | ```
894 |
895 | This results in links being generated:
896 |
897 | ```
898 | mercury
899 | venus
900 | earth
901 | ```
902 |
903 | Next we'll learn how to use these links to display planet-specific data
904 |
905 |
906 | ### Superglobal variables
907 |
908 | Superglobal variables are special variables that are automatically created by PHP.
909 |
910 | They are associative arrays that contain values acquired from user input or the server
911 |
912 | They are called superglobal because they are accessible in any variable scope (more on this later)
913 |
914 | The important superglobal arrays:
915 |
916 | - `$_SERVER`
917 | - `$_GET`
918 | - `$_POST`
919 | - `$_COOKIE`
920 | - `$_SESSION`
921 |
922 | We have already seen two examples of these: `$_GET` and `$_POST`. These arrays are automatically populated when you submit a form
923 |
924 | The 'name' attribute of each form input element is used in these arrays
925 |
926 | e.g. if you have a form element:
927 |
928 | ```
929 |
930 | ```
931 |
932 | When the form is submitted, this will be available as either `$_GET['firstname']` or `$_POST['firstname']`
933 |
934 | The main way to populate the `$_POST` superglobal variable is to post a form.
935 |
936 | `$_GET` parameters can also be populated by forms, but this isn't the only way to add values
937 |
938 | We can create links that populate the `$_GET` array
939 |
940 | To pass variables via the URL, add parameters to the end of a URL
941 |
942 | At the end of a standard URL add a `?` followed by a variable as a key/value pair, separated by an `=`
943 |
944 | ```
945 |
946 |
947 | ```
948 |
949 | To add multiple variables via the URL, separate them with an `&`
950 |
951 | Don't forget when you add an `&` in your HTML you should add `&` or it won't validate
952 |
953 | ```
954 |
955 |
956 | ```
957 |
958 | This is a useful way to pass simple variables around between different pages
959 |
960 | Back to our planets example, so far we have a list of links, one for each planet name
961 |
962 | These links append the selected planet name to the URL
963 |
964 | When a planet link has been clicked, `$_GET['planet']` will have a value
965 |
966 | We can use this, combined with a simple if/else statement checking whether the variable has been set, to detect whether to display the overview list or detail view
967 |
968 |
969 | ```
970 |
980 | You have selected planet . Here are its details:
981 |
982 | $value) {
986 | echo ''.$key.' : '.$value.' ';
987 | }
988 |
989 | ?>
990 |
991 |
994 | Select a planet to see its details...
995 |
996 | $planetData) {
999 | echo ''.$planetName.' ';
1000 | }
1001 | ?>
1002 |
1003 |
1006 | ```
1007 |
1008 |
1009 | ### $_SERVER
1010 |
1011 | This contains useful information related to the server
1012 |
1013 | For example, you can detect the URL of the current page, the file we're currently using, or the user's browser
1014 |
1015 | you can use `print_r()` to see all the possible values of the `$_SERVER` array
1016 |
1017 |
1018 | ## State, sessions and cookies
1019 |
1020 | One important point to note: variables aren't automatically stored or remembered when you move between pages
1021 |
1022 | The `$_POST` array will only be populated on a page after a form submit has occurred
1023 |
1024 | The `$_GET` array will only be populated if a form submit has occurred on the previous page, or if parameters are appended to the URL
1025 |
1026 | In order to save variables between page refreshes, we have to use an alternative technique
1027 |
1028 | HTTP is a "stateless protocol"
1029 |
1030 | This means that every server request is independent - every time you finish requesting a page, the server forgets about you
1031 |
1032 | It doesn't maintain a connection between client and server, there is no way of identifying a sequence of requests as coming from the same user
1033 |
1034 | In order to remain logged in to a site, you need a way to establish credentials across multiple requests
1035 |
1036 | It is possible to transfer information by appending a value to the URL
1037 |
1038 | It can also be added as a hidden fields in a form
1039 |
1040 | In both cases, however, the information is potentially visible at the client end, either in the location bar of the browser or in the source html of the constructed page
1041 |
1042 | A better technique is needed!
1043 |
1044 |
1045 | ### Cookies
1046 |
1047 | Cookies are small pieces of data passed between browser and server as part of the http message header rather than in the document body
1048 |
1049 | They are saved as a file on the client machine
1050 |
1051 | They can be saved for a single browser session (until you close the browser), or for any specified period of time
1052 |
1053 | They can be read and written by PHP and JavaScript
1054 |
1055 | If any cookies exist for the site in question, they are available to the `$_COOKIE` superglobal variable
1056 |
1057 | (JavaScript can access the same cookies by referencing the `document.cookie` object)
1058 |
1059 | Cookies are created in PHP using the built-in function `setcookie()`
1060 |
1061 | If, for example, we wished to hold a supplied username throughout a single browser session, we would use the following commands:
1062 |
1063 | ```
1064 | $username = $_GET['username'];
1065 | setcookie('username', $username);
1066 | ```
1067 |
1068 | This would then be accessible as `$_COOKIE['username']` no matter how many times a user refreshed the page, until the browser was closed.
1069 |
1070 | It is possible to make a cookie last longer than a browser session - you can set your own expiry date:
1071 |
1072 | ```
1073 | // store the cookie for 30 days from today
1074 | setcookie('username', $username, time() + 60*60*24*30)
1075 | ```
1076 |
1077 | ```
1078 | // store the cookie until the eighteenth of July, 2026
1079 | setcookie('username', $username, mktime(0,0,0,7,18,2026));
1080 | ```
1081 |
1082 | The third parameter for the `setcookie()` function takes a numeric value that equates to the time that the cookie should expire
1083 |
1084 | To remove a cookie, just set its date value to a date in the past
1085 |
1086 | ```
1087 | setcookie('username', NULL, -1);
1088 | ```
1089 |
1090 | Commands to set or change cookie values involve writing a document header, so they must occur before any other document content is output
1091 |
1092 | PHP code to set cookies cannot be interspersed with normal HTML, it must be at the top of a page before any HTML is output
1093 |
1094 | (Even a single space at the beginning of a PHP file before the `
1127 | ```
1128 |
1129 | Once a session has been started, we can reference variables using the `$_SESSION` superglobal array
1130 |
1131 | Session variables can be assigned to or retrieved from the `$_SESSION` associative array at any time
1132 |
1133 | ```
1134 | // start the session - must always happen at the top of the page
1135 | session_start();
1136 |
1137 | // (assuming form has been posted, set session variable)
1138 | $_SESSION['username'] = $_POST['username'];
1139 |
1140 | // this is now accessible anywhere we have a session
1141 | echo $_SESSION['username'];
1142 | ```
1143 |
1144 | Once you set a session variable, it will exist until you remove it or end the browser session
1145 |
1146 | To remove a session variable, use `unset()`
1147 |
1148 | ```
1149 | unset($_SESSION['username']);
1150 | ```
1151 |
1152 | Use sessions rather than cookies:
1153 |
1154 | - Session values are stored in temporary files at the server end rather than in the client
1155 | - Therefore sessions are far more secure and reliable than cookies
1156 |
1157 |
1158 | ## PHP and MySQL
1159 |
1160 | ***(It may be worth reading the database notes before continuing)***
1161 |
1162 |
1163 | ### Connecting to a MySQL Database with PHP
1164 |
1165 | To connect to a MySQL database with PHP we use a _class_ called `mysqli`
1166 |
1167 | The line of PHP code we need to do this is:
1168 |
1169 | ```
1170 | $db = new mysqli("host", "username", "password", "database");
1171 | ```
1172 |
1173 | We can create a simple PHP script to test to see if we can connect to the database correctly:
1174 |
1175 | ```
1176 | // connect
1177 | $db = new mysqli("server","u","p","db");
1178 |
1179 | // check if there was an error
1180 | if ($db->connect_error) {
1181 | echo "Connect failed: " . $db->connect_error;
1182 | exit();
1183 |
1184 | // no error!
1185 | } else {
1186 | echo "Database connected!";
1187 | }
1188 | ```
1189 |
1190 | An explanation of the database connection code:
1191 |
1192 | - We're storing the database connection in a variable called `$db` (We'll use this variable again later when we query the database)
1193 | - We test to see if there was an error connecting (for example because of incorrect credentials) by seeing if `$db->connect_error` has a value
1194 | - If there was an error connecting then we display it
1195 | - Otherwise the database connection was successful!
1196 |
1197 | Note that from now on in these examples it is assumed that the database connection is active
1198 |
1199 | It is often a good idea to keep connection details in a separate file for convenience
1200 |
1201 | This file can be imported at the start of every page, using `require_once`
1202 |
1203 | This approach means you only need to update the content for these in one place
1204 |
1205 | (A good practice to get in to!)
1206 |
1207 |
1208 | ### Executing SQL queries with PHP
1209 |
1210 | Once we have established a connection to the database, we can query it with SQL
1211 |
1212 | A basic SQL example is to select everything from the answers table:
1213 |
1214 | ```
1215 | SELECT * FROM `answers`
1216 | ```
1217 |
1218 | This should return the following content:
1219 |
1220 |
1221 | | id | question_id | user_id | answer | tweet_id | date_added |
1222 | |----|-------------|---------|-----------|-------------|---------------------|
1223 | | 1 | 1 | 1 | Edam | 23741876128 | 2013-03-19 18:34:23 |
1224 | | 2 | 2 | 1 | Charles | 23741456214 | 2013-03-21 18:35:51 |
1225 | | 3 | 1 | 2 | Melted | 23723849723 | 2013-03-22 09:02:12 |
1226 |
1227 |
1228 | When we get it into PHP, this data will be represented as an associative array, like those we have seen previously
1229 |
1230 | To execute this with PHP, first we add our SQL query to a variable:
1231 |
1232 | ```
1233 | $query = "SELECT * FROM `answers`";
1234 | ```
1235 |
1236 | Then we execute the query...
1237 |
1238 | ```
1239 | $result = $db->query($query);
1240 | ```
1241 |
1242 | ...and fetch the results
1243 |
1244 | ```
1245 | $row = $result->fetch_assoc();
1246 | ```
1247 |
1248 | This will return us the relevant data in an associative array, stored in the variable `$row`
1249 |
1250 |
1251 | Here is the example code
1252 |
1253 | ```
1254 | // include connection settings
1255 | require_once "../includes/connect.php";
1256 |
1257 | // get a list of all answers in the database
1258 | $query = "SELECT * FROM `answers`";
1259 |
1260 | // perform the query
1261 | $result = $db->query($query);
1262 |
1263 | // loop through the results as an associative array
1264 | while ($row = $result->fetch_assoc()) {
1265 | echo "";
1266 | print_r($row);
1267 | echo " ";
1268 | }
1269 | ```
1270 |
1271 |
1272 | ### while() loops
1273 |
1274 | We want to turn each row in the table into a simple PHP associative array
1275 |
1276 | We're going to deal with each result individually, looping through them one by one
1277 |
1278 | We will use a `while()` loop, which is similar in many ways to the `foreach()` loops that we've seen previously
1279 |
1280 | The while loop will set the variable `$row` to an array containing the values of the current row in the table
1281 |
1282 | The `$row` array keys will be the table column names
1283 |
1284 | The first time the while loop is run, the following values are present
1285 |
1286 | ```
1287 | echo $row['id']; // 1
1288 | echo $row['answer']; // 'Edam'
1289 | echo $row['date_added']; // '2013-03-19 18:34:23'
1290 | ```
1291 |
1292 | When the script reaches the end of the while loop - the closing `}` - it will go back to the start of the while loop, but this time the value of `$row` will be set to the next row in the table
1293 |
1294 | This will continue until it has run through every row that has been returned by the SQL query
1295 |
1296 |
1297 | ### Multiple SQL Queries
1298 |
1299 | It's easy to change the SQL query to update the data we'll receive
1300 |
1301 | In the next example I've just changed the query from the `answers` to `questions` table to get different results
1302 |
1303 | ```
1304 | $question_query = "SELECT * FROM `questions`";
1305 | ```
1306 |
1307 |
1308 | ### SQL Errors
1309 |
1310 | It is a good idea to wrap an if/else conditional statement around the query
1311 |
1312 | This will help to identify any errors with the SQL query
1313 |
1314 | ```
1315 | // get a list of all content from an unknown table
1316 | $query = "SELECT * FROM `lorem_ipsum`";
1317 |
1318 | // perform the query
1319 | if ($result = $db->query($query)) {
1320 |
1321 | // ... display results as before
1322 |
1323 | // if there was an error with your query
1324 | // this will display it
1325 | } else {
1326 | echo "SQL Error: " . $db->error;
1327 | }
1328 | ```
1329 |
1330 |
1331 | ### CRUD
1332 |
1333 | We have SELECT SQL queries working with PHP
1334 |
1335 | We'll come back to these again in a little while
1336 |
1337 | Let's get the other CRUD commands working
1338 |
1339 | - Create = `INSERT`
1340 | - Request = `SELECT`
1341 | - Update = `UPDATE`
1342 | - Delete = `DELETE`
1343 |
1344 | We can also write PHP scripts to create, update and delete data with SQL
1345 |
1346 | These examples use a value called `affected_rows` to test how many rows (if any) they have changed in the database
1347 |
1348 | To check that they have changed the data, we could go back and look at one of the `SELECT` examples again
1349 |
1350 |
1351 | #### INSERT
1352 |
1353 | This SQL command will add a new entry to the `questions` table:
1354 |
1355 | ```
1356 | INSERT INTO
1357 | `questions` (`id`, `question`, `date_added`)
1358 | VALUES
1359 | (3, 'Favourite Fish', 2013-03-25 18:34:13);
1360 | ```
1361 |
1362 | This can be executed by a PHP script in a similar way to the SELECT commands we saw earlier
1363 |
1364 | ```
1365 | // add new question
1366 | $query = "INSERT INTO `questions` (`id`, `question`, `date_added`) VALUES (3, 'Favourite Fish', 2013-03-25 18:34:13);";
1367 |
1368 | // perform the query
1369 | $result = $db->query($query);
1370 | if ($result) {
1371 |
1372 | // output a count of how many rows were changed
1373 | echo "SQL successful, affected rows: " . $db->affected_rows;
1374 |
1375 | // there was an SQL error
1376 | } else {
1377 | echo "SQL Error: " . $db->error;
1378 | }
1379 | ```
1380 |
1381 |
1382 | #### UPDATE
1383 |
1384 | This SQL command will update the question field of the entry we just added to the `questions` table:
1385 |
1386 | ```
1387 | UPDATE `questions` SET `question` = 'Favourite Fruit' WHERE `id` = 3;
1388 | ```
1389 |
1390 | This can be executed by a PHP script in the same way as the INSERT command
1391 |
1392 | ```
1393 | // update question
1394 | $query = "UPDATE `questions` SET `question` = 'Favourite Fruit' WHERE `id` = 3";
1395 |
1396 | // perform the query
1397 | $result = $db->query($query);
1398 | if ($result) {
1399 |
1400 | // output a count of how many rows were changed
1401 | echo "SQL successful, affected rows: " . $db->affected_rows;
1402 |
1403 | // there was an SQL error
1404 | } else {
1405 | echo "SQL Error: " . $db->error;
1406 | }
1407 | ```
1408 |
1409 |
1410 | #### DELETE
1411 |
1412 | This SQL command will delete the question we just added to the `questions` table:
1413 |
1414 | ```
1415 | DELETE FROM `questions` WHERE `id` = 3;
1416 | ```
1417 |
1418 | This can be executed by a PHP script in the same way as the INSERT and UPDATE commands
1419 |
1420 | ```
1421 | // delete question
1422 | $query = "DELETE FROM `questions` WHERE `id` = 3;";
1423 |
1424 | // perform the query
1425 | $result = $db->query($query);
1426 | if ($result) {
1427 |
1428 | // output a count of how many rows were changed
1429 | echo "SQL successful, affected rows: " . $db->affected_rows;
1430 |
1431 | // there was an SQL error
1432 | } else {
1433 | echo "SQL Error: " . $db->error;
1434 | }
1435 | ```
1436 |
1437 |
1438 | ### Displaying results
1439 |
1440 | At this point we have basic SELECT SQL queries working with PHP
1441 |
1442 | For now we're just using `print_r()` to test that we have data in a variable, in a similar way to the examples we saw earlier
1443 |
1444 | This is fine while developing to test that we're receiving data, but you don't want to display content in this way for a live site
1445 |
1446 | We need to learn how to take the SQL query results array we recieve, and display it properly with HTML
1447 |
1448 | Using a while loop to access each row individually:
1449 |
1450 | ```
1451 | // query the database
1452 | $query = "SELECT `id`, `answer`, `date_added` FROM `answers`";
1453 |
1454 | // fetch all results
1455 | $result = $db->query($query);
1456 |
1457 | // loop through each result one at a time
1458 | while ($row = $result->fetch_assoc()) {
1459 | // do something with $row
1460 | }
1461 | ```
1462 |
1463 | The while loop will set the variable `$row` to an array containing the values of the current row in the table
1464 |
1465 | The `$row` array keys will be the table column names
1466 |
1467 | The first time the while loop is run, the following values are present
1468 |
1469 | ```
1470 | echo $row['id']; // 1
1471 | echo $row['answer']; // 'Edam'
1472 | echo $row['date_added']; // '2013-03-19 18:34:23'
1473 | ```
1474 |
1475 | To add these to the HTML:
1476 |
1477 | ```
1478 | // query the database
1479 | $query = "SELECT `id`, `answer`, `date_added` FROM `answers`";
1480 |
1481 | // fetch all results
1482 | $result = $db->query($query);
1483 |
1484 | // loop through each result one at a time
1485 | while ($row = $result->fetch_assoc()) {
1486 | echo '
1487 |
1488 | Answer ' . $row['id'] . ' = ' . $row['answer'] . ' (added on ' . $row['date_added'] . ')
1489 |
1490 | ';
1491 | }
1492 | ```
1493 |
1494 | ### Counting results
1495 |
1496 | You may only want to display results if there are any to display
1497 |
1498 | To do this you can use `num_rows` to count the number of rows that have been returned
1499 |
1500 |
1501 | ```
1502 | $result = $db->query($query);
1503 |
1504 | // check we have a result
1505 | if ($result->num_rows > 0) {
1506 |
1507 | // do something
1508 | echo "There were " . $result->num_rows . " results";
1509 |
1510 | // if there are no results
1511 | } else {
1512 |
1513 | // do something else
1514 | echo "Sorry, there were no results";
1515 |
1516 | }
1517 | ```
1518 |
1519 |
1520 | ### Adjusting queries based on user input
1521 |
1522 | Up to this point we have seen fixed SQL queries
1523 |
1524 | We can use PHP to adjust our SQL queries dynamically by using variables, rather than hard-coding values
1525 |
1526 | For example, we could use an HTML form to allow a user to enter a value, then search our database for this
1527 |
1528 | ```
1529 | $query = "SELECT * FROM `answers` WHERE `answer` LIKE '%" . $_GET['suggestion'] . "%''";
1530 | ```
1531 |
1532 |
1533 | #### Dynamic CRUD queries
1534 |
1535 | We saw earlier some basic examples of other CRUD commands, used to INSERT, UPDATE and DELETE data from the database
1536 |
1537 | We can combine these with HTML forms to make this more dynamic
1538 |
1539 | ```
1540 |
1550 | ```
1551 |
1552 | This form can be used to add new questions:
1553 |
1554 | ```
1555 | // check if form has been posted
1556 | if (!empty($_POST) && !empty($_POST['question'])) {
1557 |
1558 | // create insert SQL query
1559 | $query = "INSERT INTO `questions` (`question`, `date_added`) VALUES ('".$_POST['question']."', NOW())";
1560 |
1561 | $result = $db->query($query);
1562 | ```
1563 |
1564 | There is a problem with this insert form - it doesn't check for existing data before adding a new row to the database
1565 |
1566 | Before adding a new question, it should first check to see if the question code already exists
1567 |
1568 | (This same technique may come in handy when you are thinking about adding users to your website - you shouldn't have two users with the same username)
1569 |
1570 | ```
1571 | // only add to the database if the form has been submitted
1572 | if (!empty($_POST) && !empty($_POST['question'])) {
1573 |
1574 | // save a reference to the question
1575 | $question = $_POST['question'];
1576 |
1577 | // check whether question exists already
1578 | $query = "SELECT COUNT(*) AS `count` FROM `questions` WHERE `question` = '".$question."'";
1579 | $result = $db->query($query);
1580 | $data = $result->fetch_assoc();
1581 |
1582 | // if question exists already, don't add a new one
1583 | if ($data['count'] > 0) {
1584 |
1585 | echo "This question exists already, please add a different one
";
1586 |
1587 | // no question, so add it
1588 | } else {
1589 |
1590 | // insert SQL query
1591 | $query = "INSERT INTO `questions` (`question`, `date_added`) VALUES ('".$question."', NOW())";
1592 |
1593 | // perform the query
1594 | $result = $db->query($query);
1595 |
1596 | // check the query was successful
1597 | if ($result) {
1598 |
1599 | // output a count of how many rows were changed
1600 | echo "SQL successful, affected rows: " . $db->affected_rows . "
";
1601 |
1602 | // there was an SQL error
1603 | } else {
1604 | echo "SQL Error: " . $db->error;
1605 | }
1606 | }
1607 | }
1608 | ```
1609 |
1610 |
1611 | #### Updating and deleting
1612 |
1613 | When updating or deleting data, it often makes sense to turn this into a two-step process
1614 |
1615 | Firstly, the user should be able to select the item to update or delete
1616 |
1617 | Once an item has been selected for updating, we pre-fill the values of a form to make it easier to update
1618 |
1619 | Once an item has been selected for deleting, we offer the user a final chance to change their mind. (Remember there is no undo!)
1620 |
1621 |
1622 | ## Misc. tips
1623 |
1624 | Many of these topics are independent from one another, some may be more relevant or interesting than others...
1625 |
1626 |
1627 | ### Site architecture
1628 |
1629 | When creating a website, it is important to decide on the site structure (or architecture)
1630 |
1631 | - What sections (or pages) will the website have?
1632 | - Will there be sub-sections?
1633 | - Can any user access every part of the site, or do you have to be logged-in in order to access certain aspects?
1634 |
1635 |
1636 | An example page list:
1637 |
1638 | - Home page
1639 | - Item details page
1640 | - User login page
1641 | - User registration page
1642 | - Add an item page
1643 | - (etc)
1644 |
1645 | Once you've decided on the site architecture you can put the file structure together in a logical manner
1646 |
1647 | You could create a PHP file for every page in the site
1648 |
1649 | You could either have these all in the same folder, and name them differently:
1650 |
1651 | - index.php
1652 | - details.php
1653 | - login.php
1654 | - register.php
1655 | - add.php
1656 |
1657 | Or you could call them all index.php and put them into directories:
1658 |
1659 | - /index.php
1660 | - /details/index.php
1661 | - /login/index.php
1662 | - /register/index.php
1663 | - /add/index.php
1664 |
1665 | The advantage of the second approach is that you don't need to reference the file name, which makes your URLs look cleaner
1666 |
1667 | - http://url.com/details.php
1668 | - http://url.com/register.php
1669 |
1670 | vs.
1671 |
1672 | - http://url.com/details/
1673 | - http://url.com/register/
1674 |
1675 | (subjective opinion!)
1676 |
1677 | Consider creating an includes (or assets) directory for any files that aren't displayed directly in a browser
1678 |
1679 | Examples of files that could go into this directory are:
1680 |
1681 | - a CSS file
1682 | - a folder to contain images
1683 | - a JavaScript file (or a folder containing JavaScript files)
1684 | - PHP include files
1685 | - database connection include file
1686 | - header and footer include files
1687 |
1688 | Consider separating functionality into files:
1689 |
1690 | - You may find yourself adding the same functionality in numerous files
1691 | - Any time you repeat the same code, remember there is probably a more efficient way to do it
1692 |
1693 | Consider putting this code into a separate file and including it every time you need it (as we have done with the db connection, header, footer)
1694 |
1695 | - You could put your session-handling logic into one file that you include at the top of every page
1696 | - You could put your database calls into a separate file to keep them together
1697 | - Additionally, you could then use functions to reference each one as and when you need it (We'll look at functions a little later on)
1698 |
1699 |
1700 | ### Header include files and page titles
1701 |
1702 | We've seen examples of header and footer include files:
1703 |
1704 | ```
1705 |
1706 |
1707 |
1708 |
1709 |
1710 | ```
1711 |
1712 | In the previous example, the same title was used for every page
1713 |
1714 | To set a different page title for each page, you could set a variable above the header include:
1715 |
1716 | ```
1717 |
1721 | ```
1722 |
1723 | The `$title` variable would then be available to echo in the header.php file, meaning you could output a different title on every page
1724 |
1725 |
1726 | ### Functions
1727 |
1728 | Functions are a way to group together a set of commands so that we can re-use them whenever we need to
1729 |
1730 | Functions are useful because you can write them once, then use them wherever and whenever you need
1731 |
1732 | There are two types of function:
1733 |
1734 | - Those that are native (built-in) to the language already
1735 | - Functions that we write ourselves - or alternatively 'third-party' functions that someone else has written that we can include and use
1736 |
1737 |
1738 | #### Native functions
1739 |
1740 | There are lots of built-in functions in PHP which allow us to easily perform a specific task. For example:
1741 |
1742 | - `date()` - Get the current date/time
1743 | - `mail()` - Send an email
1744 | - `scandir()` - List all files and folders in a specific directory on the web server
1745 |
1746 | There is a comprehensive list at [php.net](http://php.net) - using the search box is a good place to start
1747 |
1748 |
1749 | #### Third-party functions
1750 |
1751 | Third-party functions are useful when you want to do something that has probably be done many times before
1752 |
1753 | Often you can find that someone else has created a solution and put their example online
1754 |
1755 | Websites like stack overflow, are good places to look for these
1756 |
1757 | Code libraries and frameworks often contain a number of useful functions - more on that later...
1758 |
1759 |
1760 | #### Writing functions
1761 |
1762 | Creating our own functions is a useful way to reduce code repetition
1763 |
1764 | If you find yourself writing the same code several times, it could be made more efficient by creating a function
1765 |
1766 | ```
1767 | function doSomething() {
1768 | // code
1769 | }
1770 | ```
1771 |
1772 | As you build a website, you may start to notice situations where a function could help
1773 |
1774 | How you define a function:
1775 |
1776 | ```
1777 | function name() {
1778 | // do something
1779 | }
1780 | ```
1781 |
1782 | Then, to call this function at any time:
1783 |
1784 | ```
1785 | name();
1786 | ```
1787 |
1788 | Here's a function to output a link we may use lots of times
1789 |
1790 | ```
1791 | // output a back to top HTML link
1792 | function backToTop() {
1793 | echo '
1794 | Back to top
1795 | ';
1796 | }
1797 | ```
1798 |
1799 | To use this function:
1800 |
1801 | ```
1802 | backToTop();
1803 | ```
1804 |
1805 | Every time you call it, a back to top link will be output
1806 |
1807 |
1808 | #### Function parameters
1809 |
1810 | To pass variables into a function, you pass them through as arguments (or parameters)
1811 |
1812 | You reference the names of these variables between the parentheses when you define the function
1813 |
1814 | You then use the same variable name within the function declaration
1815 |
1816 | ```
1817 | function square($num) {
1818 | echo $num * $num;
1819 | }
1820 |
1821 | square(3); // === 9
1822 | square(5); // === 25
1823 | ```
1824 |
1825 | To return a value from a function use the `return` keyword:
1826 |
1827 | ```
1828 | function square($num) {
1829 | return $num * $num;
1830 | }
1831 |
1832 | $threeSquared = square(3); // === 9
1833 | $fiveSquared = square(5); // === 25
1834 | ```
1835 |
1836 | These are simple examples to show how to create and use functions
1837 |
1838 | In the real world you are likely to use more complex functions
1839 |
1840 | You could use functions to move some of the code you're writing into separate files
1841 |
1842 | For example, you could create a function that checks whether the current user is logged in. Something like this could be used at the top of every page of a website to determine whether to show content for a logged-in user or a member of the public
1843 |
1844 | ***Further information:***
1845 |
1846 | - [http://www.brandonsavage.net/how-to-write-a-function-in-php/](http://www.brandonsavage.net/how-to-write-a-function-in-php/)
1847 | - [http://webhole.net/2010/03/14/php-functions-tutorial/](http://webhole.net/2010/03/14/php-functions-tutorial/)
1848 | - [http://www.tuxradar.com/practicalphp/4/15/0](http://www.tuxradar.com/practicalphp/4/15/0)
1849 |
1850 | #### Variable scope
1851 |
1852 | When using functions, any variables that are defined outside of the function are not available within it
1853 |
1854 | Conversely any variable created within the function is not available outside it
1855 |
1856 | This is known as scope, and is very useful!
1857 |
1858 | There are some exceptions to this; as mentioned earlier, superglobal variables are accessible everywhere (globally)
1859 |
1860 | - [Variable Scope documentation](http://www.elated.com/articles/php-variable-scope-all-you-need-to-know/)
1861 |
1862 |
1863 | ### Formatting data
1864 |
1865 | In most of the examples we've seen so far, we've output data directly from the database to the page:
1866 |
1867 | ```
1868 | echo $something;
1869 | ```
1870 |
1871 | Sometimes you may want to format this information before outputting it on the page
1872 |
1873 | We have already seen a few basic examples of this:
1874 |
1875 | Concatenating strings - when outputting a name we've combined strings like so:
1876 |
1877 | ```
1878 | echo "" . $firstname . " " . $surname . "
";
1879 | ```
1880 |
1881 | Date functions - to output today's date:
1882 |
1883 | ```
1884 | echo date_format("d/m/y");
1885 | ```
1886 |
1887 | #### Changing case
1888 |
1889 | There are further options we could use to manipulate strings of text:
1890 |
1891 | To change the case of a text string we can use `strtolower()` or `strtoupper()`
1892 |
1893 | ```
1894 | $firstname = "Pete";
1895 | $surname = "Blah";
1896 |
1897 | echo "" . strtolower($firstname) . " " .strtoupper($surname) . "
";
1898 |
1899 | // pete BLAH
1900 | ```
1901 |
1902 | #### Limiting characters
1903 |
1904 | To limit text to a certain number of characters we can use `substr()`:
1905 |
1906 | ```
1907 | $text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.";
1908 |
1909 | // first param = string
1910 | // second param = start position
1911 | // third param = number of characters to output
1912 | echo "" . substr($text, 0, 140) . "
";
1913 | ```
1914 |
1915 | (Could be useful if for example you want to output a limited summary of a review)
1916 |
1917 |
1918 | #### Replacing characters
1919 |
1920 | To replace some text with some other text you can use `str_replace()`
1921 |
1922 | ```
1923 | $original = "hello world";
1924 |
1925 | // first param = replace
1926 | // second param = with
1927 | // third param = original string
1928 | $replaced = str_replace("world", "universe", $original);
1929 |
1930 | echo $replaced; // hello universe
1931 | ```
1932 |
1933 | There are lots more examples of string functions on the PHP website:
1934 |
1935 | - [http://www.php.net/manual/en/ref.strings.php](http://www.php.net/manual/en/ref.strings.php)
1936 |
1937 |
1938 | #### Formatting numbers
1939 |
1940 | There are also lots of functions we could use to manipulate numbers:
1941 |
1942 | You could use `round()`, `floor()` and `ceil()` to round up or down a number with a decimal point, into a whole number
1943 |
1944 | ```
1945 | $lower = 3.254;
1946 | $upper = 3.836;
1947 |
1948 | echo round($lower); // === 3
1949 | echo round($upper); // === 4
1950 | echo floor($lower); // === 3
1951 | echo floor($upper); // === 3
1952 | echo ceil($lower); // === 4
1953 | echo ceil($upper); // === 4
1954 | ```
1955 | Could be useful for calculating an average rating for an item, site statistics, etc
1956 |
1957 |
1958 | #### Generating random numbers
1959 |
1960 | You can generate a random whole number with `rand()`
1961 |
1962 | `rand(1,10)` will generate a random whole number between 1 and 10 (inclusive)
1963 |
1964 | Could be used to display a random item from an array
1965 |
1966 | ```
1967 | $planets = array("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune");
1968 | $rand = rand(0, count($planets) - 1);
1969 | echo $planet[$rand];
1970 | ```
1971 |
1972 | There are lots more examples of number functions on the PHP website:
1973 |
1974 | - [http://www.php.net/manual/en/book.math.php](http://www.php.net/manual/en/book.math.php)
1975 |
1976 |
1977 | ### Sorting arrays
1978 |
1979 | The examples we saw earlier show how we can manipulate simple variables - numbers and strings
1980 |
1981 | We can also sort and filter arrays
1982 |
1983 | ```
1984 | $planets = array("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune");
1985 | ```
1986 |
1987 | This is a standard PHP array, we already know how to access an individual item:
1988 |
1989 | ```
1990 | echo $planets[2]; // === "Earth"
1991 | ```
1992 |
1993 | To pick a random entry from an array we can use `array_rand()`
1994 |
1995 | ```
1996 | $rand = array_rand($planets);
1997 | echo $planets[$rand];
1998 | ```
1999 |
2000 | `count($array)` will give you the number of items in the array
2001 |
2002 | ```
2003 | echo count($planets); // === 8
2004 | ```
2005 |
2006 | `shuffle($array)` will shuffle (randomise) the array
2007 |
2008 | ```
2009 | shuffle($planets);
2010 | print_r($planets);
2011 | ```
2012 |
2013 | `array_reverse($array)` will...reverse an array
2014 |
2015 | ```
2016 | $reversedPlanets = array_reverse($planets);
2017 | print_r($reversedPlanets);
2018 | ```
2019 |
2020 | `array_unique()` will remove any duplicates
2021 |
2022 | We can add to or remove from the array:
2023 |
2024 | - `array_pop()` to retrieve and remove the last value
2025 | - `array_shift()` to put a value at the start of an array
2026 | - `array_push()` to put a value at the end of an array
2027 | - `array_unshift()` to retrieve and remove the first value from an array
2028 |
2029 | There are lots more examples of array functions on the PHP website:
2030 |
2031 | - [http://www.php.net/manual/en/ref.array.php](http://www.php.net/manual/en/ref.array.php)
2032 |
2033 |
2034 | ### Using PHP or MySQL to sort data
2035 |
2036 | When choosing between sorting data with PHP or MySQL, it is more efficient to do as much as possible in the original SQL query
2037 |
2038 | For example, you could `SELECT * FROM questions`, then loop through all the results in PHP to decide whether to output the current question
2039 |
2040 | But it is more efficient to filter in the SQL query...
2041 |
2042 | ...unless you are going to re-use the data elsewhere
2043 |
2044 |
2045 | ### File uploading
2046 |
2047 | #### Client-side code
2048 |
2049 | We can use HTML forms to upload files to the server
2050 |
2051 | We've already seen the standard structure of an HTML form
2052 |
2053 | In order to enable a form to upload data, add an extra attribute:
2054 |
2055 | ```
2056 |
2803 | ...
2804 |
2805 | ```
2806 |
2807 | We could just include a file containing the HTML at the relevant point:
2808 |
2809 | ```
2810 |
2811 | ...
2812 |
2817 | ...
2818 |
2819 | ```
2820 |
2821 | This is one way to store information, as ready-made HTML
2822 |
2823 | But there are some issues:
2824 |
2825 | - It's not a true separation of data from its display
2826 | - You can't re-use this information in other ways
2827 | - (Each country name is surrounded by an element so couldn't be used in any other way)
2828 | - There are more efficient ways of doing this - we could use PHP to transform it dynamically
2829 |
2830 |
2831 | Looking at the structure of the original countries HTML, there is a new line (or row) for each item of data
2832 |
2833 | On each line there is the country name with an ` ` element surrounding it
2834 |
2835 | If we had just a list of country names, we could recreate this programatically using PHP
2836 |
2837 | Now rather than just inserting the file into the page, we'll need to read and process it with PHP
2838 |
2839 | To read the file we use the built-in PHP functions `file()` and `file_get_contents()`
2840 |
2841 | ```
2842 |
2843 | ...
2844 | ";
2850 | }
2851 | ?>
2852 |
2853 |