MVC - Parse Objects From Database - php

I am trying to make my best OOP code to parse objects with data from database so I created a hook that call a class AppAutoLoadObjects from hooks folder.
config/hooks.php
$hook['pre_system'][] = array(
'class' => 'AppAutoLoadObjects',
'function' => 'initialize',
'filename' => 'AppAutoLoadObjects.php',
'filepath' => 'hooks'
);
hooks/AppAutoLoadObjects.php
class AppAutoLoadObjects
{
public function initialize()
{
spl_autoload_register(array($this,'autoloadCoreObjects'));
}
public function autoloadCoreObjects($class)
{
$path = array(
'objects/',
);
foreach($path as $dir) {
if (file_exists(APPPATH.$dir.$class."_Object".'.php'))
require_once(APPPATH.$dir.$class."_Object".'.php');
}
}
}
As you see in the code I have a objects folder where I require the object parser.
So if I have models/Products_model.php, the autoloadCoreObjects automatically loads objects/Products_Object.php .
Then in my Products_model.php I use on each function:
public function select_by_limit($start, $limit, $resolution) {
..........................................
$query = $this->db->get_compiled_select();
$result = $this->db->query($query);
return $result->custom_result_object('Products_Object');
}
So my object with items from database are parsed in Products_Object.php
class Proprietati_Object
{
private $_resolution;
public function __construct($resolution = 270){
$this->_resolution = $resolution;
$this->_ci = get_instance();
}
//here is where I check if any image in database and if not give a default
public function image(){
if($this->image_name):
return base_url('assets/uploads/'.$this->id_proprietate.'/'.$this->image_resolution());
else:
return base_url('assets/images/no-product-image-available.png');
endif;
}
//here is where I load a small part of view as string because I must show in view different html code for each product_type
public function get_block_caracteristics(){
if($this->product_type == 'apartament')
return $this->_ci->load->view('blocks/apartament', array('product' => $this), TRUE);
elseif($this->product_type == 'land')
return $this->_ci->load->view('blocks/land', array('product' => $this), TRUE);
}
//here is where I set the image resolution and depends on each page where I show the products. E.g. 100, 200, 500
private function image_resolution() {
$image = explode('.', $this->image_name);
return $image[0].'_'.$this->_resolution.'.'.$image[1];
}
}
With this approach I have my controller clean and I only use:
$products = $this->products->select_by_limit(0, 10);
$data['products'] = $products;
then in view:
<?php foreach($products as $product): ?>
<?= $product->image() ?>
<?= $product->get_block_caracteristics() ?>
<?php endforeach; ?>
My question is how can I pass the $resolution variable from the model to the Products_Object constructor? Or maybe my approach is not a good one?
I now this is a very detailed question but I am dealing with this from long time ago, and my purpose is to start coding with clean controllers and models. The framework I use is CodeIgniter.

your model
public function select_by_limit($start, $limit, $resolution)
{
$query = $this->db->get_compiled_select();
$result = $this->db->query($query);
$arrData = array();
foreach($result->result("Proprietati_Object") AS $objProduct)
{
$objProduct->setResolution($resolution);
$arrData[] = $objProduct;
}
return $arrData;
}
and in your Proprietati_Object add a function called setResolution
public function setResolution($resolution)
{
$this->_resolution = $resolution;
}
and thats it

Related

Modx: getCollection query is not working

Inside my processor class I have a statement that grabs all the projects from a db table and formats them to be displayed. This method does not work and halts at the getCollection call.
class GlobalLinkSettingsProcessor extends modObjectGetListProcessor{
public function initialize() {
return parent::initialize();
}
public function process() {
$result = $this->modx->getCollection('ManagerProjects');
$project_names = array();
foreach ($result as $row) {
$projects = unserialize($row->get('manager_projects'));
foreach($projects as $short_code => $project) {
$project_names[] = array('project_name' => $project, 'project_short_code' => $short_code);
}
}
return '{"total":' . count($project_names) . ',"results":' . $this->modx->toJSON($project_names) . ',"success":true}';
}
...
}
This code that uses plain SQL does work:
class GlobalLinkSettingsProcessor extends modObjectGetListProcessor{
public function initialize() {
return parent::initialize();
}
public function process() {
$leadersql = "SELECT * FROM `modx_manager_projects`";
$query = $this->modx->query($leadersql);
$project_names = array();
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
$projects = unserialize($row['manager_projects']);
foreach($projects as $short_code => $project) {
$project_names[] = array('project_name' => $project, 'project_short_code' => $short_code);
}
};
return '{"total":' . count($project_names) . ',"results":' . $this->modx->toJSON($project_names) . ',"success":true}';
}
...
}
I use similar method to the first which saves ManagerProjects and works fine, so I don't think it has to do with the model declaration. I could easily just use the second method above since it seems to work, but I want to use the best method.
What is wrong with the first method?
Is the first method the proper way to implement SQL in the Modx processor? Or is there a better way?
We can do this task easier a little bit.
#Vasis is right but we can use base prepareRow method instead of reloading iterate method:
<?php
class GlobalLinkSettingsProcessor extends modObjectGetListProcessor{
public $classKey = 'ManagerProjects';
protected $projects = array();
public function prepareRow(xPDOObject $object) {
$_projects = unserialize($object->get('manager_projects'));
foreach($_projects as $short_code => $project) {
$this->projects[] = array('project_name' => $project, 'project_short_code' => $short_code);
}
return parent::prepareRow($object);
}
public function outputArray(array $array,$count = false) {
$count = count($this->projects);
return parent::outputArray($this->projects,$count);
}
}
return 'GlobalLinkSettingsProcessor';
There we can see one of modx ‘features’. In modObjectGetListProcessor process method we can see this:
public function process() {
$beforeQuery = $this->beforeQuery();
if ($beforeQuery !== true) {
return $this->failure($beforeQuery);
}
$data = $this->getData();
$list = $this->iterate($data);
return $this->outputArray($list,$data['total']);
}
getData method returns a list of objects and it goes to iterate method (where we can check if the object is accessible and change the list of these objects on demand). If you don't have access to some of objects we'll get changed list. And it goes to outputArray method but second parameter is still old for it. So you should count them again.
This is solution is quite well but you tried to get data which is stored in object's field. So afterIteration method will be unusable for further extension in my version of processor. But who cares? :)
P.S.: About your first version of processor. modObjectGetList processor is ready for getting collection. So you have not to use getcollection method. Just add proper classKey property to it.
Another way is in modProcessor extension. It gives to you a base structure. But you can make your own kind of stuff.
Because you do it wrong! Just see this. The right way to do it, is something like this:
<?php
class GlobalLinkSettingsProcessor extends modObjectGetListProcessor{
public $classKey = 'ManagerProjects';
public function iterate(array $data) {
$list = array();
$list = $this->beforeIteration($list);
$this->currentIndex = 0;
/** #var xPDOObject|modAccessibleObject $object */
foreach ($data['results'] as $object) {
if ($this->checkListPermission && $object instanceof modAccessibleObject && !$object->checkPolicy('list')) continue;
$projects = unserialize($object->get('manager_projects'));
foreach($projects as $short_code => $project) {
$objectArray = array('project_name' => $project, 'project_short_code' => $short_code);
if (!empty($objectArray) && is_array($objectArray)) {
$list[] = $objectArray;
$this->currentIndex++;
}
}
}
$list = $this->afterIteration($list);
return $list;
}
}

display results in kostache

Ok I just started kostache and I would like to display the results i got from the database using orm in kohana 3.3. I know how to display them using foreach statement but when using kostache it's way different. So here's my code.
APPATH/classes/controller/album.php
class Controller_Album extends Controller
{
public function action_index()
{
$view = Kostache_Layout::factory();
$this->response->body($view->render(new View_Pages_Album_List));
}
}
APPATH/classes/view/pages/album/list.php
class View_Pages_Album_List {
public $title = 'List of Music';
public function album_list()
{
$albums = ORM::factory('Album_Information')->find_all();
return $albums;
}
}
APPATH/templates/pages/album/list.mustache
{{album_list}}
How would i display the resulst?. How would you do this in kostache?
Thanks and more power.
Well Nevermind I got it working..
public function album_list()
{
$albums = ORM::factory('Album_Information')->find_all();
$album_info = array();
foreach ($albums as $a)
{
$album = array('album' => array('artist' => $a->Artist, 'album_name' => $a->Album_Name,));
$album_info[] = $album;
}
return $album_info;
}

save() function Zend Framework

I have found this function in the documentation from Zend, more specific in the Create model and Database Table section ( http://framework.zend.com/manual/1.12/en/learning.quickstart.create-model.html ).
This is in the Application_Model_GuestbookMapper:
public function save(Application_Model_Guestbook $guestbook)
{
$data = array(
'email' => $guestbook->getEmail(),
'comment' => $guestbook->getComment(),
'created' => date('Y-m-d H:i:s'),
);
if (null === ($id = $guestbook->getId())) {
unset($data['id']);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array('id = ?' => $id));
}
}
and now i would like to integrate this into my controller, but i have no idea how?
I created an instance of the mapper and tried to pass the info from my decoded json string to it, but I still get errors...:
public function indexAction()
{
$mapper = new Application_Model_GuestbookMapper();
$db = Zend_Db_Table_Abstract::getDefaultAdapter();
$json = file_get_contents('http://data.appsforghent.be/poi/apotheken.json');
$data = Zend_Json::decode($json);
foreach($data['apotheken'] as $row)
{
$mapper->save();
}
}
I know i have to pass the $data to the save() function but I have no idea how... The model won't fit the json-url, I just wanted to show how I retrieve and decode the json.
Can anybody help me?
What you need to pass in to the $mapper->save(); is an instance of Application_Model_Guestbook. So hopefully you have a class Application_Model_Guestbook in which you define the possibility to set a data array as its attributes, for example like this:
class Application_Model_Guestbook {
private $email,$comment,$created;
public function __construct($data) {
$this->email = $data['email'];
// etc add other variables
}
public function getEmail() {
return $this->email;
}
}
Then to call that, use:
foreach($data['apotheken'] as $row)
{
$guestbook = new Application_Model_Guestbook($row);
$mapper->save($guestbook);
}
I have not tested this specifically, but it should give you an idea of how to achieve what you want to do.

Zend Framework JSON Output

In controller I am generating a special form by ID, passed from AJAX. Form output is JSON. Form creates finely. But my problem is to show this JSON in view. How?
Thank you.
In controller (http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.json):
$this->getHelper('json')->sendJson(array(
'param1' => 'v1'
'param2' => 'v2'
));
In view (http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.json):
<?php
echo $this->json(array(
'param1' => 'v1'
'param2' => 'v2'
));
?>
json is a encoded string containing vars in js style if you need to access the member in this string you need to json_decode the string so
$result = json_decode($jsonString);
but note that json treat php associative array like php object ... so if you pass an array you can access it as $result->memberReference not $result['memberReference'];
The easiest way is to stop view from being executed:
function jsonAction () {
....
print $json;
exit;
}
Also see check http://pl.php.net/json_encode if you don't have JSON string already.
You can use Zend class
$sData = Zend_Json::encode($aArray);
Or you can use advanced scenario like:
$data = array(
'onClick' => new Zend_Json_Expr('function() {'
. 'alert("I am a valid javascript callback '
. 'created by Zend_Json"); }'),
'other' => 'no expression',
);
$jsonObjectWithExpression = Zend_Json::encode($data,false,
array('enableJsonExprFinder' => true)
);
The best way todo this in my opinion is to assign one controller as your json output, then you can do this:
class Api_IndexController extends Zend_Controller_Action {
public function init() {
$this->data = array();
}
public function preDispatch() {
$this->variables = $this->_getAllParams();
}
public function postDispatch() {
$this->_helper->json($this->data);
}
public function __call($name, $args) {
return;
}
public function forumAction () {
$this->mapper = new ORM_Model_Mapper_Forum();
$this->model = new ORM_Model_Forum();
$this->dbTable = new ORM_Model_DbTable_Forum();
if (isset($this->variables['id']) && is_numeric($this->variables['id'])) {
$output = $this->model->find($this->variables['id']);
if ($output->id == null) {
return $this->_setError(404);
}
} else {
$output = $this->mapper->fetchAllToArray();
}
$this->data = $output;
}
private function _setError($code=500) {
$this->data = array('error' => $code);
}
}

__toString problems

I'm building a little MVC system (learning) and I have some problems with showing variables in my view files.
This is from my View class:
private $vars = array();
public function __set($key, $value)
{
$this->vars[$key] = $value;
}
public function __get($key)
{
return $this->vars[$key];
}
public function __toString()
{
return $this->vars[$key];
}
public function show($file)
{
global $router;
$folder = strtolower($router->current_controller);
$path = VIEWPATH.$folder.'/'.$file.'.phtml';
if ( ! file_exists($path))
{
die("Template: $file, not found");
}
include ($path);
}
And here is from my controller:
$test = new View();
$test->name = 'karl';
$test->show('name_view');
And the view file (name_view)
echo $name // doesn't work
echo $this->name // Works
What am I doing wrong? Perhaps I haft to make something global?
THX / Tobias
EDIT: I just extracted the vars array in the view class right before I include the view file and then it worked.. Thank you for all help.
There is no $key in __toString()!
Also __toString() doesn't accept any parameters!
Test it with this:
public function __toString()
{
return json_encode($this->vars);
}
After your edit I realized that your problem is not on the __toString() method (you can just delete it since you're not using it). Doing echo $this->name is the correct way to show variables from inside your view in your case, however if you want to just do echo $name may I suggest a different approach?
function View($view)
{
if (is_file($view) === true)
{
$arguments = array_slice(func_get_args(), 1);
foreach ($arguments as $argument)
{
if (is_array($argument) === true)
{
extract($argument, EXTR_OVERWRITE);
}
}
require($view);
}
}
Use the View function like this:
$data = array
(
'name' => 'karl',
);
View('/path/to/your/name_view.phtml', $data);
Now it should work just by doing echo $name;, you can adapt it to your View class if you want to. If that doesn't work, try changing the name_view view extension to .php.

Categories