1
0

Added DB Access + Error page

This commit is contained in:
Mike Schwörer 2014-05-12 10:11:20 +02:00
parent 3efba81ebc
commit ffdc17efd5
124 changed files with 6346 additions and 82 deletions

View File

@ -37,10 +37,23 @@ return array(
), ),
), ),
), ),
'db' => array(
'connectionString' => 'mysql:host=localhost;dbname=db451718',
'username' => 'root',
'password' => '',
'enableProfiling' => true,
'enableParamLogging' => true,
'charset' => 'utf8',
),
), ),
'params' => array( 'params' => array(
// php configuration // php configuration
'php.defaultCharset' => 'utf-8', 'php.defaultCharset' => 'utf-8',
'php.timezone' => 'UTC', 'php.timezone' => 'UTC',
'yii.handleErrors' => true,
'yii.debug' => true,
'yii.traceLevel' => 3,
) )
); );

View File

@ -1,33 +0,0 @@
<?php
/**
*
* @author Antonio Ramirez <amigo.cobos@gmail.com>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @copyright 2013 2amigOS! Consultation Group LLC
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
return array(
'modules' => array(
'gii' => array(
'class' => 'system.gii.GiiModule',
'password' => 'yii',
'ipFilters' => array('127.0.0.1','::1'),
),
),
'components' => array(
'db' => array(
'connectionString' => 'mysql:host=localhost;dbname=db451718',
'username' => 'root',
'password' => '',
'enableProfiling' => true,
'enableParamLogging' => true,
'charset' => 'utf8',
),
),
'params' => array(
'yii.handleErrors' => true,
'yii.debug' => true,
'yii.traceLevel' => 3,
)
);

View File

@ -1,26 +0,0 @@
<?php
/**
*
* @author Antonio Ramirez <amigo.cobos@gmail.com>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @copyright 2013 2amigOS! Consultation Group LLC
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
return array(
'components' => array(
'db' => array(
'connectionString' => 'mysql:host=rdbms.strato.de;dbname=DB451718',
'username' => 'U451718',
'password' => 'Datenbank',
'enableProfiling' => YII_DEBUG,
'enableParamLogging' => YII_DEBUG,
'charset' => 'utf8',
),
),
'params' => array(
'yii.debug' => false,
'yii.traceLevel' => 0,
'yii.handleErrors' => APP_CONFIG_NAME !== 'test',
)
);

View File

@ -1,7 +0,0 @@
<?php
/**
* stage.php
*/
return array(
);

View File

@ -91,16 +91,6 @@
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.9.1.min.js"><\/script>')</script> <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.9.1.min.js"><\/script>')</script>
<script src="js/libs/bootstrap.min.js"></script> <script src="js/libs/bootstrap.min.js"></script>
<script src="js/plugins.js"></script> <script src="js/plugins.js"></script>
<script src="js/main.js"></script><script> <script src="js/main.js"></script>
var _gaq = [
['_setAccount', 'UA-XXXXX-X'],
['_trackPageview']
];
(function (d, t) {
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
g.src = ('https:' == location.protocol ? '//ssl' : '//www') + '.google-analytics.com/ga.js';
s.parentNode.insertBefore(g, s)
}(document, 'script'));
</script>
</body> </body>
</html> </html>

12
app/views/site/error.php Normal file
View File

@ -0,0 +1,12 @@
<?php
$this->pageTitle=Yii::app()->name . ' - Error';
$this->breadcrumbs=array(
'Error',
);
?>
<h2>Error <?php echo $code; ?></h2>
<div class="error">
<?php echo CHtml::encode($message); ?>
</div>

View File

@ -16,9 +16,27 @@
<div class="span4"> <div class="span4">
<h2>Heading</h2> <h2>Heading</h2>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris <p>
condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis
euismod. Donec sed odio dui. </p> <?php
$connection = Yii::app()->db;
$command=$connection->createCommand("SELECT * FROM programme");
$command->execute(); // a non-query SQL statement execution
// or execute an SQL query and fetch the result set
$reader=$command->query();
// each $row is an array representing a row of data
$dbgtxt = "ello";
foreach($reader as $row)
{
$dbgtxt = $dbgtxt . print_r($row, true);
}
echo TbHtml::textArea('dbgtxt', $dbgtxt, array('rows' => 5));
?>
</p>
<p><a class="btn" href="#">View details &raquo;</a></p> <p><a class="btn" href="#">View details &raquo;</a></p>
</div> </div>

BIN
demos/blog/css/bg.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

166
demos/blog/css/form.css Normal file
View File

@ -0,0 +1,166 @@
/**
* CSS styles for forms generated by yiic.
*
* The styles can be applied to the following form structure:
*
* <div class="form">
* <div class="row">
* <label for="inputid">xyz</label>
* <input name="inputid" id="inputid" type="text" />
* <p class="hint">hint text</p>
* </div>
* <div class="row">
* <label for="inputid">xyz</label>
* <input name="inputid" id="inputid" type="text" />
* <p class="hint">hint text</p>
* </div>
* <div class="row buttons">
* <label for="inputid">xyz</label>
* <input name="inputid" id="inputid" type="text" />
* <p class="hint">hint text</p>
* </div>
* </div>
*
* The above code will render the labels and input fields in separate lines.
* In order to render them in the same line, please use the "wide" form as follows,
*
* <div class="wide form">
* ......
* </div>
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008-2010 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
div.form
{
margin: 0;
}
div.form input,
div.form textarea,
div.form select
{
margin: 0.2em 0 0.5em 0;
}
div.form fieldset
{
border: 1px solid #DDD;
padding: 10px;
margin: 0 0 10px 0;
-moz-border-radius:7px;
}
div.form label
{
font-weight: bold;
font-size: 0.9em;
display: block;
}
div.form .row
{
margin: 5px 0;
}
div.form .hint
{
margin: 0;
padding: 0;
color: #999;
}
div.form .note
{
font-style: italic;
}
div.form span.required
{
color: red;
}
div.form div.error label,
div.form label.error,
div.form span.error
{
color: #C00;
}
div.form div.error input,
div.form div.error textarea,
div.form div.error select,
div.form input.error,
div.form textarea.error,
div.form select.error
{
background: #FEE;
border-color: #C00;
}
div.form div.success input,
div.form div.success textarea,
div.form div.success select,
div.form input.success,
div.form textarea.success,
div.form select.success
{
background: #E6EFC2;
border-color: #C6D880;
}
div.form .errorSummary
{
border: 2px solid #C00;
padding: 7px 7px 12px 7px;
margin: 0 0 20px 0;
background: #FEE;
font-size: 0.9em;
}
div.form .errorMessage
{
color: red;
font-size: 0.9em;
}
div.form .errorSummary p
{
margin: 0;
padding: 5px;
}
div.form .errorSummary ul
{
margin: 0;
padding: 0 0 0 20px;
}
div.wide form label
{
float: left;
margin-right: 10px;
position: relative;
text-align: right;
width: 100px;
}
div.wide form .row
{
clear: left;
}
div.wide form .buttons
{
clear: left;
padding-left: 110px;
}
div.wide form .errorMessage
{
margin: 0 0 0 110px;
}

35
demos/blog/css/ie.css Normal file
View File

@ -0,0 +1,35 @@
/* -----------------------------------------------------------------------
Blueprint CSS Framework 0.9
http://blueprintcss.org
* Copyright (c) 2007-Present. See LICENSE for more info.
* See README for instructions on how to use Blueprint.
* For credits and origins, see AUTHORS.
* This is a compressed file. See the sources in the 'src' directory.
----------------------------------------------------------------------- */
/* ie.css */
body {text-align:center;}
.container {text-align:left;}
* html .column, * html div.span-1, * html div.span-2, * html div.span-3, * html div.span-4, * html div.span-5, * html div.span-6, * html div.span-7, * html div.span-8, * html div.span-9, * html div.span-10, * html div.span-11, * html div.span-12, * html div.span-13, * html div.span-14, * html div.span-15, * html div.span-16, * html div.span-17, * html div.span-18, * html div.span-19, * html div.span-20, * html div.span-21, * html div.span-22, * html div.span-23, * html div.span-24 {display:inline;overflow-x:hidden;}
* html legend {margin:0px -8px 16px 0;padding:0;}
sup {vertical-align:text-top;}
sub {vertical-align:text-bottom;}
html>body p code {*white-space:normal;}
hr {margin:-8px auto 11px;}
img {-ms-interpolation-mode:bicubic;}
.clearfix, .container {display:inline-block;}
* html .clearfix, * html .container {height:1%;}
fieldset {padding-top:0;}
textarea {overflow:auto;}
input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;}
input.text:focus, input.title:focus {border-color:#666;}
input.text, input.title, textarea, select {margin:0.5em 0;}
input.checkbox, input.radio {position:relative;top:.25em;}
form.inline div, form.inline p {vertical-align:middle;}
form.inline label {position:relative;top:-0.25em;}
form.inline input.checkbox, form.inline input.radio, form.inline input.button, form.inline button {margin:0.5em 0;}
button, input.button {position:relative;top:0.25em;}

267
demos/blog/css/main.css Normal file
View File

@ -0,0 +1,267 @@
body
{
margin: 0;
padding: 0;
color: #555;
font: normal 10pt Arial,Helvetica,sans-serif;
background: #EFEFEF;
}
#page
{
margin-top: 5px;
margin-bottom: 5px;
background: white;
border: 1px solid #C9E0ED;
}
#header
{
margin: 0;
padding: 0;
border-top: 3px solid #C9E0ED;
}
#content
{
padding: 20px;
}
#sidebar
{
padding: 20px;
}
#footer
{
padding: 10px;
margin: 10px 20px;
font-size: 0.8em;
text-align: center;
border-top: 1px solid #C9E0ED;
}
#logo
{
padding: 10px 20px;
font-size: 200%;
}
#mainmenu
{
background:white url(bg.gif) repeat-x left top;
}
#mainmenu ul
{
padding:6px 20px 5px 20px;
margin:0px;
}
#mainmenu ul li
{
display: inline;
}
#mainmenu ul li a
{
color:#ffffff;
background-color:transparent;
font-size:12px;
font-weight:bold;
text-decoration:none;
padding:5px 8px;
}
#mainmenu ul li a:hover, #mainmenu ul li.active a
{
color: #6399cd;
background-color:#EFF4FA;
text-decoration:none;
}
div.flash-error, div.flash-notice, div.flash-success
{
padding:.8em;
margin-bottom:1em;
border:2px solid #ddd;
}
div.flash-error
{
background:#FBE3E4;
color:#8a1f11;
border-color:#FBC2C4;
}
div.flash-notice
{
background:#FFF6BF;
color:#514721;
border-color:#FFD324;
}
div.flash-success
{
background:#E6EFC2;
color:#264409;
border-color:#C6D880;
}
div.flash-error a
{
color:#8a1f11;
}
div.flash-notice a
{
color:#514721;
}
div.flash-success a
{
color:#264409;
}
div.form .rememberMe label
{
display: inline;
}
div.view
{
padding: 10px;
margin: 10px 0;
border: 1px solid #C9E0ED;
}
div.breadcrumbs
{
font-size: 0.9em;
padding: 5px 20px;
}
div.breadcrumbs span
{
font-weight: bold;
}
.portlet
{
}
.portlet-decoration
{
padding: 3px 8px;
background: #B7D6E7;
border-left: 5px solid #6FACCF;
}
.portlet-title
{
font-size: 12px;
font-weight: bold;
padding: 0;
margin: 0;
color: #298dcd;
}
.portlet-content
{
font-size:0.9em;
margin: 0;
padding: 5px 8px;
margin-bottom:15px;
background:#EFFDFF;
}
.portlet-content ul
{
list-style-image:none;
list-style-position:outside;
list-style-type:none;
margin: 0;
padding: 0;
}
.portlet-content li
{
padding: 2px 0 4px 0px;
}
.post
{
margin: 0 0 20px;
}
.post .title
{
font-size: 1.5em;
border-bottom: 1px solid #C9E0ED;
}
.post .title a
{
color: #555;
text-decoration: none;
}
.post .author
{
color: #888;
margin: 0 0 5px;
}
.post .nav
{
-moz-border-radius:7px;
padding: 5px;
background: #EFFDFF;
}
.comment
{
-moz-border-radius:7px;
padding: 10px;
background: #F5F5F5;
margin: 5px 0;
}
.comment .content
{
margin: 10px 0;
}
.comment .author
{
margin: 5px 0;
padding: 0 0 3px;
border-bottom: 1px solid #DDD;
}
.comment .time
{
color: #888;
font-size: 0.8em;
}
.comment a.cid
{
color:#CCC;
float:right;
font-size:1.5em;
font-weight:bold;
padding:0 5px 5px 5px;
text-decoration: none;
}
.comment a.cid:hover
{
color:#555;
}
.comment .pending
{
color:red;
}

29
demos/blog/css/print.css Normal file
View File

@ -0,0 +1,29 @@
/* -----------------------------------------------------------------------
Blueprint CSS Framework 0.9
http://blueprintcss.org
* Copyright (c) 2007-Present. See LICENSE for more info.
* See README for instructions on how to use Blueprint.
* For credits and origins, see AUTHORS.
* This is a compressed file. See the sources in the 'src' directory.
----------------------------------------------------------------------- */
/* print.css */
body {line-height:1.5;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;color:#000;background:none;font-size:10pt;}
.container {background:none;}
hr {background:#ccc;color:#ccc;width:100%;height:2px;margin:2em 0;padding:0;border:none;}
hr.space {background:#fff;color:#fff;visibility:hidden;}
h1, h2, h3, h4, h5, h6 {font-family:"Helvetica Neue", Arial, "Lucida Grande", sans-serif;}
code {font:.9em "Courier New", Monaco, Courier, monospace;}
a img {border:none;}
p img.top {margin-top:0;}
blockquote {margin:1.5em;padding:1em;font-style:italic;font-size:.9em;}
.small {font-size:.9em;}
.large {font-size:1.1em;}
.quiet {color:#999;}
.hide {display:none;}
a:link, a:visited {background:transparent;font-weight:700;text-decoration:underline;}
a:link:after, a:visited:after {content:" (" attr(href) ")";font-size:90%;}

235
demos/blog/css/screen.css Normal file
View File

@ -0,0 +1,235 @@
/* -----------------------------------------------------------------------
Blueprint CSS Framework 0.9
http://blueprintcss.org
* Copyright (c) 2007-Present. See LICENSE for more info.
* See README for instructions on how to use Blueprint.
* For credits and origins, see AUTHORS.
* This is a compressed file. See the sources in the 'src' directory.
----------------------------------------------------------------------- */
/* reset.css */
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;}
body {line-height:1.5;}
table {border-collapse:separate;border-spacing:0;}
caption, th, td {text-align:left;font-weight:normal;}
table, td, th {vertical-align:middle;}
blockquote:before, blockquote:after, q:before, q:after {content:"";}
blockquote, q {quotes:"" "";}
a img {border:none;}
/* typography.css */
html {font-size:100.01%;}
body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;}
h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;}
h1 {font-size:2em;line-height:1;margin-bottom:0.5em;}
h2 {font-size:1.6em;margin-bottom:0.75em;}
h3 {font-size:1.4em;line-height:1;margin-bottom:1em;}
h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;}
h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;}
h6 {font-size:1em;font-weight:bold;}
h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;}
p {margin:0 0 1.5em;}
p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;}
p img.right {float:right;margin:1.5em 0 1.5em 1.5em;}
a:focus, a:hover {color:#000;}
a {color:#009;text-decoration:underline;}
blockquote {margin:1.5em;color:#666;font-style:italic;}
strong {font-weight:bold;}
em, dfn {font-style:italic;}
dfn {font-weight:bold;}
sup, sub {line-height:0;}
abbr, acronym {border-bottom:1px dotted #666;}
address {margin:0 0 1.5em;font-style:italic;}
del {color:#666;}
pre {margin:1.5em 0;white-space:pre;}
pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;}
li ul, li ol {margin:0;}
ul, ol {margin:0 1.5em 1.5em 0;padding-left:3.333em;}
ul {list-style-type:disc;}
ol {list-style-type:decimal;}
dl {margin:0 0 1.5em 0;}
dl dt {font-weight:bold;}
dd {margin-left:1.5em;}
table {margin-bottom:1.4em;width:100%;}
th {font-weight:bold;}
thead th {background:#c3d9ff;}
th, td, caption {padding:4px 10px 4px 5px;}
tfoot {font-style:italic;}
caption {background:#eee;}
.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;}
.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;}
.hide {display:none;}
.quiet {color:#666;}
.loud {color:#000;}
.highlight {background:#ff0;}
.added {background:#060;color:#fff;}
.removed {background:#900;color:#fff;}
.first {margin-left:0;padding-left:0;}
.last {margin-right:0;padding-right:0;}
.top {margin-top:0;padding-top:0;}
.bottom {margin-bottom:0;padding-bottom:0;}
/* grid.css */
.container {width:950px;margin:0 auto;}
.showgrid {background:url(src/grid.png);}
.column, div.span-1, div.span-2, div.span-3, div.span-4, div.span-5, div.span-6, div.span-7, div.span-8, div.span-9, div.span-10, div.span-11, div.span-12, div.span-13, div.span-14, div.span-15, div.span-16, div.span-17, div.span-18, div.span-19, div.span-20, div.span-21, div.span-22, div.span-23, div.span-24 {float:left;margin-right:10px;}
.last, div.last {margin-right:0;}
.span-1 {width:30px;}
.span-2 {width:70px;}
.span-3 {width:110px;}
.span-4 {width:150px;}
.span-5 {width:190px;}
.span-6 {width:230px;}
.span-7 {width:270px;}
.span-8 {width:310px;}
.span-9 {width:350px;}
.span-10 {width:390px;}
.span-11 {width:430px;}
.span-12 {width:470px;}
.span-13 {width:510px;}
.span-14 {width:550px;}
.span-15 {width:590px;}
.span-16 {width:630px;}
.span-17 {width:670px;}
.span-18 {width:710px;}
.span-19 {width:750px;}
.span-20 {width:790px;}
.span-21 {width:830px;}
.span-22 {width:870px;}
.span-23 {width:910px;}
.span-24, div.span-24 {width:950px;margin-right:0;}
input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px!important;border-right-width:1px!important;padding-left:5px!important;padding-right:5px!important;}
input.span-1, textarea.span-1 {width:18px!important;}
input.span-2, textarea.span-2 {width:58px!important;}
input.span-3, textarea.span-3 {width:98px!important;}
input.span-4, textarea.span-4 {width:138px!important;}
input.span-5, textarea.span-5 {width:178px!important;}
input.span-6, textarea.span-6 {width:218px!important;}
input.span-7, textarea.span-7 {width:258px!important;}
input.span-8, textarea.span-8 {width:298px!important;}
input.span-9, textarea.span-9 {width:338px!important;}
input.span-10, textarea.span-10 {width:378px!important;}
input.span-11, textarea.span-11 {width:418px!important;}
input.span-12, textarea.span-12 {width:458px!important;}
input.span-13, textarea.span-13 {width:498px!important;}
input.span-14, textarea.span-14 {width:538px!important;}
input.span-15, textarea.span-15 {width:578px!important;}
input.span-16, textarea.span-16 {width:618px!important;}
input.span-17, textarea.span-17 {width:658px!important;}
input.span-18, textarea.span-18 {width:698px!important;}
input.span-19, textarea.span-19 {width:738px!important;}
input.span-20, textarea.span-20 {width:778px!important;}
input.span-21, textarea.span-21 {width:818px!important;}
input.span-22, textarea.span-22 {width:858px!important;}
input.span-23, textarea.span-23 {width:898px!important;}
input.span-24, textarea.span-24 {width:938px!important;}
.append-1 {padding-right:40px;}
.append-2 {padding-right:80px;}
.append-3 {padding-right:120px;}
.append-4 {padding-right:160px;}
.append-5 {padding-right:200px;}
.append-6 {padding-right:240px;}
.append-7 {padding-right:280px;}
.append-8 {padding-right:320px;}
.append-9 {padding-right:360px;}
.append-10 {padding-right:400px;}
.append-11 {padding-right:440px;}
.append-12 {padding-right:480px;}
.append-13 {padding-right:520px;}
.append-14 {padding-right:560px;}
.append-15 {padding-right:600px;}
.append-16 {padding-right:640px;}
.append-17 {padding-right:680px;}
.append-18 {padding-right:720px;}
.append-19 {padding-right:760px;}
.append-20 {padding-right:800px;}
.append-21 {padding-right:840px;}
.append-22 {padding-right:880px;}
.append-23 {padding-right:920px;}
.prepend-1 {padding-left:40px;}
.prepend-2 {padding-left:80px;}
.prepend-3 {padding-left:120px;}
.prepend-4 {padding-left:160px;}
.prepend-5 {padding-left:200px;}
.prepend-6 {padding-left:240px;}
.prepend-7 {padding-left:280px;}
.prepend-8 {padding-left:320px;}
.prepend-9 {padding-left:360px;}
.prepend-10 {padding-left:400px;}
.prepend-11 {padding-left:440px;}
.prepend-12 {padding-left:480px;}
.prepend-13 {padding-left:520px;}
.prepend-14 {padding-left:560px;}
.prepend-15 {padding-left:600px;}
.prepend-16 {padding-left:640px;}
.prepend-17 {padding-left:680px;}
.prepend-18 {padding-left:720px;}
.prepend-19 {padding-left:760px;}
.prepend-20 {padding-left:800px;}
.prepend-21 {padding-left:840px;}
.prepend-22 {padding-left:880px;}
.prepend-23 {padding-left:920px;}
div.border {padding-right:4px;margin-right:5px;border-right:1px solid #eee;}
div.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #eee;}
.pull-1 {margin-left:-40px;}
.pull-2 {margin-left:-80px;}
.pull-3 {margin-left:-120px;}
.pull-4 {margin-left:-160px;}
.pull-5 {margin-left:-200px;}
.pull-6 {margin-left:-240px;}
.pull-7 {margin-left:-280px;}
.pull-8 {margin-left:-320px;}
.pull-9 {margin-left:-360px;}
.pull-10 {margin-left:-400px;}
.pull-11 {margin-left:-440px;}
.pull-12 {margin-left:-480px;}
.pull-13 {margin-left:-520px;}
.pull-14 {margin-left:-560px;}
.pull-15 {margin-left:-600px;}
.pull-16 {margin-left:-640px;}
.pull-17 {margin-left:-680px;}
.pull-18 {margin-left:-720px;}
.pull-19 {margin-left:-760px;}
.pull-20 {margin-left:-800px;}
.pull-21 {margin-left:-840px;}
.pull-22 {margin-left:-880px;}
.pull-23 {margin-left:-920px;}
.pull-24 {margin-left:-960px;}
.pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;}
.push-1 {margin:0 -40px 1.5em 40px;}
.push-2 {margin:0 -80px 1.5em 80px;}
.push-3 {margin:0 -120px 1.5em 120px;}
.push-4 {margin:0 -160px 1.5em 160px;}
.push-5 {margin:0 -200px 1.5em 200px;}
.push-6 {margin:0 -240px 1.5em 240px;}
.push-7 {margin:0 -280px 1.5em 280px;}
.push-8 {margin:0 -320px 1.5em 320px;}
.push-9 {margin:0 -360px 1.5em 360px;}
.push-10 {margin:0 -400px 1.5em 400px;}
.push-11 {margin:0 -440px 1.5em 440px;}
.push-12 {margin:0 -480px 1.5em 480px;}
.push-13 {margin:0 -520px 1.5em 520px;}
.push-14 {margin:0 -560px 1.5em 560px;}
.push-15 {margin:0 -600px 1.5em 600px;}
.push-16 {margin:0 -640px 1.5em 640px;}
.push-17 {margin:0 -680px 1.5em 680px;}
.push-18 {margin:0 -720px 1.5em 720px;}
.push-19 {margin:0 -760px 1.5em 760px;}
.push-20 {margin:0 -800px 1.5em 800px;}
.push-21 {margin:0 -840px 1.5em 840px;}
.push-22 {margin:0 -880px 1.5em 880px;}
.push-23 {margin:0 -920px 1.5em 920px;}
.push-24 {margin:0 -960px 1.5em 960px;}
.push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:right;position:relative;}
.prepend-top {margin-top:1.5em;}
.append-bottom {margin-bottom:1.5em;}
.box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;}
hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;}
hr.space {background:#fff;color:#fff;visibility:hidden;}
.clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;}
.clearfix, .container {display:block;}
.clear {clear:both;}

15
demos/blog/index-test.php Normal file
View File

@ -0,0 +1,15 @@
<?php
/**
* This is the bootstrap file for test application.
* This file should be removed when the application is deployed for production.
*/
// change the following paths if necessary
$yii=dirname(__FILE__).'/../../framework/yii.php';
$config=dirname(__FILE__).'/protected/config/test.php';
// remove the following line when in production mode
// defined('YII_DEBUG') or define('YII_DEBUG',true);
require_once($yii);
Yii::createWebApplication($config)->run();

11
demos/blog/index.php Normal file
View File

@ -0,0 +1,11 @@
<?php
// change the following paths if necessary
$yii=dirname(__FILE__).'/../../framework/yii.php';
$config=dirname(__FILE__).'/protected/config/main.php';
// remove the following line when in production mode
// defined('YII_DEBUG') or define('YII_DEBUG',true);
require_once($yii);
Yii::createWebApplication($config)->run();

View File

@ -0,0 +1 @@
deny from all

View File

@ -0,0 +1,23 @@
<?php
/**
* Controller is the customized base controller class.
* All controller classes for this application should extend from this base class.
*/
class Controller extends CController
{
/**
* @var string the default layout for the controller view. Defaults to 'column1',
* meaning using a single column layout. See 'protected/views/layouts/column1.php'.
*/
public $layout='column1';
/**
* @var array context menu items. This property will be assigned to {@link CMenu::items}.
*/
public $menu=array();
/**
* @var array the breadcrumbs of the current page. The value of this property will
* be assigned to {@link CBreadcrumbs::links}. Please refer to {@link CBreadcrumbs::links}
* for more details on how to specify this property.
*/
public $breadcrumbs=array();
}

View File

@ -0,0 +1,19 @@
<?php
Yii::import('zii.widgets.CPortlet');
class RecentComments extends CPortlet
{
public $title='Recent Comments';
public $maxComments=10;
public function getRecentComments()
{
return Comment::model()->findRecentComments($this->maxComments);
}
protected function renderContent()
{
$this->render('recentComments');
}
}

View File

@ -0,0 +1,23 @@
<?php
Yii::import('zii.widgets.CPortlet');
class TagCloud extends CPortlet
{
public $title='Tags';
public $maxTags=20;
protected function renderContent()
{
$tags=Tag::model()->findTagWeights($this->maxTags);
foreach($tags as $tag=>$weight)
{
$link=CHtml::link(CHtml::encode($tag), array('post/index','tag'=>$tag));
echo CHtml::tag('span', array(
'class'=>'tag',
'style'=>"font-size:{$weight}pt",
), $link)."\n";
}
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* UserIdentity represents the data needed to identity a user.
* It contains the authentication method that checks if the provided
* data can identity the user.
*/
class UserIdentity extends CUserIdentity
{
private $_id;
/**
* Authenticates a user.
* @return boolean whether authentication succeeds.
*/
public function authenticate()
{
$user=User::model()->find('LOWER(username)=?',array(strtolower($this->username)));
if($user===null)
$this->errorCode=self::ERROR_USERNAME_INVALID;
else if(!$user->validatePassword($this->password))
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else
{
$this->_id=$user->id;
$this->username=$user->username;
$this->errorCode=self::ERROR_NONE;
}
return $this->errorCode==self::ERROR_NONE;
}
/**
* @return integer the ID of the user record
*/
public function getId()
{
return $this->_id;
}
}

View File

@ -0,0 +1,17 @@
<?php
Yii::import('zii.widgets.CPortlet');
class UserMenu extends CPortlet
{
public function init()
{
$this->title=CHtml::encode(Yii::app()->user->name);
parent::init();
}
protected function renderContent()
{
$this->render('userMenu');
}
}

View File

@ -0,0 +1,7 @@
<ul>
<?php foreach($this->getRecentComments() as $comment): ?>
<li><?php echo $comment->authorLink; ?> on
<?php echo CHtml::link(CHtml::encode($comment->post->title), $comment->getUrl()); ?>
</li>
<?php endforeach; ?>
</ul>

View File

@ -0,0 +1,6 @@
<ul>
<li><?php echo CHtml::link('Create New Post',array('post/create')); ?></li>
<li><?php echo CHtml::link('Manage Posts',array('post/admin')); ?></li>
<li><?php echo CHtml::link('Approve Comments',array('comment/index')) . ' (' . Comment::model()->pendingCommentCount . ')'; ?></li>
<li><?php echo CHtml::link('Logout',array('site/logout')); ?></li>
</ul>

View File

@ -0,0 +1,8 @@
<?php
// This is the configuration for yiic console application.
// Any writable CConsoleApplication properties can be configured here.
return array(
'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
'name'=>'My Console Application',
);

View File

@ -0,0 +1,76 @@
<?php
// uncomment the following to define a path alias
// Yii::setPathOfAlias('local','path/to/local-folder');
// This is the main Web application configuration. Any writable
// CWebApplication properties can be configured here.
return array(
'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
'name'=>'Yii Blog Demo',
// preloading 'log' component
'preload'=>array('log'),
// autoloading model and component classes
'import'=>array(
'application.models.*',
'application.components.*',
),
'defaultController'=>'post',
// application components
'components'=>array(
'user'=>array(
// enable cookie-based authentication
'allowAutoLogin'=>true,
),
'db'=>array(
'connectionString' => 'sqlite:protected/data/blog.db',
'tablePrefix' => 'tbl_',
),
// uncomment the following to use a MySQL database
/*
'db'=>array(
'connectionString' => 'mysql:host=localhost;dbname=blog',
'emulatePrepare' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'tablePrefix' => 'tbl_',
),
*/
'errorHandler'=>array(
// use 'site/error' action to display errors
'errorAction'=>'site/error',
),
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'post/<id:\d+>/<title:.*?>'=>'post/view',
'posts/<tag:.*?>'=>'post/index',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
),
'log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'CFileLogRoute',
'levels'=>'error, warning',
),
// uncomment the following to show log messages on web pages
/*
array(
'class'=>'CWebLogRoute',
),
*/
),
),
),
// application-level parameters that can be accessed
// using Yii::app()->params['paramName']
'params'=>require(dirname(__FILE__).'/params.php'),
);

View File

@ -0,0 +1,19 @@
<?php
// this contains the application parameters that can be maintained via GUI
return array(
// this is displayed in the header section
'title'=>'My Yii Blog',
// this is used in error pages
'adminEmail'=>'webmaster@example.com',
// number of posts displayed per page
'postsPerPage'=>10,
// maximum number of comments that can be displayed in recent comments portlet
'recentCommentCount'=>10,
// maximum number of tags that can be displayed in tag cloud portlet
'tagCloudCount'=>20,
// whether post comments need to be approved before published
'commentNeedApproval'=>true,
// the copyright information displayed in the footer section
'copyrightInfo'=>'Copyright &copy; 2009 by My Company.',
);

View File

@ -0,0 +1,25 @@
<?php
return CMap::mergeArray(
require(dirname(__FILE__).'/main.php'),
array(
'components'=>array(
'fixture'=>array(
'class'=>'system.test.CDbFixtureManager',
),
'db'=>array(
'connectionString'=>'sqlite:'.dirname(__FILE__).'/../data/blog-test.db',
),
// uncomment the following to use a MySQL database
/*
'db'=>array(
'connectionString' => 'mysql:host=localhost;dbname=blog-test',
'emulatePrepare' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8',
),
*/
),
)
);

View File

@ -0,0 +1,130 @@
<?php
class CommentController extends Controller
{
public $layout='column2';
/**
* @var CActiveRecord the currently loaded data model instance.
*/
private $_model;
/**
* @return array action filters
*/
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
);
}
/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* @return array access control rules
*/
public function accessRules()
{
return array(
array('allow', // allow authenticated users to access all actions
'users'=>array('@'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
*/
public function actionUpdate()
{
$model=$this->loadModel();
if(isset($_POST['ajax']) && $_POST['ajax']==='comment-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
if(isset($_POST['Comment']))
{
$model->attributes=$_POST['Comment'];
if($model->save())
$this->redirect(array('index'));
}
$this->render('update',array(
'model'=>$model,
));
}
/**
* Deletes a particular model.
* If deletion is successful, the browser will be redirected to the 'index' page.
*/
public function actionDelete()
{
if(Yii::app()->request->isPostRequest)
{
// we only allow deletion via POST request
$this->loadModel()->delete();
// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
if(!isset($_POST['ajax']))
$this->redirect(array('index'));
}
else
throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
}
/**
* Lists all models.
*/
public function actionIndex()
{
$dataProvider=new CActiveDataProvider('Comment', array(
'criteria'=>array(
'with'=>'post',
'order'=>'t.status, t.create_time DESC',
),
));
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
/**
* Approves a particular comment.
* If approval is successful, the browser will be redirected to the comment index page.
*/
public function actionApprove()
{
if(Yii::app()->request->isPostRequest)
{
$comment=$this->loadModel();
$comment->approve();
$this->redirect(array('index'));
}
else
throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
}
/**
* Returns the data model based on the primary key given in the GET variable.
* If the data model is not found, an HTTP exception will be raised.
*/
public function loadModel()
{
if($this->_model===null)
{
if(isset($_GET['id']))
$this->_model=Comment::model()->findbyPk($_GET['id']);
if($this->_model===null)
throw new CHttpException(404,'The requested page does not exist.');
}
return $this->_model;
}
}

View File

@ -0,0 +1,216 @@
<?php
class PostController extends Controller
{
public $layout='column2';
/**
* @var CActiveRecord the currently loaded data model instance.
*/
private $_model;
/**
* @return array action filters
*/
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
);
}
/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* @return array access control rules
*/
public function accessRules()
{
return array(
array('allow', // allow all users to access 'index' and 'view' actions.
'actions'=>array('index','view'),
'users'=>array('*'),
),
array('allow', // allow authenticated users to access all actions
'users'=>array('@'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
/**
* Displays a particular model.
*/
public function actionView()
{
$post=$this->loadModel();
$comment=$this->newComment($post);
$this->render('view',array(
'model'=>$post,
'comment'=>$comment,
));
}
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$model=new Post;
if(isset($_POST['Post']))
{
$model->attributes=$_POST['Post'];
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
$this->render('create',array(
'model'=>$model,
));
}
/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
*/
public function actionUpdate()
{
$model=$this->loadModel();
if(isset($_POST['Post']))
{
$model->attributes=$_POST['Post'];
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
$this->render('update',array(
'model'=>$model,
));
}
/**
* Deletes a particular model.
* If deletion is successful, the browser will be redirected to the 'index' page.
*/
public function actionDelete()
{
if(Yii::app()->request->isPostRequest)
{
// we only allow deletion via POST request
$this->loadModel()->delete();
// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
if(!isset($_GET['ajax']))
$this->redirect(array('index'));
}
else
throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
}
/**
* Lists all models.
*/
public function actionIndex()
{
$criteria=new CDbCriteria(array(
'condition'=>'status='.Post::STATUS_PUBLISHED,
'order'=>'update_time DESC',
'with'=>'commentCount',
));
if(isset($_GET['tag']))
$criteria->addSearchCondition('tags',$_GET['tag']);
$dataProvider=new CActiveDataProvider('Post', array(
'pagination'=>array(
'pageSize'=>Yii::app()->params['postsPerPage'],
),
'criteria'=>$criteria,
));
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
/**
* Manages all models.
*/
public function actionAdmin()
{
$model=new Post('search');
if(isset($_GET['Post']))
$model->attributes=$_GET['Post'];
$this->render('admin',array(
'model'=>$model,
));
}
/**
* Suggests tags based on the current user input.
* This is called via AJAX when the user is entering the tags input.
*/
public function actionSuggestTags()
{
if(isset($_GET['q']) && ($keyword=trim($_GET['q']))!=='')
{
$tags=Tag::model()->suggestTags($keyword);
if($tags!==array())
echo implode("\n",$tags);
}
}
/**
* Returns the data model based on the primary key given in the GET variable.
* If the data model is not found, an HTTP exception will be raised.
*/
public function loadModel()
{
if($this->_model===null)
{
if(isset($_GET['id']))
{
if(Yii::app()->user->isGuest)
$condition='status='.Post::STATUS_PUBLISHED.' OR status='.Post::STATUS_ARCHIVED;
else
$condition='';
$this->_model=Post::model()->findByPk($_GET['id'], $condition);
}
if($this->_model===null)
throw new CHttpException(404,'The requested page does not exist.');
}
return $this->_model;
}
/**
* Creates a new comment.
* This method attempts to create a new comment based on the user input.
* If the comment is successfully created, the browser will be redirected
* to show the created comment.
* @param Post the post that the new comment belongs to
* @return Comment the comment instance
*/
protected function newComment($post)
{
$comment=new Comment;
if(isset($_POST['ajax']) && $_POST['ajax']==='comment-form')
{
echo CActiveForm::validate($comment);
Yii::app()->end();
}
if(isset($_POST['Comment']))
{
$comment->attributes=$_POST['Comment'];
if($post->addComment($comment))
{
if($comment->status==Comment::STATUS_PENDING)
Yii::app()->user->setFlash('commentSubmitted','Thank you for your comment. Your comment will be posted once it is approved.');
$this->refresh();
}
}
return $comment;
}
}

View File

@ -0,0 +1,97 @@
<?php
class SiteController extends Controller
{
public $layout='column1';
/**
* Declares class-based actions.
*/
public function actions()
{
return array(
// captcha action renders the CAPTCHA image displayed on the contact page
'captcha'=>array(
'class'=>'CCaptchaAction',
'backColor'=>0xFFFFFF,
),
// page action renders "static" pages stored under 'protected/views/site/pages'
// They can be accessed via: index.php?r=site/page&view=FileName
'page'=>array(
'class'=>'CViewAction',
),
);
}
/**
* This is the action to handle external exceptions.
*/
public function actionError()
{
if($error=Yii::app()->errorHandler->error)
{
if(Yii::app()->request->isAjaxRequest)
echo $error['message'];
else
$this->render('error', $error);
}
}
/**
* Displays the contact page
*/
public function actionContact()
{
$model=new ContactForm;
if(isset($_POST['ContactForm']))
{
$model->attributes=$_POST['ContactForm'];
if($model->validate())
{
$headers="From: {$model->email}\r\nReply-To: {$model->email}";
mail(Yii::app()->params['adminEmail'],$model->subject,$model->body,$headers);
Yii::app()->user->setFlash('contact','Thank you for contacting us. We will respond to you as soon as possible.');
$this->refresh();
}
}
$this->render('contact',array('model'=>$model));
}
/**
* Displays the login page
*/
public function actionLogin()
{
if (!defined('CRYPT_BLOWFISH')||!CRYPT_BLOWFISH)
throw new CHttpException(500,"This application requires that PHP was compiled with Blowfish support for crypt().");
$model=new LoginForm;
// if it is ajax validation request
if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
// collect user input data
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if($model->validate() && $model->login())
$this->redirect(Yii::app()->user->returnUrl);
}
// display the login form
$this->render('login',array('model'=>$model));
}
/**
* Logs out the current user and redirect to homepage.
*/
public function actionLogout()
{
Yii::app()->user->logout();
$this->redirect(Yii::app()->homeUrl);
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,13 @@
<?php
$dbFile=dirname(__FILE__).'/blog.db';
$sqlFile=dirname(__FILE__).'/schema.sqlite.sql';
@unlink($dbFile);
$db=new PDO('sqlite:'.$dbFile);
$sqls=file_get_contents($sqlFile);
foreach(explode(';',$sqls) as $sql)
{
if(trim($sql)!=='')
$db->exec($sql);
}

View File

@ -0,0 +1,70 @@
CREATE TABLE tbl_lookup
(
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(128) NOT NULL,
code INTEGER NOT NULL,
type VARCHAR(128) NOT NULL,
position INTEGER NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE tbl_user
(
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(128) NOT NULL,
password VARCHAR(128) NOT NULL,
email VARCHAR(128) NOT NULL,
profile TEXT
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE tbl_post
(
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(128) NOT NULL,
content TEXT NOT NULL,
tags TEXT,
status INTEGER NOT NULL,
create_time INTEGER,
update_time INTEGER,
author_id INTEGER NOT NULL,
CONSTRAINT FK_post_author FOREIGN KEY (author_id)
REFERENCES tbl_user (id) ON DELETE CASCADE ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE tbl_comment
(
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
content TEXT NOT NULL,
status INTEGER NOT NULL,
create_time INTEGER,
author VARCHAR(128) NOT NULL,
email VARCHAR(128) NOT NULL,
url VARCHAR(128),
post_id INTEGER NOT NULL,
CONSTRAINT FK_comment_post FOREIGN KEY (post_id)
REFERENCES tbl_post (id) ON DELETE CASCADE ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE tbl_tag
(
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(128) NOT NULL,
frequency INTEGER DEFAULT 1
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Draft', 'PostStatus', 1, 1);
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Published', 'PostStatus', 2, 2);
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Archived', 'PostStatus', 3, 3);
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Pending Approval', 'CommentStatus', 1, 1);
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Approved', 'CommentStatus', 2, 2);
INSERT INTO tbl_user (username, password, email) VALUES ('demo','$2a$10$JTJf6/XqC94rrOtzuF397OHa4mbmZrVTBOQCmYD9U.obZRUut4BoC','webmaster@example.com');
INSERT INTO tbl_post (title, content, status, create_time, update_time, author_id, tags) VALUES ('Welcome!','This blog system is developed using Yii. It is meant to demonstrate how to use Yii to build a complete real-world application. Complete source code may be found in the Yii releases.
Feel free to try this system by writing new posts and posting comments.',2,1230952187,1230952187,1,'yii, blog');
INSERT INTO tbl_post (title, content, status, create_time, update_time, author_id, tags) VALUES ('A Test Post', '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. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 2,1230952187,1230952187,1,'test');
INSERT INTO tbl_comment (content, status, create_time, author, email, post_id) VALUES ('This is a test comment.', 2, 1230952187, 'Tester', 'tester@example.com', 2);
INSERT INTO tbl_tag (name) VALUES ('yii');
INSERT INTO tbl_tag (name) VALUES ('blog');
INSERT INTO tbl_tag (name) VALUES ('test');

View File

@ -0,0 +1,70 @@
CREATE TABLE tbl_lookup
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name VARCHAR(128) NOT NULL,
code INTEGER NOT NULL,
type VARCHAR(128) NOT NULL,
position INTEGER NOT NULL
);
CREATE TABLE tbl_user
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
username VARCHAR(128) NOT NULL,
password VARCHAR(128) NOT NULL,
email VARCHAR(128) NOT NULL,
profile TEXT
);
CREATE TABLE tbl_post
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title VARCHAR(128) NOT NULL,
content TEXT NOT NULL,
tags TEXT,
status INTEGER NOT NULL,
create_time INTEGER,
update_time INTEGER,
author_id INTEGER NOT NULL,
CONSTRAINT FK_post_author FOREIGN KEY (author_id)
REFERENCES tbl_user (id) ON DELETE CASCADE ON UPDATE RESTRICT
);
CREATE TABLE tbl_comment
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
status INTEGER NOT NULL,
create_time INTEGER,
author VARCHAR(128) NOT NULL,
email VARCHAR(128) NOT NULL,
url VARCHAR(128),
post_id INTEGER NOT NULL,
CONSTRAINT FK_comment_post FOREIGN KEY (post_id)
REFERENCES tbl_post (id) ON DELETE CASCADE ON UPDATE RESTRICT
);
CREATE TABLE tbl_tag
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name VARCHAR(128) NOT NULL,
frequency INTEGER DEFAULT 1
);
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Draft', 'PostStatus', 1, 1);
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Published', 'PostStatus', 2, 2);
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Archived', 'PostStatus', 3, 3);
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Pending Approval', 'CommentStatus', 1, 1);
INSERT INTO tbl_lookup (name, type, code, position) VALUES ('Approved', 'CommentStatus', 2, 2);
INSERT INTO tbl_user (username, password, email) VALUES ('demo','$2a$10$JTJf6/XqC94rrOtzuF397OHa4mbmZrVTBOQCmYD9U.obZRUut4BoC','webmaster@example.com');
INSERT INTO tbl_post (title, content, status, create_time, update_time, author_id, tags) VALUES ('Welcome!','This blog system is developed using Yii. It is meant to demonstrate how to use Yii to build a complete real-world application. Complete source code may be found in the Yii releases.
Feel free to try this system by writing new posts and leaving comments.',2,1230952187,1230952187,1,'yii, blog');
INSERT INTO tbl_post (title, content, status, create_time, update_time, author_id, tags) VALUES ('A Test Post', '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. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 2,1230952187,1230952187,1,'test');
INSERT INTO tbl_comment (content, status, create_time, author, email, post_id) VALUES ('This is a test comment.', 2, 1230952187, 'Tester', 'tester@example.com', 2);
INSERT INTO tbl_tag (name) VALUES ('yii');
INSERT INTO tbl_tag (name) VALUES ('blog');
INSERT INTO tbl_tag (name) VALUES ('test');

View File

@ -0,0 +1,148 @@
<?php
class Comment extends CActiveRecord
{
/**
* The followings are the available columns in table 'tbl_comment':
* @var integer $id
* @var string $content
* @var integer $status
* @var integer $create_time
* @var string $author
* @var string $email
* @var string $url
* @var integer $post_id
*/
const STATUS_PENDING=1;
const STATUS_APPROVED=2;
/**
* Returns the static model of the specified AR class.
* @return CActiveRecord the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return '{{comment}}';
}
/**
* @return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('content, author, email', 'required'),
array('author, email, url', 'length', 'max'=>128),
array('email','email'),
array('url','url'),
);
}
/**
* @return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'post' => array(self::BELONGS_TO, 'Post', 'post_id'),
);
}
/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'Id',
'content' => 'Comment',
'status' => 'Status',
'create_time' => 'Create Time',
'author' => 'Name',
'email' => 'Email',
'url' => 'Website',
'post_id' => 'Post',
);
}
/**
* Approves a comment.
*/
public function approve()
{
$this->status=Comment::STATUS_APPROVED;
$this->update(array('status'));
}
/**
* @param Post the post that this comment belongs to. If null, the method
* will query for the post.
* @return string the permalink URL for this comment
*/
public function getUrl($post=null)
{
if($post===null)
$post=$this->post;
return $post->url.'#c'.$this->id;
}
/**
* @return string the hyperlink display for the current comment's author
*/
public function getAuthorLink()
{
if(!empty($this->url))
return CHtml::link(CHtml::encode($this->author),$this->url);
else
return CHtml::encode($this->author);
}
/**
* @return integer the number of comments that are pending approval
*/
public function getPendingCommentCount()
{
return $this->count('status='.self::STATUS_PENDING);
}
/**
* @param integer the maximum number of comments that should be returned
* @return array the most recently added comments
*/
public function findRecentComments($limit=10)
{
return $this->with('post')->findAll(array(
'condition'=>'t.status='.self::STATUS_APPROVED,
'order'=>'t.create_time DESC',
'limit'=>$limit,
));
}
/**
* This is invoked before the record is saved.
* @return boolean whether the record should be saved.
*/
protected function beforeSave()
{
if(parent::beforeSave())
{
if($this->isNewRecord)
$this->create_time=time();
return true;
}
else
return false;
}
}

View File

@ -0,0 +1,42 @@
<?php
/**
* ContactForm class.
* ContactForm is the data structure for keeping
* contact form data. It is used by the 'contact' action of 'SiteController'.
*/
class ContactForm extends CFormModel
{
public $name;
public $email;
public $subject;
public $body;
public $verifyCode;
/**
* Declares the validation rules.
*/
public function rules()
{
return array(
// name, email, subject and body are required
array('name, email, subject, body', 'required'),
// email has to be a valid email address
array('email', 'email'),
// verifyCode needs to be entered correctly
array('verifyCode', 'captcha', 'allowEmpty'=>!CCaptcha::checkRequirements()),
);
}
/**
* Declares customized attribute labels.
* If not declared here, an attribute would have a label that is
* the same as its name with the first letter in upper case.
*/
public function attributeLabels()
{
return array(
'verifyCode'=>'Verification Code',
);
}
}

View File

@ -0,0 +1,74 @@
<?php
/**
* LoginForm class.
* LoginForm is the data structure for keeping
* user login form data. It is used by the 'login' action of 'SiteController'.
*/
class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe;
private $_identity;
/**
* Declares the validation rules.
* The rules state that username and password are required,
* and password needs to be authenticated.
*/
public function rules()
{
return array(
// username and password are required
array('username, password', 'required'),
// rememberMe needs to be a boolean
array('rememberMe', 'boolean'),
// password needs to be authenticated
array('password', 'authenticate'),
);
}
/**
* Declares attribute labels.
*/
public function attributeLabels()
{
return array(
'rememberMe'=>'Remember me next time',
);
}
/**
* Authenticates the password.
* This is the 'authenticate' validator as declared in rules().
*/
public function authenticate($attribute,$params)
{
$this->_identity=new UserIdentity($this->username,$this->password);
if(!$this->_identity->authenticate())
$this->addError('password','Incorrect username or password.');
}
/**
* Logs in the user using the given username and password in the model.
* @return boolean whether login is successful
*/
public function login()
{
if($this->_identity===null)
{
$this->_identity=new UserIdentity($this->username,$this->password);
$this->_identity->authenticate();
}
if($this->_identity->errorCode===UserIdentity::ERROR_NONE)
{
$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
Yii::app()->user->login($this->_identity,$duration);
return true;
}
else
return false;
}
}

View File

@ -0,0 +1,76 @@
<?php
class Lookup extends CActiveRecord
{
/**
* The followings are the available columns in table 'tbl_lookup':
* @var integer $id
* @var string $object_type
* @var integer $code
* @var string $name_en
* @var string $name_fr
* @var integer $sequence
* @var integer $status
*/
private static $_items=array();
/**
* Returns the static model of the specified AR class.
* @return CActiveRecord the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return '{{lookup}}';
}
/**
* Returns the items for the specified type.
* @param string item type (e.g. 'PostStatus').
* @return array item names indexed by item code. The items are order by their position values.
* An empty array is returned if the item type does not exist.
*/
public static function items($type)
{
if(!isset(self::$_items[$type]))
self::loadItems($type);
return self::$_items[$type];
}
/**
* Returns the item name for the specified type and code.
* @param string the item type (e.g. 'PostStatus').
* @param integer the item code (corresponding to the 'code' column value)
* @return string the item name for the specified the code. False is returned if the item type or code does not exist.
*/
public static function item($type,$code)
{
if(!isset(self::$_items[$type]))
self::loadItems($type);
return isset(self::$_items[$type][$code]) ? self::$_items[$type][$code] : false;
}
/**
* Loads the lookup items for the specified type from the database.
* @param string the item type
*/
private static function loadItems($type)
{
self::$_items[$type]=array();
$models=self::model()->findAll(array(
'condition'=>'type=:type',
'params'=>array(':type'=>$type),
'order'=>'position',
));
foreach($models as $model)
self::$_items[$type][$model->code]=$model->name;
}
}

View File

@ -0,0 +1,202 @@
<?php
class Post extends CActiveRecord
{
/**
* The followings are the available columns in table 'tbl_post':
* @var integer $id
* @var string $title
* @var string $content
* @var string $tags
* @var integer $status
* @var integer $create_time
* @var integer $update_time
* @var integer $author_id
*/
const STATUS_DRAFT=1;
const STATUS_PUBLISHED=2;
const STATUS_ARCHIVED=3;
private $_oldTags;
/**
* Returns the static model of the specified AR class.
* @return CActiveRecord the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return '{{post}}';
}
/**
* @return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('title, content, status', 'required'),
array('status', 'in', 'range'=>array(1,2,3)),
array('title', 'length', 'max'=>128),
array('tags', 'match', 'pattern'=>'/^[\w\s,]+$/', 'message'=>'Tags can only contain word characters.'),
array('tags', 'normalizeTags'),
array('title, status', 'safe', 'on'=>'search'),
);
}
/**
* @return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'author' => array(self::BELONGS_TO, 'User', 'author_id'),
'comments' => array(self::HAS_MANY, 'Comment', 'post_id', 'condition'=>'comments.status='.Comment::STATUS_APPROVED, 'order'=>'comments.create_time DESC'),
'commentCount' => array(self::STAT, 'Comment', 'post_id', 'condition'=>'status='.Comment::STATUS_APPROVED),
);
}
/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'Id',
'title' => 'Title',
'content' => 'Content',
'tags' => 'Tags',
'status' => 'Status',
'create_time' => 'Create Time',
'update_time' => 'Update Time',
'author_id' => 'Author',
);
}
/**
* @return string the URL that shows the detail of the post
*/
public function getUrl()
{
return Yii::app()->createUrl('post/view', array(
'id'=>$this->id,
'title'=>$this->title,
));
}
/**
* @return array a list of links that point to the post list filtered by every tag of this post
*/
public function getTagLinks()
{
$links=array();
foreach(Tag::string2array($this->tags) as $tag)
$links[]=CHtml::link(CHtml::encode($tag), array('post/index', 'tag'=>$tag));
return $links;
}
/**
* Normalizes the user-entered tags.
*/
public function normalizeTags($attribute,$params)
{
$this->tags=Tag::array2string(array_unique(Tag::string2array($this->tags)));
}
/**
* Adds a new comment to this post.
* This method will set status and post_id of the comment accordingly.
* @param Comment the comment to be added
* @return boolean whether the comment is saved successfully
*/
public function addComment($comment)
{
if(Yii::app()->params['commentNeedApproval'])
$comment->status=Comment::STATUS_PENDING;
else
$comment->status=Comment::STATUS_APPROVED;
$comment->post_id=$this->id;
return $comment->save();
}
/**
* This is invoked when a record is populated with data from a find() call.
*/
protected function afterFind()
{
parent::afterFind();
$this->_oldTags=$this->tags;
}
/**
* This is invoked before the record is saved.
* @return boolean whether the record should be saved.
*/
protected function beforeSave()
{
if(parent::beforeSave())
{
if($this->isNewRecord)
{
$this->create_time=$this->update_time=time();
$this->author_id=Yii::app()->user->id;
}
else
$this->update_time=time();
return true;
}
else
return false;
}
/**
* This is invoked after the record is saved.
*/
protected function afterSave()
{
parent::afterSave();
Tag::model()->updateFrequency($this->_oldTags, $this->tags);
}
/**
* This is invoked after the record is deleted.
*/
protected function afterDelete()
{
parent::afterDelete();
Comment::model()->deleteAll('post_id='.$this->id);
Tag::model()->updateFrequency($this->tags, '');
}
/**
* Retrieves the list of posts based on the current search/filter conditions.
* @return CActiveDataProvider the data provider that can return the needed posts.
*/
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('title',$this->title,true);
$criteria->compare('status',$this->status);
return new CActiveDataProvider('Post', array(
'criteria'=>$criteria,
'sort'=>array(
'defaultOrder'=>'status, update_time DESC',
),
));
}
}

View File

@ -0,0 +1,159 @@
<?php
class Tag extends CActiveRecord
{
/**
* The followings are the available columns in table 'tbl_tag':
* @var integer $id
* @var string $name
* @var integer $frequency
*/
/**
* Returns the static model of the specified AR class.
* @return CActiveRecord the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return '{{tag}}';
}
/**
* @return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('name', 'required'),
array('frequency', 'numerical', 'integerOnly'=>true),
array('name', 'length', 'max'=>128),
);
}
/**
* @return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
);
}
/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'Id',
'name' => 'Name',
'frequency' => 'Frequency',
);
}
/**
* Returns tag names and their corresponding weights.
* Only the tags with the top weights will be returned.
* @param integer the maximum number of tags that should be returned
* @return array weights indexed by tag names.
*/
public function findTagWeights($limit=20)
{
$models=$this->findAll(array(
'order'=>'frequency DESC',
'limit'=>$limit,
));
$total=0;
foreach($models as $model)
$total+=$model->frequency;
$tags=array();
if($total>0)
{
foreach($models as $model)
$tags[$model->name]=8+(int)(16*$model->frequency/($total+10));
ksort($tags);
}
return $tags;
}
/**
* Suggests a list of existing tags matching the specified keyword.
* @param string the keyword to be matched
* @param integer maximum number of tags to be returned
* @return array list of matching tag names
*/
public function suggestTags($keyword,$limit=20)
{
$tags=$this->findAll(array(
'condition'=>'name LIKE :keyword',
'order'=>'frequency DESC, Name',
'limit'=>$limit,
'params'=>array(
':keyword'=>'%'.strtr($keyword,array('%'=>'\%', '_'=>'\_', '\\'=>'\\\\')).'%',
),
));
$names=array();
foreach($tags as $tag)
$names[]=$tag->name;
return $names;
}
public static function string2array($tags)
{
return preg_split('/\s*,\s*/',trim($tags),-1,PREG_SPLIT_NO_EMPTY);
}
public static function array2string($tags)
{
return implode(', ',$tags);
}
public function updateFrequency($oldTags, $newTags)
{
$oldTags=self::string2array($oldTags);
$newTags=self::string2array($newTags);
$this->addTags(array_values(array_diff($newTags,$oldTags)));
$this->removeTags(array_values(array_diff($oldTags,$newTags)));
}
public function addTags($tags)
{
$criteria=new CDbCriteria;
$criteria->addInCondition('name',$tags);
$this->updateCounters(array('frequency'=>1),$criteria);
foreach($tags as $name)
{
if(!$this->exists('name=:name',array(':name'=>$name)))
{
$tag=new Tag;
$tag->name=$name;
$tag->frequency=1;
$tag->save();
}
}
}
public function removeTags($tags)
{
if(empty($tags))
return;
$criteria=new CDbCriteria;
$criteria->addInCondition('name',$tags);
$this->updateCounters(array('frequency'=>-1),$criteria);
$this->deleteAll('frequency<=0');
}
}

View File

@ -0,0 +1,90 @@
<?php
class User extends CActiveRecord
{
/**
* The followings are the available columns in table 'tbl_user':
* @var integer $id
* @var string $username
* @var string $password
* @var string $email
* @var string $profile
*/
/**
* Returns the static model of the specified AR class.
* @return CActiveRecord the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return '{{user}}';
}
/**
* @return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('username, password, email', 'required'),
array('username, password, email', 'length', 'max'=>128),
array('profile', 'safe'),
);
}
/**
* @return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'posts' => array(self::HAS_MANY, 'Post', 'author_id'),
);
}
/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'Id',
'username' => 'Username',
'password' => 'Password',
'email' => 'Email',
'profile' => 'Profile',
);
}
/**
* Checks if the given password is correct.
* @param string the password to be validated
* @return boolean whether the password is valid
*/
public function validatePassword($password)
{
return CPasswordHelper::verifyPassword($password,$this->password);
}
/**
* Generates the password hash.
* @param string password
* @return string hash
*/
public function hashPassword($password)
{
return CPasswordHelper::hashPassword($password);
}
}

View File

@ -0,0 +1,25 @@
<?php
/**
* Change the following URL based on your server configuration
* Make sure the URL ends with a slash so that we can use relative URLs in test cases
*/
define('TEST_BASE_URL','http://localhost/yii/demos/blog/index-test.php/');
/**
* The base class for functional test cases.
* In this class, we set the base URL for the test application.
* We also provide some common methods to be used by concrete test classes.
*/
class WebTestCase extends CWebTestCase
{
/**
* Sets up before each test method runs.
* This mainly sets the base URL for the test application.
*/
protected function setUp()
{
parent::setUp();
$this->setBrowserUrl(TEST_BASE_URL);
}
}

View File

@ -0,0 +1,10 @@
<?php
// change the following paths if necessary
$yiit=dirname(__FILE__).'/../../../../framework/yiit.php';
$config=dirname(__FILE__).'/../config/test.php';
require_once($yiit);
require_once(dirname(__FILE__).'/WebTestCase.php');
Yii::createWebApplication($config);

View File

@ -0,0 +1,24 @@
<?php
return array(
/*
'sample1'=>array(
'content' => '',
'status' => '',
'create_time' => '',
'author' => '',
'email' => '',
'url' => '',
'post_id' => '',
),
'sample2'=>array(
'content' => '',
'status' => '',
'create_time' => '',
'author' => '',
'email' => '',
'url' => '',
'post_id' => '',
),
*/
);

View File

@ -0,0 +1,18 @@
<?php
return array(
/*
'sample1'=>array(
'name' => '',
'code' => '',
'type' => '',
'position' => '',
),
'sample2'=>array(
'name' => '',
'code' => '',
'type' => '',
'position' => '',
),
*/
);

View File

@ -0,0 +1,13 @@
<?php
return array(
'sample1'=>array(
'title'=>'test post 1',
'content'=>"This blog is powered by [Yii framework](http://www.yiiframework.com).",
'status'=>2,
'create_time'=>1230952187,
'update_time'=>1230952187,
'author_id'=>1,
'tags'=>'yii, blog',
),
);

View File

@ -0,0 +1,12 @@
<?php
return array(
array(
'name'=>'yii',
'frequency'=>1,
),
array(
'name'=>'blog',
'frequency'=>1,
),
);

View File

@ -0,0 +1,9 @@
<?php
return array(
array(
'username'=>'demo',
'password'=>'$2a$10$JTJf6/XqC94rrOtzuF397OHa4mbmZrVTBOQCmYD9U.obZRUut4BoC',
'email'=>'webmaster@example.com',
),
);

View File

@ -0,0 +1,36 @@
<?php
class CommentTest extends WebTestCase
{
/**
* We use both 'Post' and 'Comment' fixtures.
* @see CWebTestCase::fixtures
*/
public $fixtures=array(
'posts'=>'Post',
'comments'=>'Comment',
);
public function testCreate()
{
$this->open('post/1/xyz');
// verify the sample post title exists
$this->assertTextPresent($this->posts['sample1']['title']);
$this->assertElementPresent("name=Comment[author]");
// verify validation errors
$this->clickAndWait("//input[@value='Submit']");
$this->assertTextPresent('Name cannot be blank.');
$this->assertTextPresent('Email cannot be blank.');
$this->assertTextPresent('Comment cannot be blank.');
// verify commenting is successful
$comment="comment 1";
$this->type('name=Comment[author]','me');
$this->type('name=Comment[email]','me@example.com');
$this->type('name=Comment[content]',$comment);
$this->clickAndWait("//input[@value='Submit']");
$this->assertTextPresent('Thank you for your comment');
}
}

View File

@ -0,0 +1,30 @@
<?php
class PostTest extends WebTestCase
{
/**
* We use the 'Post' only for this test.
* @see CWebTestCase::fixtures
*/
public $fixtures=array(
'posts'=>'Post',
);
public function testIndex()
{
$this->open('');
// verify header title exists
$this->assertTextPresent('Yii Blog Demo');
// verify the sample post title exists
$this->assertTextPresent($this->posts['sample1']['title']);
}
public function testView()
{
$this->open('post/1/xyz');
// verify the sample post title exists
$this->assertTextPresent($this->posts['sample1']['title']);
// verify comment form exists
$this->assertTextPresent('Leave a Comment');
}
}

View File

@ -0,0 +1,41 @@
<?php
class SiteTest extends WebTestCase
{
public function testContact()
{
$this->open('site/contact');
$this->assertTextPresent('Contact Us');
$this->assertElementPresent('name=ContactForm[name]');
$this->type('name=ContactForm[name]','tester');
$this->type('name=ContactForm[email]','tester@example.com');
$this->type('name=ContactForm[subject]','test subject');
$this->clickAndWait("//input[@value='Submit']");
$this->assertTextPresent('Body cannot be blank.');
}
public function testLoginLogout()
{
$this->open('');
// ensure the user is logged out
if($this->isTextPresent('Logout'))
$this->clickAndWait('link=Logout');
// test login process, including validation
$this->clickAndWait('link=Login');
$this->assertElementPresent('name=LoginForm[username]');
$this->type('name=LoginForm[username]','demo');
$this->clickAndWait("//input[@value='Login']");
$this->assertTextPresent('Password cannot be blank.');
$this->type('name=LoginForm[password]','demo');
$this->clickAndWait("//input[@value='Login']");
$this->assertTextNotPresent('Password cannot be blank.');
$this->assertTextPresent('Logout');
// test logout process
$this->assertTextNotPresent('Login');
$this->clickAndWait('link=Logout');
$this->assertTextPresent('Login');
}
}

View File

@ -0,0 +1,13 @@
<phpunit bootstrap="bootstrap.php"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="false">
<selenium>
<browser name="Internet Explorer" browser="*iexplore" />
<browser name="Firefox" browser="*firefox" />
</selenium>
</phpunit>

View File

@ -0,0 +1,42 @@
This directory contains unit and functional tests for the blog demo.
- fixtures: contains fixture data for relevant database tables.
Each file is used to set up the fixture data for a particular table.
The file name is the same as the table name.
- functional: contains functional test cases.
- unit: contains unit test cases.
- report: contains any coverage reports.
In order to run these tests, the following requirements must be met:
- PHPUnit 3.3 or higher
- Selenium RC 1.0 or higher
Depending on your installation of Yii release, you may need to modify
the file "WebTestCase.php" so that the "TEST_BASE_URL" constant contains
correct value. You may also modify "phpunit.xml" to specify the browsers
you intend to run the functional tests on.
To run these tests, please refer to PHPUnit documentation. The followings
are some examples:
- Executes all tests under the "unit" directory with verbose information:
phpunit --verbose unit
- Executes all tests under "functional" (Selenium RC is running):
phpunit functional
- Executes a particular test:
phpunit functional/PostTest.php
*DISCLAIMER* The test cases included here are by no means complete. They mainly serve
for demonstrative purpose.

View File

@ -0,0 +1,57 @@
<?php
class CommentTest extends CDbTestCase
{
/**
* We use both 'Post' and 'Comment' fixtures.
* @see CWebTestCase::fixtures
*/
public $fixtures=array(
'posts'=>'Post',
'comments'=>'Comment',
);
public function testFindRecentComments()
{
$this->assertEquals(array(), Comment::model()->findRecentComments());
$comment=new Comment;
$comment->setAttributes(array(
'content'=>'comment 1',
'status'=>Comment::STATUS_APPROVED,
'create_time'=>time(),
'author'=>'me',
'email'=>'me@example.com',
'post_id'=>$this->posts['sample1']['id'],
),false);
$this->assertTrue($comment->save(false));
$this->assertEquals(1,$comment->id);
$comments=Comment::model()->findRecentComments();
$this->assertEquals(1,count($comments));
$this->assertEquals($comment->attributes, $comments[0]->attributes);
}
public function testApprove()
{
$comment=new Comment;
$comment->setAttributes(array(
'content'=>'comment 1',
'status'=>Comment::STATUS_PENDING,
'create_time'=>time(),
'author'=>'me',
'email'=>'me@example.com',
'post_id'=>$this->posts['sample1']['id'],
),false);
$this->assertTrue($comment->save(false));
$comment=Comment::model()->findByPk($comment->id);
$this->assertTrue($comment instanceof Comment);
$this->assertEquals(Comment::STATUS_PENDING,$comment->status);
$comment->approve();
$this->assertEquals(Comment::STATUS_APPROVED,$comment->status);
$comment=Comment::model()->findByPk($comment->id);
$this->assertEquals(Comment::STATUS_APPROVED,$comment->status);
}
}

View File

@ -0,0 +1,13 @@
<?php
class LookupTest extends CDbTestCase
{
public $fixtures=array(
'lookups'=>'Lookup',
);
public function testCreate()
{
}
}

View File

@ -0,0 +1,18 @@
<?php
class PostTest extends CDbTestCase
{
/**
* We use both 'Post' and 'Comment' fixtures.
* @see CWebTestCase::fixtures
*/
public $fixtures=array(
'posts'=>'Post',
'comments'=>'Comment',
);
public function testSave()
{
// write code here to test post saving method
}
}

View File

@ -0,0 +1,13 @@
<?php
class TagTest extends CDbTestCase
{
public $fixtures=array(
'tags'=>'Tag',
);
public function testCreate()
{
}
}

View File

@ -0,0 +1,24 @@
<?php
class UserTest extends CDbTestCase
{
public $fixtures=array(
'users'=>'User',
);
public function testValidatePassword()
{
$this->assertTrue($this->users(0)->validatePassword('demo'));
$this->assertFalse($this->users(0)->validatePassword('wrong'));
}
public function testChangePassword()
{
$user=$this->users(0);
$user->password=$user->hashPassword('newpwd');
$this->assertFalse($user->validatePassword('demo'));
$this->assertTrue($user->validatePassword('newpwd'));
}
}

View File

@ -0,0 +1,40 @@
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'comment-form',
'enableAjaxValidation'=>true,
)); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<div class="row">
<?php echo $form->labelEx($model,'author'); ?>
<?php echo $form->textField($model,'author',array('size'=>60,'maxlength'=>128)); ?>
<?php echo $form->error($model,'author'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'email'); ?>
<?php echo $form->textField($model,'email',array('size'=>60,'maxlength'=>128)); ?>
<?php echo $form->error($model,'email'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'url'); ?>
<?php echo $form->textField($model,'url',array('size'=>60,'maxlength'=>128)); ?>
<?php echo $form->error($model,'url'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'content'); ?>
<?php echo $form->textArea($model,'content',array('rows'=>6, 'cols'=>50)); ?>
<?php echo $form->error($model,'content'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton($model->isNewRecord ? 'Submit' : 'Save'); ?>
</div>
<?php $this->endWidget(); ?>
</div><!-- form -->

View File

@ -0,0 +1,46 @@
<?php
$deleteJS = <<<DEL
$('.container').on('click','.time a.delete',function() {
var th=$(this),
container=th.closest('div.comment'),
id=container.attr('id').slice(1);
if(confirm('Are you sure you want to delete comment #'+id+'?')) {
$.ajax({
url:th.attr('href'),
type:'POST'
}).done(function(){container.slideUp()});
}
return false;
});
DEL;
Yii::app()->getClientScript()->registerScript('delete', $deleteJS);
?>
<div class="comment" id="c<?php echo $data->id; ?>">
<?php echo CHtml::link("#{$data->id}", $data->url, array(
'class'=>'cid',
'title'=>'Permalink to this comment',
)); ?>
<div class="author">
<?php echo $data->authorLink; ?> says on
<?php echo CHtml::link(CHtml::encode($data->post->title), $data->post->url); ?>
</div>
<div class="time">
<?php if($data->status==Comment::STATUS_PENDING): ?>
<span class="pending">Pending approval</span> |
<?php echo CHtml::linkButton('Approve', array(
'submit'=>array('comment/approve','id'=>$data->id),
)); ?> |
<?php endif; ?>
<?php echo CHtml::link('Update',array('comment/update','id'=>$data->id)); ?> |
<?php echo CHtml::link('Delete',array('comment/delete','id'=>$data->id),array('class'=>'delete')); ?> |
<?php echo date('F j, Y \a\t h:i a',$data->create_time); ?>
</div>
<div class="content">
<?php echo nl2br(CHtml::encode($data->content)); ?>
</div>
</div><!-- comment -->

View File

@ -0,0 +1,12 @@
<?php
$this->breadcrumbs=array(
'Comments',
);
?>
<h1>Comments</h1>
<?php $this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_view',
)); ?>

View File

@ -0,0 +1,10 @@
<?php
$this->breadcrumbs=array(
'Comments'=>array('index'),
'Update Comment #'.$model->id,
);
?>
<h1>Update Comment #<?php echo $model->id; ?></h1>
<?php echo $this->renderPartial('_form', array('model'=>$model)); ?>

View File

@ -0,0 +1,7 @@
<?php $this->beginContent('/layouts/main'); ?>
<div class="container">
<div id="content">
<?php echo $content; ?>
</div><!-- content -->
</div>
<?php $this->endContent(); ?>

View File

@ -0,0 +1,22 @@
<?php $this->beginContent('/layouts/main'); ?>
<div class="container">
<div class="span-18">
<div id="content">
<?php echo $content; ?>
</div><!-- content -->
</div>
<div class="span-6 last">
<div id="sidebar">
<?php if(!Yii::app()->user->isGuest) $this->widget('UserMenu'); ?>
<?php $this->widget('TagCloud', array(
'maxTags'=>Yii::app()->params['tagCloudCount'],
)); ?>
<?php $this->widget('RecentComments', array(
'maxComments'=>Yii::app()->params['recentCommentCount'],
)); ?>
</div><!-- sidebar -->
</div>
</div>
<?php $this->endContent(); ?>

View File

@ -0,0 +1,55 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="language" content="en" />
<!-- blueprint CSS framework -->
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/screen.css" media="screen, projection" />
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/print.css" media="print" />
<!--[if lt IE 8]>
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/ie.css" media="screen, projection" />
<![endif]-->
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/main.css" />
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/form.css" />
<title><?php echo CHtml::encode($this->pageTitle); ?></title>
</head>
<body>
<div class="container" id="page">
<div id="header">
<div id="logo"><?php echo CHtml::encode(Yii::app()->name); ?></div>
</div><!-- header -->
<div id="mainmenu">
<?php $this->widget('zii.widgets.CMenu',array(
'items'=>array(
array('label'=>'Home', 'url'=>array('post/index')),
array('label'=>'About', 'url'=>array('site/page', 'view'=>'about')),
array('label'=>'Contact', 'url'=>array('site/contact')),
array('label'=>'Login', 'url'=>array('site/login'), 'visible'=>Yii::app()->user->isGuest),
array('label'=>'Logout ('.Yii::app()->user->name.')', 'url'=>array('site/logout'), 'visible'=>!Yii::app()->user->isGuest)
),
)); ?>
</div><!-- mainmenu -->
<?php $this->widget('zii.widgets.CBreadcrumbs', array(
'links'=>$this->breadcrumbs,
)); ?><!-- breadcrumbs -->
<?php echo $content; ?>
<div id="footer">
Copyright &copy; <?php echo date('Y'); ?> by My Company.<br/>
All Rights Reserved.<br/>
<?php echo Yii::powered(); ?>
</div><!-- footer -->
</div><!-- page -->
</body>
</html>

View File

@ -0,0 +1,22 @@
<?php foreach($comments as $comment): ?>
<div class="comment" id="c<?php echo $comment->id; ?>">
<?php echo CHtml::link("#{$comment->id}", $comment->getUrl($post), array(
'class'=>'cid',
'title'=>'Permalink to this comment',
)); ?>
<div class="author">
<?php echo $comment->authorLink; ?> says:
</div>
<div class="time">
<?php echo date('F j, Y \a\t h:i a',$comment->create_time); ?>
</div>
<div class="content">
<?php echo nl2br(CHtml::encode($comment->content)); ?>
</div>
</div><!-- comment -->
<?php endforeach; ?>

View File

@ -0,0 +1,47 @@
<div class="form">
<?php $form=$this->beginWidget('CActiveForm'); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<?php echo CHtml::errorSummary($model); ?>
<div class="row">
<?php echo $form->labelEx($model,'title'); ?>
<?php echo $form->textField($model,'title',array('size'=>80,'maxlength'=>128)); ?>
<?php echo $form->error($model,'title'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'content'); ?>
<?php echo CHtml::activeTextArea($model,'content',array('rows'=>10, 'cols'=>70)); ?>
<p class="hint">You may use <a target="_blank" href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a>.</p>
<?php echo $form->error($model,'content'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'tags'); ?>
<?php $this->widget('CAutoComplete', array(
'model'=>$model,
'attribute'=>'tags',
'url'=>array('suggestTags'),
'multiple'=>true,
'htmlOptions'=>array('size'=>50),
)); ?>
<p class="hint">Please separate different tags with commas.</p>
<?php echo $form->error($model,'tags'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'status'); ?>
<?php echo $form->dropDownList($model,'status',Lookup::items('PostStatus')); ?>
<?php echo $form->error($model,'status'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
</div>
<?php $this->endWidget(); ?>
</div><!-- form -->

View File

@ -0,0 +1,23 @@
<div class="post">
<div class="title">
<?php echo CHtml::link(CHtml::encode($data->title), $data->url); ?>
</div>
<div class="author">
posted by <?php echo $data->author->username . ' on ' . date('F j, Y',$data->create_time); ?>
</div>
<div class="content">
<?php
$this->beginWidget('CMarkdown', array('purifyOutput'=>true));
echo $data->content;
$this->endWidget();
?>
</div>
<div class="nav">
<b>Tags:</b>
<?php echo implode(', ', $data->tagLinks); ?>
<br/>
<?php echo CHtml::link('Permalink', $data->url); ?> |
<?php echo CHtml::link("Comments ({$data->commentCount})",$data->url.'#comments'); ?> |
Last updated on <?php echo date('F j, Y',$data->update_time); ?>
</div>
</div>

View File

@ -0,0 +1,31 @@
<?php
$this->breadcrumbs=array(
'Manage Posts',
);
?>
<h1>Manage Posts</h1>
<?php $this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
array(
'name'=>'title',
'type'=>'raw',
'value'=>'CHtml::link(CHtml::encode($data->title), $data->url)'
),
array(
'name'=>'status',
'value'=>'Lookup::item("PostStatus",$data->status)',
'filter'=>Lookup::items('PostStatus'),
),
array(
'name'=>'create_time',
'type'=>'datetime',
'filter'=>false,
),
array(
'class'=>'CButtonColumn',
),
),
)); ?>

View File

@ -0,0 +1,8 @@
<?php
$this->breadcrumbs=array(
'Create Post',
);
?>
<h1>Create Post</h1>
<?php echo $this->renderPartial('_form', array('model'=>$model)); ?>

View File

@ -0,0 +1,9 @@
<?php if(!empty($_GET['tag'])): ?>
<h1>Posts Tagged with <i><?php echo CHtml::encode($_GET['tag']); ?></i></h1>
<?php endif; ?>
<?php $this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_view',
'template'=>"{items}\n{pager}",
)); ?>

View File

@ -0,0 +1,10 @@
<?php
$this->breadcrumbs=array(
$model->title=>$model->url,
'Update',
);
?>
<h1>Update <i><?php echo CHtml::encode($model->title); ?></i></h1>
<?php echo $this->renderPartial('_form', array('model'=>$model)); ?>

View File

@ -0,0 +1,36 @@
<?php
$this->breadcrumbs=array(
$model->title,
);
$this->pageTitle=$model->title;
?>
<?php $this->renderPartial('_view', array(
'data'=>$model,
)); ?>
<div id="comments">
<?php if($model->commentCount>=1): ?>
<h3>
<?php echo $model->commentCount>1 ? $model->commentCount . ' comments' : 'One comment'; ?>
</h3>
<?php $this->renderPartial('_comments',array(
'post'=>$model,
'comments'=>$model->comments,
)); ?>
<?php endif; ?>
<h3>Leave a Comment</h3>
<?php if(Yii::app()->user->hasFlash('commentSubmitted')): ?>
<div class="flash-success">
<?php echo Yii::app()->user->getFlash('commentSubmitted'); ?>
</div>
<?php else: ?>
<?php $this->renderPartial('/comment/_form',array(
'model'=>$comment,
)); ?>
<?php endif; ?>
</div><!-- comments -->

View File

@ -0,0 +1,70 @@
<?php
$this->pageTitle=Yii::app()->name . ' - Contact Us';
$this->breadcrumbs=array(
'Contact',
);
?>
<h1>Contact Us</h1>
<?php if(Yii::app()->user->hasFlash('contact')): ?>
<div class="flash-success">
<?php echo Yii::app()->user->getFlash('contact'); ?>
</div>
<?php else: ?>
<p>
If you have business inquiries or other questions, please fill out the following form to contact us. Thank you.
</p>
<div class="form">
<?php $form=$this->beginWidget('CActiveForm'); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<?php echo $form->errorSummary($model); ?>
<div class="row">
<?php echo $form->labelEx($model,'name'); ?>
<?php echo $form->textField($model,'name'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'email'); ?>
<?php echo $form->textField($model,'email'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'subject'); ?>
<?php echo $form->textField($model,'subject',array('size'=>60,'maxlength'=>128)); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'body'); ?>
<?php echo $form->textArea($model,'body',array('rows'=>6, 'cols'=>50)); ?>
</div>
<?php if(CCaptcha::checkRequirements()): ?>
<div class="row">
<?php echo $form->labelEx($model,'verifyCode'); ?>
<div>
<?php $this->widget('CCaptcha'); ?>
<?php echo $form->textField($model,'verifyCode'); ?>
</div>
<div class="hint">Please enter the letters as they are shown in the image above.
<br/>Letters are not case-sensitive.</div>
</div>
<?php endif; ?>
<div class="row submit">
<?php echo CHtml::submitButton('Submit'); ?>
</div>
<?php $this->endWidget(); ?>
</div><!-- form -->
<?php endif; ?>

View File

@ -0,0 +1,12 @@
<?php
$this->pageTitle=Yii::app()->name . ' - Error';
$this->breadcrumbs=array(
'Error',
);
?>
<h2>Error <?php echo $code; ?></h2>
<div class="error">
<?php echo CHtml::encode($message); ?>
</div>

View File

@ -0,0 +1,46 @@
<?php
$this->pageTitle=Yii::app()->name . ' - Login';
$this->breadcrumbs=array(
'Login',
);
?>
<h1>Login</h1>
<p>Please fill out the following form with your login credentials:</p>
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'login-form',
'enableAjaxValidation'=>true,
)); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<div class="row">
<?php echo $form->labelEx($model,'username'); ?>
<?php echo $form->textField($model,'username'); ?>
<?php echo $form->error($model,'username'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'password'); ?>
<?php echo $form->passwordField($model,'password'); ?>
<?php echo $form->error($model,'password'); ?>
<p class="hint">
Hint: You may login with <tt>demo/demo</tt>.
</p>
</div>
<div class="row rememberMe">
<?php echo $form->checkBox($model,'rememberMe'); ?>
<?php echo $form->label($model,'rememberMe'); ?>
<?php echo $form->error($model,'rememberMe'); ?>
</div>
<div class="row submit">
<?php echo CHtml::submitButton('Login'); ?>
</div>
<?php $this->endWidget(); ?>
</div><!-- form -->

View File

@ -0,0 +1,9 @@
<?php
$this->pageTitle=Yii::app()->name . ' - About';
$this->breadcrumbs=array(
'About',
);
?>
<h1>About</h1>
<p>This is the "about" page for my blog site.</p>

View File

@ -0,0 +1,4 @@
#!/usr/bin/env php
<?php
require_once(dirname(__FILE__).'/yiic.php');

View File

@ -0,0 +1,16 @@
@echo off
rem -------------------------------------------------------------
rem Yii command line script for Windows.
rem This is the bootstrap script for running yiic on Windows.
rem -------------------------------------------------------------
@setlocal
set BIN_PATH=%~dp0
if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
%PHP_COMMAND% "%BIN_PATH%yiic.php" %*
@endlocal

View File

@ -0,0 +1,7 @@
<?php
// change the following paths if necessary
$yiic=dirname(__FILE__).'/../../../framework/yiic.php';
$config=dirname(__FILE__).'/config/console.php';
require_once($yiic);

View File

@ -0,0 +1 @@
deny from all

View File

7
demos/hangman/index.php Normal file
View File

@ -0,0 +1,7 @@
<?php
$yii=dirname(__FILE__).'/../../framework/yii.php';
$config=dirname(__FILE__).'/protected/config/main.php';
require_once($yii);
Yii::createWebApplication($config)->run();

View File

@ -0,0 +1 @@
deny from all

View File

@ -0,0 +1,14 @@
<?php
return array(
'name'=>'Hangman Game',
'defaultController'=>'game',
'components'=>array(
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'game/guess/<g:\w>'=>'game/guess',
),
),
),
);

View File

@ -0,0 +1,222 @@
<?php
/**
* GameController class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008-2013 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* GameController implements the {@link http://en.wikipedia.org/wiki/Hangman_(game) Hangman game}.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id: CController.php 131 2008-11-02 01:32:57Z qiang.xue $
* @package demos.hangman
* @since 1.0
*/
class GameController extends CController
{
/**
* @var string sets the default action to be 'play'
*/
public $defaultAction='play';
/**
* The 'play' action.
* In this action, users are asked to choose a difficulty level
* of the game.
*/
public function actionPlay()
{
static $levels=array(
'10'=>'Easy game; you are allowed 10 misses.',
'5'=>'Medium game; you are allowed 5 misses.',
'3'=>'Hard game; you are allowed 3 misses.',
);
// if a difficulty level is correctly chosen
if(isset($_POST['level']) && isset($levels[$_POST['level']]))
{
$this->word=$this->generateWord();
$this->guessWord=str_repeat('_',strlen($this->word));
$this->level=$_POST['level'];
$this->misses=0;
$this->setPageState('guessed',null);
// show the guess page
$this->render('guess');
}
else
{
$params=array(
'levels'=>$levels,
// if this is a POST request, it means the level is not chosen
'error'=>Yii::app()->request->isPostRequest,
);
// show the difficulty level page
$this->render('play',$params);
}
}
/**
* The 'guess' action.
* This action is invoked each time when the user makes a guess.
*/
public function actionGuess()
{
// check to see if the letter is guessed correctly
if(isset($_GET['g'][0]) && ($result=$this->guess($_GET['g'][0]))!==null)
$this->render($result ? 'win' : 'lose');
else // the letter is guessed correctly, but not win yet
{
$guessed=$this->getPageState('guessed',array());
$guessed[$_GET['g'][0]]=true;
$this->setPageState('guessed',$guessed,array());
$this->render('guess');
}
}
/**
* The 'guess' action.
* This action is invoked when the user gives up the game.
*/
public function actionGiveup()
{
$this->render('lose');
}
/**
* Checks to see if a letter is already guessed.
* @param string the letter
* @return boolean whether the letter is already guessed.
*/
public function isGuessed($letter)
{
$guessed=$this->getPageState('guessed',array());
return isset($guessed[$letter]);
}
/**
* Generates a word to be guessed.
* @return string the word to be guessed
*/
protected function generateWord()
{
$wordFile=dirname(__FILE__).'/words.txt';
$words=preg_split("/[\s,]+/",file_get_contents($wordFile));
do
{
$i=rand(0,count($words)-1);
$word=$words[$i];
} while(strlen($word)<5 || !ctype_alpha($word));
return strtoupper($word);
}
/**
* Checks to see if a letter is guessed correctly.
* @param string the letter
* @return mixed true if the word is guessed correctly, false
* if the user has used up all guesses and the word is guessed
* incorrectly, and null if the letter is guessed correctly but
* the whole word is guessed correctly yet.
*/
protected function guess($letter)
{
$word=$this->word;
$guessWord=$this->guessWord;
$pos=0;
$success=false;
while(($pos=strpos($word,$letter,$pos))!==false)
{
$guessWord[$pos]=$letter;
$success=true;
$pos++;
}
if($success)
{
$this->guessWord=$guessWord;
if($guessWord===$word)
return true;
}
else
{
$this->misses++;
if($this->misses>=$this->level)
return false;
}
}
/**
* @return integer the difficulty level. This value is persistent
* during the whole game session.
*/
public function getLevel()
{
return $this->getPageState('level');
}
/**
* @param integer the difficulty level. This value is persistent
* during the whole game session.
*/
public function setLevel($value)
{
$this->setPageState('level',$value);
}
/**
* @return string the word to be guessed. This value is persistent
* during the whole game session.
*/
public function getWord()
{
return $this->getPageState('word');
}
/**
* @param string the word to be guessed. This value is persistent
* during the whole game session.
*/
public function setWord($value)
{
$this->setPageState('word',$value);
}
/**
* @return string the word being guessed. This value is persistent
* during the whole game session.
*/
public function getGuessWord()
{
return $this->getPageState('guessWord');
}
/**
* @param string the word being guessed. This value is persistent
* during the whole game session.
*/
public function setGuessWord($value)
{
$this->setPageState('guessWord',$value);
}
/**
* @return integer the number of misses. This value is persistent
* during the whole game session.
*/
public function getMisses()
{
return $this->getPageState('misses');
}
/**
* @param integer the number of misses. This value is persistent
* during the whole game session.
*/
public function setMisses($value)
{
$this->setPageState('misses',$value);
}
}

View File

@ -0,0 +1,28 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
Neither the name of Yii Software LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

View File

@ -0,0 +1,21 @@
<h2>Please make a guess</h2>
<h3 style="letter-spacing: 4px;"><?php echo $this->guessWord; ?></h3>
<p>You have made <?php echo $this->misses; ?> bad guesses out of a maximum of <?php echo $this->level; ?>.</p>
<?php echo CHtml::statefulForm(); ?>
<p>Guess:
<?php
for($i=ord('A');$i<=ord('Z');++$i)
{
if(!$this->isGuessed(chr($i)))
echo "\n".CHtml::linkButton(chr($i),array('submit'=>array('guess','g'=>chr($i))));
}
?>
</p>
<p><?php echo CHtml::linkButton('Give up?',array('submit'=>array('giveup'))); ?></p>
</form>

View File

@ -0,0 +1,5 @@
<h2>You Lose!</h2>
<p>The word was: <?php echo $this->word; ?>.</p>
<p><?php echo CHtml::link('Start Again',array('play')); ?></p>

View File

@ -0,0 +1,15 @@
<p>This is the game of Hangman. You must guess a word, a letter at a time.
If you make too many mistakes, you lose the game!</p>
<?php echo CHtml::beginForm(); ?>
<?php echo CHtml::radioButtonList('level', null, $levels); ?>
<br/>
<?php echo CHtml::submitButton('Play!'); ?>
<?php if($error): ?>
<span style="color:red">You must choose a difficulty level!</span>
<?php endif; ?>
<?php echo CHtml::endForm(); ?>

View File

@ -0,0 +1,5 @@
<h2>You Win!</h2>
<p>The word was: <?php echo $this->word; ?>.</p>
<p><?php echo CHtml::link('Start Again',array('play')); ?></p>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Hangman Game</title>
</head>
<body>
<h1>Hangman Game</h1>
<?php echo $content; ?>
</body>
</html>

View File

@ -0,0 +1,7 @@
<?php
// include Yii bootstrap file
require_once(dirname(__FILE__).'/../../framework/yii.php');
// create a Web application instance and run
Yii::createWebApplication()->run();

View File

@ -0,0 +1 @@
deny from all

View File

@ -0,0 +1,15 @@
<?php
/**
* SiteController is the default controller to handle user requests.
*/
class SiteController extends CController
{
/**
* Index action is the default action in a controller.
*/
public function actionIndex()
{
echo 'Hello World';
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<actionScriptProperties version="1" mainApplicationPath="phonebook.mxml">
<compiler additionalCompilerArguments="-locale en_US" copyDependentFiles="true" generateAccessible="false" strict="true" warn="true" htmlGenerate="true" htmlPlayerVersionCheck="true" htmlPlayerVersion="9.0.0" htmlExpressInstall="true" htmlHistoryManagement="true" outputFolderPath="bin">
<compilerSourcePath/>
<libraryPath>
<libraryPathEntry kind="3" path="${FRAMEWORKS}/libs/playerglobal.swc" linkType="2"/>
<libraryPathEntry kind="3" path="${FRAMEWORKS}/libs/utilities.swc" linkType="1"/>
<libraryPathEntry kind="3" path="${FRAMEWORKS}/libs/flex.swc" linkType="1" sourcepath="${FRAMEWORKS}/source"/>
<libraryPathEntry kind="3" path="${FRAMEWORKS}/libs/framework.swc" linkType="1" sourcepath="${FRAMEWORKS}/source"/>
<libraryPathEntry kind="3" path="${FRAMEWORKS}/libs/rpc.swc" linkType="1"/>
<libraryPathEntry kind="3" path="${FRAMEWORKS}/libs/charts.swc" linkType="1" sourcepath="${FRAMEWORKS}/source"/>
<libraryPathEntry kind="1" path="${FRAMEWORKS}/locale/{locale}" linkType="1"/>
</libraryPath>
<sourceAttachmentPath>
<sourceAttachmentPathEntry kind="3" path="${FRAMEWORKS}/libs/flex.swc" linkType="1" sourcepath="${FRAMEWORKS}/source"/>
<sourceAttachmentPathEntry kind="3" path="${FRAMEWORKS}/libs/framework.swc" linkType="1" sourcepath="${FRAMEWORKS}/source"/>
<sourceAttachmentPathEntry kind="3" path="${FRAMEWORKS}/libs/charts.swc" linkType="1" sourcepath="${FRAMEWORKS}/source"/>
</sourceAttachmentPath>
</compiler>
<applications>
<application path="phonebook.mxml"/>
</applications>
<buildCSSFiles/>
</actionScriptProperties>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<flexProperties version="1" toolCompile="true" flexServerType="0"/>

View File

@ -0,0 +1,276 @@
// Flash Player Version Detection - Rev 1.6
// Detect Client Browser type
// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved.
var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
function ControlVersion()
{
var version;
var axo;
var e;
// NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry
try {
// version will be set for 7.X or greater players
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
version = axo.GetVariable("$version");
} catch (e) {
}
if (!version)
{
try {
// version will be set for 6.X players only
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
// installed player is some revision of 6.0
// GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
// so we have to be careful.
// default to the first public version
version = "WIN 6,0,21,0";
// throws if AllowScripAccess does not exist (introduced in 6.0r47)
axo.AllowScriptAccess = "always";
// safe to call for 6.0r47 or greater
version = axo.GetVariable("$version");
} catch (e) {
}
}
if (!version)
{
try {
// version will be set for 4.X or 5.X player
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
version = axo.GetVariable("$version");
} catch (e) {
}
}
if (!version)
{
try {
// version will be set for 3.X player
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
version = "WIN 3,0,18,0";
} catch (e) {
}
}
if (!version)
{
try {
// version will be set for 2.X player
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
version = "WIN 2,0,0,11";
} catch (e) {
version = -1;
}
}
return version;
}
// JavaScript helper required to detect Flash Player PlugIn version information
function GetSwfVer(){
// NS/Opera version >= 3 check for Flash plugin in plugin array
var flashVer = -1;
if (navigator.plugins != null && navigator.plugins.length > 0) {
if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
var descArray = flashDescription.split(" ");
var tempArrayMajor = descArray[2].split(".");
var versionMajor = tempArrayMajor[0];
var versionMinor = tempArrayMajor[1];
var versionRevision = descArray[3];
if (versionRevision == "") {
versionRevision = descArray[4];
}
if (versionRevision[0] == "d") {
versionRevision = versionRevision.substring(1);
} else if (versionRevision[0] == "r") {
versionRevision = versionRevision.substring(1);
if (versionRevision.indexOf("d") > 0) {
versionRevision = versionRevision.substring(0, versionRevision.indexOf("d"));
}
}
var flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
}
}
// MSN/WebTV 2.6 supports Flash 4
else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
// WebTV 2.5 supports Flash 3
else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
// older WebTV supports Flash 2
else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
else if ( isIE && isWin && !isOpera ) {
flashVer = ControlVersion();
}
return flashVer;
}
// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available
function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision)
{
versionStr = GetSwfVer();
if (versionStr == -1 ) {
return false;
} else if (versionStr != 0) {
if(isIE && isWin && !isOpera) {
// Given "WIN 2,0,0,11"
tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"]
tempString = tempArray[1]; // "2,0,0,11"
versionArray = tempString.split(","); // ['2', '0', '0', '11']
} else {
versionArray = versionStr.split(".");
}
var versionMajor = versionArray[0];
var versionMinor = versionArray[1];
var versionRevision = versionArray[2];
// is the major.revision >= requested major.revision AND the minor version >= requested minor
if (versionMajor > parseFloat(reqMajorVer)) {
return true;
} else if (versionMajor == parseFloat(reqMajorVer)) {
if (versionMinor > parseFloat(reqMinorVer))
return true;
else if (versionMinor == parseFloat(reqMinorVer)) {
if (versionRevision >= parseFloat(reqRevision))
return true;
}
}
return false;
}
}
function AC_AddExtension(src, ext)
{
if (src.indexOf('?') != -1)
return src.replace(/\?/, ext+'?');
else
return src + ext;
}
function AC_Generateobj(objAttrs, params, embedAttrs)
{
var str = '';
if (isIE && isWin && !isOpera)
{
str += '<object ';
for (var i in objAttrs)
str += i + '="' + objAttrs[i] + '" ';
str += '>';
for (var i in params)
str += '<param name="' + i + '" value="' + params[i] + '" /> ';
str += '</object>';
} else {
str += '<embed ';
for (var i in embedAttrs)
str += i + '="' + embedAttrs[i] + '" ';
str += '> </embed>';
}
document.write(str);
}
function AC_FL_RunContent(){
var ret =
AC_GetArgs
( arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
, "application/x-shockwave-flash"
);
AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}
function AC_GetArgs(args, ext, srcParamName, classid, mimeType){
var ret = new Object();
ret.embedAttrs = new Object();
ret.params = new Object();
ret.objAttrs = new Object();
for (var i=0; i < args.length; i=i+2){
var currArg = args[i].toLowerCase();
switch (currArg){
case "classid":
break;
case "pluginspage":
ret.embedAttrs[args[i]] = args[i+1];
break;
case "src":
case "movie":
args[i+1] = AC_AddExtension(args[i+1], ext);
ret.embedAttrs["src"] = args[i+1];
ret.params[srcParamName] = args[i+1];
break;
case "onafterupdate":
case "onbeforeupdate":
case "onblur":
case "oncellchange":
case "onclick":
case "ondblClick":
case "ondrag":
case "ondragend":
case "ondragenter":
case "ondragleave":
case "ondragover":
case "ondrop":
case "onfinish":
case "onfocus":
case "onhelp":
case "onmousedown":
case "onmouseup":
case "onmouseover":
case "onmousemove":
case "onmouseout":
case "onkeypress":
case "onkeydown":
case "onkeyup":
case "onload":
case "onlosecapture":
case "onpropertychange":
case "onreadystatechange":
case "onrowsdelete":
case "onrowenter":
case "onrowexit":
case "onrowsinserted":
case "onstart":
case "onscroll":
case "onbeforeeditfocus":
case "onactivate":
case "onbeforedeactivate":
case "ondeactivate":
case "type":
case "codebase":
ret.objAttrs[args[i]] = args[i+1];
break;
case "id":
case "width":
case "height":
case "align":
case "vspace":
case "hspace":
case "class":
case "title":
case "accesskey":
case "name":
case "tabindex":
ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i+1];
break;
default:
ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i+1];
}
}
ret.objAttrs["classid"] = classid;
if (mimeType) ret.embedAttrs["type"] = mimeType;
return ret;
}

Some files were not shown because too many files have changed in this diff Show More