Laravel 4: how can I understand how it all works? - laravel

I am using Laravel 3 in one project and it's been a joy. I have also looked at the source code several times to see how some things work behind the scenes.
But now in Laravel 4, I don't know where to begin or how to understand it all. Where can I learn all the behind the scenes of Laravel 4?
Case in point: I wanted to find out if the DB::insert() returns the id of inserted row. So I started searching.
1. I found the Illuminate\Support\Facades\Facade class that "encapsulates" DB.
2. The resolveFacadeInstance function is called and then I tried to print these arrays, but my computer hangs :-/. And I'm sure this would lead to many more classes that I wouldn't understand.
Is there a way I could try to learn the inner workings of Laravel 4? Maybe stack traces?

The facade class is just a filter class to allow you to call methods as if they were static.
For the facade mappings go here: http://laravel.com/docs/facades#facade-class-reference
The starting point to fully understand laravel's inner-workings should begin at:
/public/index.php
You can follow the logic of the program, noticing that requires start.php, which loads an instance of the "Application" which is found here:
/vendor/laravel/framework/src/Illuminate/Foundation/Application.php

This Tuts+ video shows a couple of ways of finding out what class is actually doing the work.
E.g.:
$root = get_class(DB::getFacadeRoot());
var_dump($root);

You can check out the early docs for Laravel 4 here : http://four.laravel.com/ – that should give you a good starting point

The actual Laravel 4 code is well documented in the files. If you want to understand the inner workings then open up the source code files and read the notes. For example I looked up the DB::insert() code in /vendor/laravel/framework/src/Illuminate/Foundation/Application.php.
/**
* Run an insert statement against the database.
*
* #param string $query
* #param array $bindings
* #return bool
*/
public function insert($query, $bindings = array())
{
return $this->statement($query, $bindings);
}
Ok, so this is calling the statement function so I search for function statement in the same code / class:
/**
* Execute an SQL statement and return the boolean result.
*
* #param string $query
* #param array $bindings
* #return bool
*/
public function statement($query, $bindings = array())
{
return $this->run($query, $bindings, function($me, $query, $bindings)
{
if ($me->pretending()) return true;
$bindings = $me->prepareBindings($bindings);
return $me->getPdo()->prepare($query)->execute($bindings);
});
}
We can now see that this returns the boolean result based on the comments above the code.

If you come from Laravel 3 this article is for you. After that you should read the other tutorials of that series.
Author's note:
This article should outline some of the more important changes to Laravel between versions 3 and the upcoming version 4. Bear in mind
this isn’t all of the changes. As the release of Laravel 4 gets closer
I’ll keep this article up to date. If you’re having any problems with
Laravel 4 please jump on to #laravel on Freenode. At this time we’d
like to ask people not to post help topics on the forums.

Related

Having trouble making a query builder work properly for finding all posts from last 7 days

I'm using Doctrine query builder to try to find all occurrences from the last 7 days. Here's my code:
return $this->createPublishedQueryBuilder('content')
->andWhere('content.date BETWEEN :today AND :sevenDaysAgo')
->setParameter('today', new \DateTime())
->setParameter('sevenDaysAgo', new \DateTime('-7 day'))
->orderBy('content.pageviews.weekly', 'desc')
->setMaxResults($count)
->getQuery()
->getResult();
But it's not returning any results. The recently added lines were the andwhere and two setparameter lines below that in order to add the additional search functionality. Any thoughts on what's going on would be greatly appreciated.
EDIT 1:
No luck switching :today AND :sevenDaysAgo
I also forgot to mention here is the date variable:
/**
* #ORM\Column(type="datetime")
*
* #Serial\SerializedName("publication_date")
* #Serial\Type("DateTime<'Y-m-d'>")
* #Serial\Groups({"list", "fixture", "detail", "email"})
*
* #Assert\Date()
*
* #var DateTime
*/
protected $date;
instead of using a between query I would suggest using a higher-than method.
return $this->createPublishedQueryBuilder('content')
->andWhere('content.date > :sevenDaysAgo')
->setParameter('sevenDaysAgo', new \DateTime('-7 day'))
->orderBy('content.pageviews.weekly', 'desc')
->setMaxResults($count)
->getQuery()
->getResult();
otherwise I see no errors in your query. I guess "createPublishedQueryBuilder" is intentional and an abstract form of "createQueryBuilder" ?

efficient way to display subset of Doctrine collection in twig

I've got a Symfony entity, which has a OneToMany mapping with an OrderBy clause like this:
/**
* #ORM\OneToMany(targetEntity="App\Entity\News", mappedBy="category", orphanRemoval=true)
* #ORM\OrderBy({"id" = "DESC"})
*/
private $news;
Assuming I would like to only display n entries in Twig, I would have the options to either loop over it and ignoring every thing after loop.index n or rather use slice. However these options do have the downside, that if there are a lot of news entries, all of them will be loaded, which isn't very efficient.
Another option would be to use a Criteria in the controller or the entity to limit the amount of loaded entities. If I understood it here correctly, it should modify the doctrine query directly and thus not have any performance impact. Is this the best practice, or would it be better to have a custom query builder in the controller or a function in the repository?
Actually you can set $news relationship as EXTRA_LAZY and use $news->slice() function without triggering a full load as stated in official documentation:
If you mark an association as extra lazy the following methods on
collections can be called without triggering a full load of the
collection:
Collection#contains($entity)
Collection#containsKey($key) (available with Doctrine 2.5)
Collection#count()
Collection#get($key) (available with Doctrine 2.4)
Collection#slice($offset, $length = null)
Therefore your declaration should look like the following:
/**
* #ORM\OneToMany(targetEntity="App\Entity\News", mappedBy="category", orphanRemoval=true, fetch="EXTRA_LAZY")
* #ORM\OrderBy({"id" = "DESC"})
*/
private $news;

Codeigniter HMVC + ion_auth trouble loading the config items

I have been banging my head for 5 hours and I finally solved the problem but I just cannot go to sleep without knowing the reason. Let me explain the issue first.
I have used codeigniter HMVC extension and installed ion_auth as a separate module.
|-modules
|--auth
|---config
|-----ion_auth.php
|---controllers
|-----auth.php
|---models
|-----ion_auth_model.php
|---views
When I was trying to get a user's group I started to get wired SQL errors. Then I narrowed the issue and figured out that the items in config/ion_auth.php were not loaded in the ion_auth_model.php file.
ERROR - 2016-02-24 20:09:26 --> Query error: You have an error in your
SQL syntax; check the manual that corresponds to your MySQL server
version for the right syntax to use near 'as id, .name,
.description JOIN ON .=.id WHERE . = '2'' at line 1 - Invalid
query: SELECT . as id, .name, .description JOIN ON .=.id
WHERE . = '2'
Then I tried couple of stuffs and when I remove the index 'ion_auth' from
couple of method calls in ion_auth_model.php everything started to work.
I changed
$this->tables = $this->config->item('tables', 'ion_auth');
$this->join = $this->config->item('join', 'ion_auth);
to
$this->tables = $this->config->item('tables');
$this->join = $this->config->item('join');
Can anyone tell me why it worked?
This is the inner implementation of the CodeIgniter function config->item() found in the file system\core\Config.php
/**
* Fetch a config file item
*
* #param string $item Config item name
* #param string $index Index name
* #return string|null The configuration item or NULL if the item doesn't exist
*/
public function item($item, $index = '')
{
if ($index == '')
{
return isset($this->config[$item]) ? $this->config[$item] : NULL;
}
return isset($this->config[$index], $this->config[$index][$item]) ? $this->config[$index][$item] : NULL;
}
When you pass the $index parameter, the function checks if both parameters are initialized in the config and returns config[$index] of the CI instance; or null if any of them is not initialized.
If config[$item] is not set in the CI instance, the function returns always null. Let's assume this is not the case, as your call don't crash when avoiding $index.
So when you pass $index as the second parameter, your code crashes because the function returns null, and that means that the config[$index] of the CI instance is not set. Now the question is why it's not set, and I can't help you here, but it looks like you are missing to load some modules.
Best regards

Magento 1.6.2 got double prefix while calling createEntityTables during custom eav entity setup

Followed Alan Storm's tutorial, and I got some problem while calling createEntityTables() method. My script is like:
$installer->createEntityTables(
$this->getTable('complexworld/eavblogpost')
);
I've solved the problem related to BLOB/TEXT Mysql error, but another problem occurred. The tables I created have double prefix ("mgt_" is the prefix),
mgt_mgt_eavblog_posts
mgt_mgt_eavblog_posts_char
mgt_mgt_eavblog_posts_datetime
mgt_mgt_eavblog_posts_decimal
mgt_mgt_eavblog_posts_int
mgt_mgt_eavblog_posts_text
mgt_mgt_eavblog_posts_varchar
Tried to dig in createEntityTables() method, and while I print $this->getTable($baseTableName),
if (!$isNoCreateMainTable) {
/**
* Create table main eav table
*/
echo $this->getTable($baseTableName);
exit;
$connection = $this->getConnection();
I got "mgt_mgt_eavblog_posts" on the screen, which means the core method may have added an extra prefix to the table name. Any idea what's going wrong here? I appreciate all your kind helps!
$table = strtolower(substr(ltrim($this->getTable('complexworld/eavblogpost')), strlen(Mage::getConfig()->getTablePrefix())));
$installer->createEntityTables($table);

How can I retrieve the latest question of each thread in Propel 1.6?

I want to get the newest entries for each of my threads (private messaging system) with Propel 1.6 making use of the fluid ModelQuery interface. This would allow me to reuse both methods for getting newest entries and only getting entries where a user is involved (nobody wants to see messages not for him).
I already found out that in standard-SQL I have to use a subquery to get the newest entry for each of my forum threads. I also found out that in Propel you have to use a Criteria::CUSTOM query to achieve this, but the whole Criteria::CUSTOM stuff seems to be pre-Propel-1.6, because none of the examples makes use of the new ModelQuery.
Now the problem is, that I want to make use of the concenation feature in ModelQueries, where you can attach several own methods to each other like this:
$entries = MessageQuery::create()
->messagesInvolvingUser($user) // user retrieved or sent the message
->newestFromThread() // get the latest entry from a lot of Re:-stuff
I do not think that this would still be possible if I had to use
$c = new Criteria();
$c->add([the subquery filter]);
in newestFromThread().
What’s the best method to retrieve the latest entry for each thread given the following scheme (thread_id means that all messages belong to the same correspondence, I want only one entry per thread_id):
id(INT)
title(VARCHAR)
thread_id(INTEGER)
date(DATETIME)
The current PHP-implementation looks like this:
<?php
class MessageQuery extends BaseMessageQuery {
public function messagesInvolvingUser($user) {
return $this
->where('Message.AuthorId = ?', $user->getId())
->_or()
->where('Message.RecipientId = ?', $user->getId());
}
public function newestFromThread() {
return $this;
// To be implemented
}
}
And I am using it like this:
$messages = MessageQuery::create()
->messagesInvolvingUser(Zend_Auth::getInstance()->getIdentity())
->newestFromThread()
->find();
How about ordering results by date (DESC) and to limit to one result ?
Considering the answers in a similar question about pure SQL solutions, I guess it is easiest to add a new column newest indicating which message in a communcation is the newest. This probably fits the object-oriented approach of Propel better, too. I could write my application like this then:
public function preInsert(PropelPDO $con = null) {
$this->setNewest(1);
$this->getEarlier()->setNewest(0);
return true;
}

Resources